@tungstenstudio/dartboard-input 1.0.0-rc.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.
package/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright 2026 Tungsten Studio
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,294 @@
1
+ # @tungstenstudio/dartboard-input
2
+
3
+ Interactive SVG dartboard input component built with D3. Click, tap, or keyboard-navigate beds to fire throw events.
4
+
5
+ **[Live Demo](https://tungstenstudio.gitlab.io/libs/dartboard-input/)**
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @tungstenstudio/dartboard-input d3-selection d3-shape
11
+ # or
12
+ pnpm add @tungstenstudio/dartboard-input d3-selection d3-shape
13
+ # or
14
+ yarn add @tungstenstudio/dartboard-input d3-selection d3-shape
15
+ # or
16
+ bun add @tungstenstudio/dartboard-input d3-selection d3-shape
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```js
22
+ import { Dartboard } from '@tungstenstudio/dartboard-input';
23
+ import '@tungstenstudio/dartboard-input/style.css';
24
+
25
+ const board = new Dartboard('#dartboard');
26
+ board.render();
27
+
28
+ document.querySelector('#dartboard').addEventListener('throw', (e) => {
29
+ console.log(e.detail); // { bed: 'T20', ring: 'triple', score: 60 }
30
+ });
31
+ ```
32
+
33
+ ## React Usage
34
+
35
+ ```tsx
36
+ import { useRef, useEffect } from 'react';
37
+ import { Dartboard } from '@tungstenstudio/dartboard-input';
38
+ import '@tungstenstudio/dartboard-input/style.css';
39
+
40
+ function DartboardInput({ onThrow }) {
41
+ const ref = useRef(null);
42
+
43
+ useEffect(() => {
44
+ const board = new Dartboard(ref.current, { size: 400 });
45
+ board.render();
46
+
47
+ const handler = (e) => onThrow?.(e.detail);
48
+ ref.current.addEventListener('throw', handler);
49
+
50
+ return () => board.destroy();
51
+ }, []);
52
+
53
+ return <div ref={ref} />;
54
+ }
55
+ ```
56
+
57
+ ## API
58
+
59
+ ### `new Dartboard(container, options?)`
60
+
61
+ Creates a dartboard instance.
62
+
63
+ | Parameter | Type | Description |
64
+ |-----------|------|-------------|
65
+ | `container` | `string \| HTMLElement` | CSS selector or DOM element |
66
+ | `options` | `Partial<DartboardOptions>` | Size and ring proportions |
67
+
68
+ ### `board.render(): this`
69
+
70
+ Renders the dartboard SVG. Chainable.
71
+
72
+ ### `board.destroy(): void`
73
+
74
+ Removes the board from the DOM and cleans up references.
75
+
76
+ ### `board.throwAt(target): void`
77
+
78
+ Programmatically triggers a throw event.
79
+
80
+ ```js
81
+ board.throwAt('T20'); // bed string
82
+ board.throwAt({ segment: 20, ring: 'TRIPLE' }); // explicit BedTarget
83
+ ```
84
+
85
+ ### `board.highlight(targets, options?): void`
86
+
87
+ Adds a CSS class to targeted beds. All targeting methods accept any mix of bed strings, numbers, and `BedTarget` objects.
88
+
89
+ ```js
90
+ // Bed strings — target specific beds
91
+ board.highlight(['T20', 'D16', 'DB25']);
92
+
93
+ // Segment number — target all scoring beds on that segment
94
+ board.highlight([20]); // double, triple, inner single, outer single
95
+ board.highlight(['20']); // same thing as a string
96
+
97
+ // Miss ring
98
+ board.highlight(['miss']); // highlight entire miss ring
99
+ board.highlight(['M20']); // highlight a specific miss bed
100
+
101
+ // BedTarget object — for precision targeting
102
+ board.highlight([{ segment: 20, ring: 'INNER_SINGLE' }]);
103
+
104
+ // BedTarget without ring — same as segment number
105
+ board.highlight([{ segment: 20 }]);
106
+
107
+ // Custom class name
108
+ board.highlight(['D20'], { className: 'my-highlight' });
109
+ ```
110
+
111
+ ### `board.unhighlight(targets, options?): void`
112
+
113
+ Removes a CSS class from specific beds (counterpart to `highlight`).
114
+
115
+ ```js
116
+ board.unhighlight(['T20']);
117
+ board.unhighlight([20]); // unhighlight all beds on segment 20
118
+ board.unhighlight(['miss']); // unhighlight entire miss ring
119
+ ```
120
+
121
+ ### `board.reset(className?): void`
122
+
123
+ Removes highlight class from all beds.
124
+
125
+ ### `board.disable(): this`
126
+
127
+ Disables the board — suppresses all throw and hover events, dims the board visually. Chainable.
128
+
129
+ ### `board.enable(): this`
130
+
131
+ Re-enables the board after `disable()`. Chainable.
132
+
133
+ ### `board.disabled: boolean`
134
+
135
+ Read-only property indicating whether the board is currently disabled.
136
+
137
+ ## Bed Strings
138
+
139
+ Beds are identified by an abbreviation prefix and a segment number:
140
+
141
+ | Input | Targets | Example |
142
+ |-------|---------|---------|
143
+ | `T` + number | Triple | `'T20'` |
144
+ | `D` + number | Double | `'D16'` |
145
+ | `S` + number | Both singles (inner + outer) | `'S20'` |
146
+ | `DB` + number | Double Bull (Bullseye) | `'DB25'` |
147
+ | `B` + number | Single Bull (Bull) | `'B25'` |
148
+ | `M` + number | Miss | `'M20'` |
149
+ | number only | All scoring beds on that segment | `'20'` or `20` |
150
+ | `'miss'` | Entire miss ring (all 20 segments) | `'miss'` |
151
+
152
+ When a number is used alone, all scoring beds on that segment are targeted (double, triple, inner single, outer single, single bull, double bull) — the miss ring is excluded. To target a specific single, use the explicit `BedTarget` form: `{ segment: 20, ring: 'INNER_SINGLE' }`.
153
+
154
+ ## Events
155
+
156
+ ### `throw`
157
+
158
+ Dispatched on the container element when a bed is clicked, tapped, or activated via keyboard.
159
+
160
+ ```ts
161
+ interface ThrowDetail {
162
+ bed: string; // e.g. 'T20', 'D16', 'B25', 'DB25', 'M20'
163
+ ring: string; // e.g. 'triple', 'double', 'singleBull', 'doubleBull', 'miss'
164
+ score: number; // e.g. 60, 32, 25, 50, 0
165
+ }
166
+ ```
167
+
168
+ ### `hover`
169
+
170
+ Dispatched when a bed is entered or left.
171
+
172
+ ```ts
173
+ interface HoverDetail {
174
+ bed: string;
175
+ ring: string;
176
+ score: number;
177
+ hovering: boolean;
178
+ }
179
+ ```
180
+
181
+ ## Segment States
182
+
183
+ Three built-in state classes are included for marking beds as good, bad, or neutral — useful for coaching sessions, practice games, or heatmaps:
184
+
185
+ ```js
186
+ // Mark good targets (green)
187
+ board.highlight(['T20'], { className: 'is-good' });
188
+
189
+ // Mark bad targets (red)
190
+ board.highlight(['T1'], { className: 'is-bad' });
191
+
192
+ // Mark neutral targets (blue)
193
+ board.highlight(['D5'], { className: 'is-neutral' });
194
+
195
+ // Remove a specific state
196
+ board.unhighlight(['T1'], { className: 'is-bad' });
197
+
198
+ // Clear all of one state
199
+ board.reset('is-good');
200
+ ```
201
+
202
+ The colors are themeable via CSS custom properties:
203
+
204
+ ```css
205
+ .c-Dartboard {
206
+ --dartboard-good: #228b22;
207
+ --dartboard-bad: #e32636;
208
+ --dartboard-neutral: #4a6fa5;
209
+ }
210
+ ```
211
+
212
+ You can also define your own state classes. Use this specificity pattern to override the default bed fills:
213
+
214
+ ```css
215
+ .c-Dartboard .c-Dartboard-bed.is-warning.isDark,
216
+ .c-Dartboard .c-Dartboard-bed.is-warning.isLight {
217
+ fill: orange;
218
+ }
219
+ ```
220
+
221
+ ## Mobile / Touch-Friendly Sizing
222
+
223
+ The default ring proportions can be too narrow for comfortable tapping on small screens. The exported `MOBILE_OPTIONS` preset widens the scoring rings (double, triple, bull) for larger touch targets:
224
+
225
+ ```js
226
+ import { Dartboard, MOBILE_OPTIONS } from '@tungstenstudio/dartboard-input';
227
+
228
+ const isMobile = window.matchMedia('(max-width: 600px)').matches;
229
+ const board = new Dartboard('#dartboard', isMobile ? MOBILE_OPTIONS : {});
230
+ board.render();
231
+ ```
232
+
233
+ You can also build your own proportions — the `*Percent` options control each ring's share of the radius (they should sum to 100):
234
+
235
+ ```js
236
+ new Dartboard('#dartboard', {
237
+ missPercent: 7,
238
+ doublePercent: 14,
239
+ outerSinglePercent: 21,
240
+ triplePercent: 14,
241
+ innerSinglePercent: 26,
242
+ singleBullPercent: 9,
243
+ doubleBullPercent: 9,
244
+ });
245
+ ```
246
+
247
+ ## Theming
248
+
249
+ Override CSS custom properties on the `.c-Dartboard` element:
250
+
251
+ ```css
252
+ .c-Dartboard {
253
+ --dartboard-dark: #1a1a1a;
254
+ --dartboard-light: #f5f5dc;
255
+ --dartboard-scoring-dark: #e32636;
256
+ --dartboard-scoring-light: #228b22;
257
+ --dartboard-miss: #000;
258
+ --dartboard-miss-label: #fff;
259
+ --dartboard-stroke: silver;
260
+ --dartboard-stroke-width: 2px;
261
+ --dartboard-highlight-color: #ffd700;
262
+ --dartboard-good: #228b22;
263
+ --dartboard-bad: #e32636;
264
+ --dartboard-neutral: #4a6fa5;
265
+ }
266
+ ```
267
+
268
+ ## Terminology
269
+
270
+ This library uses standard darts terminology:
271
+
272
+ - **Segment** — one of the 20 numbered wedges on the board (1–20)
273
+ - **Bed** — a specific scoring zone: the intersection of a segment and a ring (e.g., "triple 20")
274
+ - **Ring** — a concentric band: double, triple, inner single, outer single, single bull, double bull, miss
275
+
276
+ ## Types
277
+
278
+ All types are exported for TypeScript consumers:
279
+
280
+ - `Dartboard` — main class
281
+ - `DartboardOptions` — constructor options
282
+ - `ThrowDetail` — throw event payload
283
+ - `HoverDetail` — hover event payload
284
+ - `BedTarget` — explicit target (`{ segment, ring? }`) — omit `ring` to target all scoring beds
285
+ - `BedInput` — union of `BedTarget | string | number` accepted by all targeting methods
286
+ - `HighlightOptions` — options for `highlight`
287
+ - `Ring`, `Rings`, `Segment`, `Bed` — board model types
288
+ - `DEFAULT_OPTIONS`, `MOBILE_OPTIONS` — ring proportion presets
289
+ - `DEFAULT_RINGS`, `DEFAULT_SEGMENTS` — board layout constants
290
+ - `parseBed` — utility to parse a bed string into `BedTarget[]`
291
+
292
+ ## License
293
+
294
+ ISC