@tungstenstudio/dartboard-input 1.0.0-rc.0 → 1.0.0-rc.2

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 CHANGED
@@ -26,7 +26,7 @@ const board = new Dartboard('#dartboard');
26
26
  board.render();
27
27
 
28
28
  document.querySelector('#dartboard').addEventListener('throw', (e) => {
29
- console.log(e.detail); // { bed: 'T20', ring: 'triple', score: 60 }
29
+ console.log(e.detail); // { bed: 'T20', segment: 20, ring: 'triple', score: 60 }
30
30
  });
31
31
  ```
32
32
 
@@ -56,14 +56,18 @@ function DartboardInput({ onThrow }) {
56
56
 
57
57
  ## API
58
58
 
59
- ### `new Dartboard(container, options?)`
59
+ ### `new Dartboard(container, options?, segments?, rings?)`
60
60
 
61
61
  Creates a dartboard instance.
62
62
 
63
- | Parameter | Type | Description |
64
- |-----------|------|-------------|
65
- | `container` | `string \| HTMLElement` | CSS selector or DOM element |
66
- | `options` | `Partial<DartboardOptions>` | Size and ring proportions |
63
+ | Parameter | Type | Default | Description |
64
+ |-----------|------|---------|-------------|
65
+ | `container` | `string \| HTMLElement` | — | CSS selector or DOM element |
66
+ | `options` | `Partial<DartboardOptions>` | `DEFAULT_OPTIONS` | Size, padding, and ring proportions |
67
+ | `segments` | `Segment[]` | `DEFAULT_SEGMENTS` | Board segment layout (standard 1–20) |
68
+ | `rings` | `Rings` | `DEFAULT_RINGS` | Ring definitions (names, abbreviations, multipliers) |
69
+
70
+ When `size` is `null` (the default), the board auto-sizes to fit its container using `Math.min(offsetHeight, offsetWidth)`. The `padding` option (default `0`) adds inner padding so the board edges aren't clipped by the viewBox boundary — the SVG viewBox stays at the full size while the board radius shrinks by the padding amount.
67
71
 
68
72
  ### `board.render(): this`
69
73
 
@@ -134,6 +138,14 @@ Re-enables the board after `disable()`. Chainable.
134
138
 
135
139
  Read-only property indicating whether the board is currently disabled.
136
140
 
141
+ ### `board.segments: Segment[]`
142
+
143
+ Read-only array of segments the board was constructed with.
144
+
145
+ ### `board.rings: Rings`
146
+
147
+ Read-only ring definitions the board was constructed with.
148
+
137
149
  ## Bed Strings
138
150
 
139
151
  Beds are identified by an abbreviation prefix and a segment number:
@@ -159,9 +171,10 @@ Dispatched on the container element when a bed is clicked, tapped, or activated
159
171
 
160
172
  ```ts
161
173
  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
174
+ bed: string; // e.g. 'T20', 'D16', 'B25', 'DB25', 'M20'
175
+ segment: number; // e.g. 20, 16, 25
176
+ ring: string; // e.g. 'triple', 'double', 'singleBull', 'doubleBull', 'miss'
177
+ score: number; // e.g. 60, 32, 25, 50, 0
165
178
  }
166
179
  ```
167
180
 
@@ -172,6 +185,7 @@ Dispatched when a bed is entered or left.
172
185
  ```ts
173
186
  interface HoverDetail {
174
187
  bed: string;
188
+ segment: number;
175
189
  ring: string;
176
190
  score: number;
177
191
  hovering: boolean;
@@ -265,6 +279,45 @@ Override CSS custom properties on the `.c-Dartboard` element:
265
279
  }
266
280
  ```
267
281
 
282
+ ## CSS Class Structure
283
+
284
+ Each bed element in the SVG has several classes you can use for fine-grained styling:
285
+
286
+ | Class | Description |
287
+ |-------|-------------|
288
+ | `.c-Dartboard` | Wrapper div around the SVG |
289
+ | `.c-Dartboard-bed` | Every clickable bed element |
290
+ | `.c-Dartboard-bed--{n}` | Bed for segment number *n* (e.g. `.c-Dartboard-bed--20`) |
291
+ | `.c-Dartboard-{ring}` | Ring group: `double`, `triple`, `innerSingle`, `outerSingle`, `singleBull`, `doubleBull`, `miss` |
292
+ | `.isDark` / `.isLight` | Alternating segment color class |
293
+ | `.is-hovered` | Applied while a bed is pointer-hovered |
294
+ | `.is-highlighted` | Default highlight class (includes a pulsing animation) |
295
+ | `.is-disabled` | Applied to the wrapper when the board is disabled |
296
+ | `.c-Dartboard-missLabel` | Segment number labels in the miss ring |
297
+
298
+ To override fills for a specific ring, combine the ring group with bed classes:
299
+
300
+ ```css
301
+ /* Make all triple beds gold */
302
+ .c-Dartboard .c-Dartboard-triple .c-Dartboard-bed.isDark,
303
+ .c-Dartboard .c-Dartboard-triple .c-Dartboard-bed.isLight {
304
+ fill: gold;
305
+ }
306
+
307
+ /* Style a single bed */
308
+ .c-Dartboard .c-Dartboard-triple .c-Dartboard-bed--20 {
309
+ fill: hotpink;
310
+ }
311
+ ```
312
+
313
+ ## Keyboard & Accessibility
314
+
315
+ All beds are focusable (`tabindex="0"`) with `role="button"` and descriptive `aria-label` attributes (e.g. "T20, scores 60"). The SVG has `role="group"` and `aria-label="Dartboard"`.
316
+
317
+ - **Enter** or **Space** on a focused bed dispatches a `throw` event
318
+ - **Tab** / **Shift+Tab** navigates between beds
319
+ - Focus is indicated with an outline using `--dartboard-highlight-color`
320
+
268
321
  ## Terminology
269
322
 
270
323
  This library uses standard darts terminology:
@@ -285,9 +338,35 @@ All types are exported for TypeScript consumers:
285
338
  - `BedInput` — union of `BedTarget | string | number` accepted by all targeting methods
286
339
  - `HighlightOptions` — options for `highlight`
287
340
  - `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[]`
341
+
342
+ ## Constants
343
+
344
+ - `DEFAULT_OPTIONS` — default ring proportions (see below)
345
+ - `MOBILE_OPTIONS` — wider scoring rings for touch targets
346
+ - `DEFAULT_RINGS` — standard ring definitions (name, abbreviation, multiplier)
347
+ - `DEFAULT_SEGMENTS` — standard 1–20 segment layout with positions and colors
348
+
349
+ Default values (`DEFAULT_OPTIONS`):
350
+
351
+ | Option | Default | Mobile |
352
+ |--------|---------|--------|
353
+ | `padding` | 0 | — |
354
+ | `missPercent` | 10 | 7 |
355
+ | `doublePercent` | 10 | 14 |
356
+ | `outerSinglePercent` | 25 | 21 |
357
+ | `triplePercent` | 10 | 14 |
358
+ | `innerSinglePercent` | 30 | 26 |
359
+ | `singleBullPercent` | 8 | 9 |
360
+ | `doubleBullPercent` | 7 | 9 |
361
+
362
+ ## Utilities
363
+
364
+ Exported helper functions:
365
+
366
+ - `parseBed(bed, rings, segments?)` — parse a bed string into `BedTarget[]`
367
+ - `buildThrowDetail(bed)` — convert a `Bed` into a `ThrowDetail` object
368
+ - `addRingToSegments(ring, segments)` — combine a `Ring` with `Segment[]` to produce `Bed[]`
369
+ - `asPercent(n)` — convert an integer percentage to a decimal (e.g. `10` → `0.1`)
291
370
 
292
371
  ## License
293
372
 
package/dist/index.cjs CHANGED
@@ -39,6 +39,7 @@ var import_d3_shape = require("d3-shape");
39
39
  // src/constants.ts
40
40
  var DEFAULT_OPTIONS = {
41
41
  size: null,
42
+ padding: 0,
42
43
  missPercent: 10,
43
44
  doublePercent: 10,
44
45
  outerSinglePercent: 25,
@@ -100,6 +101,7 @@ var SCORING_RINGS = [
100
101
  function buildThrowDetail(bed) {
101
102
  return {
102
103
  bed: bed.ring.abbr + bed.segment,
104
+ segment: bed.segment,
103
105
  ring: bed.ring.name,
104
106
  score: bed.segment * bed.ring.multiplier
105
107
  };
@@ -166,14 +168,17 @@ var Dartboard = class {
166
168
  if (!boardContainer) {
167
169
  throw new Error(`Dartboard: container not found`);
168
170
  }
169
- const width = this.options.size || Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);
171
+ const padding = this.options.padding;
172
+ const boardSize = this.options.size || Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);
173
+ const width = boardSize - padding * 2;
174
+ const viewBoxSize = boardSize;
170
175
  const segmentWidth = 360 / segments.length;
171
176
  const radius = width / 2;
172
177
  const rotation = segmentWidth / -2;
173
178
  const wrapper = (0, import_d3_selection.select)(boardContainer).append("div").classed("c-Dartboard", true);
174
- const svg = wrapper.append("svg").attr("viewBox", `0 0 ${width} ${width}`).attr("role", "group").attr("aria-label", "Dartboard").append("g").attr(
179
+ const svg = wrapper.append("svg").attr("viewBox", `0 0 ${viewBoxSize} ${viewBoxSize}`).attr("role", "group").attr("aria-label", "Dartboard").append("g").attr(
175
180
  "transform",
176
- `translate(${radius}, ${radius}) rotate(${rotation})`
181
+ `translate(${viewBoxSize / 2}, ${viewBoxSize / 2}) rotate(${rotation})`
177
182
  );
178
183
  const pieFn = (0, import_d3_shape.pie)().sort((a, b) => (a.position ?? 0) - (b.position ?? 0)).value(() => segmentWidth);
179
184
  this.board = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/dartboard.ts","../src/constants.ts","../src/utils.ts"],"sourcesContent":["import './dartboard.css';\nexport { Dartboard } from './dartboard';\nexport type {\n Ring,\n Rings,\n Segment,\n Bed,\n DartboardOptions,\n ThrowDetail,\n HoverDetail,\n BedTarget,\n BedInput,\n HighlightOptions,\n} from './types';\nexport { DEFAULT_OPTIONS, MOBILE_OPTIONS, DEFAULT_RINGS, DEFAULT_SEGMENTS } from './constants';\nexport { buildThrowDetail, asPercent, addRingToSegments, parseBed } from './utils';\n","import { select, type Selection } from 'd3-selection';\nimport { arc, pie, type PieArcDatum } from 'd3-shape';\nimport type {\n DartboardOptions,\n Rings,\n Ring,\n Segment,\n Bed,\n ThrowDetail,\n HoverDetail,\n BedTarget,\n BedInput,\n HighlightOptions,\n} from './types';\nimport { DEFAULT_OPTIONS, DEFAULT_RINGS, DEFAULT_SEGMENTS } from './constants';\nimport { buildThrowDetail, asPercent, addRingToSegments, parseBed } from './utils';\n\n// D3's selection generics are deeply nested and don't compose well across\n// chained calls. Using `any` for internal state avoids 100+ lines of type\n// gymnastics while keeping the public API fully typed.\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface BoardState {\n container: HTMLElement;\n wrapper: Selection<any, any, any, any>;\n width: number;\n height: number;\n radius: number;\n rotation: number;\n segmentWidth: number;\n svg: Selection<any, any, any, any>;\n pie: ReturnType<typeof pie<Bed>>;\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\ninterface SizeMap {\n miss: number;\n double: number;\n outerSingle: number;\n triple: number;\n innerSingle: number;\n singleBull: number;\n doubleBull: number;\n}\n\nfunction buildAriaLabel(bed: Bed): string {\n const detail = buildThrowDetail(bed);\n return `${detail.bed}, scores ${detail.score}`;\n}\n\nexport class Dartboard {\n private board: BoardState | null = null;\n private sizes: SizeMap | null = null;\n private rendered = false;\n private _disabled = false;\n private readonly options: DartboardOptions;\n readonly segments: Segment[];\n readonly rings: Rings;\n\n constructor(\n container: string | HTMLElement,\n options: Partial<DartboardOptions> = {},\n segments: Segment[] = DEFAULT_SEGMENTS,\n rings: Rings = DEFAULT_RINGS,\n ) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.segments = segments;\n this.rings = rings;\n\n const percentSum =\n this.options.missPercent +\n this.options.doublePercent +\n this.options.outerSinglePercent +\n this.options.triplePercent +\n this.options.innerSinglePercent +\n this.options.singleBullPercent +\n this.options.doubleBullPercent;\n\n if (percentSum !== 100) {\n throw new Error(\n `Dartboard: ring percentages must sum to 100 (got ${percentSum})`,\n );\n }\n\n const boardContainer =\n typeof container === 'string'\n ? document.querySelector<HTMLElement>(container)\n : container;\n\n if (!boardContainer) {\n throw new Error(`Dartboard: container not found`);\n }\n\n const width =\n this.options.size ||\n Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);\n const segmentWidth = 360 / segments.length;\n const radius = width / 2;\n const rotation = segmentWidth / -2;\n\n const wrapper = select(boardContainer)\n .append('div')\n .classed('c-Dartboard', true);\n\n const svg = wrapper\n .append('svg')\n .attr('viewBox', `0 0 ${width} ${width}`)\n .attr('role', 'group')\n .attr('aria-label', 'Dartboard')\n .append('g')\n .attr(\n 'transform',\n `translate(${radius}, ${radius}) rotate(${rotation})`,\n );\n\n const pieFn = pie<Bed>()\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))\n .value(() => segmentWidth);\n\n this.board = {\n container: boardContainer,\n wrapper,\n width,\n height: width,\n radius,\n rotation,\n segmentWidth,\n svg,\n pie: pieFn,\n };\n\n this.sizes = {\n miss: radius * asPercent(this.options.missPercent),\n double: radius * asPercent(this.options.doublePercent),\n outerSingle: radius * asPercent(this.options.outerSinglePercent),\n triple: radius * asPercent(this.options.triplePercent),\n innerSingle: radius * asPercent(this.options.innerSinglePercent),\n singleBull: radius * asPercent(this.options.singleBullPercent),\n doubleBull: radius * asPercent(this.options.doubleBullPercent),\n };\n }\n\n render(): this {\n if (!this.board || !this.sizes) return this;\n if (this.rendered) return this;\n this.rendered = true;\n\n const { board, sizes } = this;\n\n let innerRadius = 0;\n let outerRadius = innerRadius + sizes.doubleBull;\n this.renderBeds(\n board,\n this.rings.DOUBLE_BULL,\n [{ segment: 25, color: 'Dark' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.singleBull;\n this.renderBeds(\n board,\n this.rings.SINGLE_BULL,\n [{ segment: 25, color: 'Light' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.innerSingle;\n this.renderBeds(\n board,\n this.rings.INNER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.triple;\n this.renderBeds(\n board,\n this.rings.TRIPLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.outerSingle;\n this.renderBeds(\n board,\n this.rings.OUTER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.double;\n this.renderBeds(\n board,\n this.rings.DOUBLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = board.radius - sizes.miss;\n outerRadius = board.radius;\n this.renderMissRing(\n board,\n this.rings.MISS,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n return this;\n }\n\n destroy(): void {\n if (this.board) {\n // Remove all D3 event listeners before removing from DOM\n this.board.wrapper.selectAll('.c-Dartboard-bed')\n .on('pointerup', null)\n .on('pointerenter', null)\n .on('pointerleave', null)\n .on('keydown', null);\n this.board.wrapper.remove();\n this.board = null;\n this.sizes = null;\n this.rendered = false;\n }\n }\n\n get disabled(): boolean {\n return this._disabled;\n }\n\n disable(): this {\n this._disabled = true;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', true);\n }\n return this;\n }\n\n enable(): this {\n this._disabled = false;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', false);\n }\n return this;\n }\n\n throwAt(target: BedInput): void {\n if (!this.board || this._disabled) return;\n\n const targets = this.resolveTargets([target]);\n if (targets.length === 0) return;\n const first = targets[0];\n\n if (!this.isValidTarget(first)) {\n throw new Error(`Dartboard: invalid throw target — segment ${first.segment} does not exist`);\n }\n\n const ring = this.rings[first.ring];\n const bed: Bed = { segment: first.segment, color: 'Dark', ring };\n const detail = buildThrowDetail(bed);\n\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n highlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, true);\n }\n }\n\n unhighlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, false);\n }\n }\n\n reset(className = 'is-highlighted'): void {\n if (!this.board) return;\n this.board.wrapper.selectAll(`.${className}`).classed(className, false);\n }\n\n private isValidTarget(target: Required<BedTarget>): boolean {\n const isBull = target.ring === 'DOUBLE_BULL' || target.ring === 'SINGLE_BULL';\n if (isBull) {\n return target.segment === 25;\n }\n return this.segments.some((s) => s.segment === target.segment);\n }\n\n private resolveTargets(inputs: BedInput[]): Required<BedTarget>[] {\n return inputs.flatMap((input): Required<BedTarget>[] => {\n if (typeof input === 'number') {\n return parseBed(String(input), this.rings, this.segments) as Required<BedTarget>[];\n }\n if (typeof input === 'string') {\n return parseBed(input, this.rings, this.segments) as Required<BedTarget>[];\n }\n if (!input.ring) {\n return parseBed(String(input.segment), this.rings, this.segments) as Required<BedTarget>[];\n }\n return [input as Required<BedTarget>];\n });\n }\n\n private dispatchThrow(bed: Bed): void {\n if (!this.board || this._disabled) return;\n const detail = buildThrowDetail(bed);\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n private dispatchHover(bed: Bed, hovering: boolean): void {\n if (!this.board || this._disabled) return;\n const throwDetail = buildThrowDetail(bed);\n const detail: HoverDetail = { ...throwDetail, hovering };\n this.board.container.dispatchEvent(\n new CustomEvent<HoverDetail>('hover', { detail }),\n );\n }\n\n private renderBeds(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const className = `c-Dartboard-${ring.name}`;\n const arcFn = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const beds = board.svg\n .append('g')\n .classed(className, true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} ${className}--${d.data.segment} is${d.data.color}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'pointerenter',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', true);\n this.dispatchHover(d.data, true);\n },\n )\n .on(\n 'pointerleave',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', false);\n this.dispatchHover(d.data, false);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n beds.append('path').attr('d', arcFn as never);\n }\n\n private renderMissRing(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const missArc = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const missBeds = board.svg\n .append('g')\n .classed('c-Dartboard-miss', true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} c-Dartboard-miss--${d.data.segment}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n missBeds.append('path').attr('d', missArc as never);\n\n const determineRotation = (bedData: Bed) =>\n -board.rotation + board.segmentWidth * ((bedData.position ?? 0) - 1);\n\n const determineX = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[0];\n\n const determineY = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[1];\n\n missBeds\n .append('text')\n .classed('c-Dartboard-missLabel', true)\n .attr('x', (d: PieArcDatum<Bed>) => determineX(d))\n .attr('y', (d: PieArcDatum<Bed>) => determineY(d))\n .attr('dy', '.35em')\n .attr(\n 'transform',\n (d: PieArcDatum<Bed>) =>\n `rotate(${determineRotation(d.data)}, ${determineX(d)}, ${determineY(d)})`,\n )\n .attr('text-anchor', 'middle')\n .text((d: PieArcDatum<Bed>) => d.data.segment);\n }\n}\n","import type { DartboardOptions, Rings, Segment } from './types';\n\nexport const DEFAULT_OPTIONS: DartboardOptions = {\n size: null,\n missPercent: 10,\n doublePercent: 10,\n outerSinglePercent: 25,\n triplePercent: 10,\n innerSinglePercent: 30,\n singleBullPercent: 8,\n doubleBullPercent: 7,\n};\n\nexport const DEFAULT_RINGS: Rings = {\n MISS: { name: 'miss', abbr: 'M', multiplier: 0 },\n DOUBLE: { name: 'double', abbr: 'D', multiplier: 2 },\n OUTER_SINGLE: { name: 'outerSingle', abbr: 'S', multiplier: 1 },\n TRIPLE: { name: 'triple', abbr: 'T', multiplier: 3 },\n INNER_SINGLE: { name: 'innerSingle', abbr: 'S', multiplier: 1 },\n SINGLE_BULL: { name: 'singleBull', abbr: 'B', multiplier: 1 },\n DOUBLE_BULL: { name: 'doubleBull', abbr: 'DB', multiplier: 2 },\n};\n\nexport const MOBILE_OPTIONS: Partial<DartboardOptions> = {\n missPercent: 7,\n doublePercent: 14,\n outerSinglePercent: 21,\n triplePercent: 14,\n innerSinglePercent: 26,\n singleBullPercent: 9,\n doubleBullPercent: 9,\n};\n\nexport const DEFAULT_SEGMENTS: Segment[] = [\n { segment: 20, position: 1, color: 'Dark' },\n { segment: 1, position: 2, color: 'Light' },\n { segment: 18, position: 3, color: 'Dark' },\n { segment: 4, position: 4, color: 'Light' },\n { segment: 13, position: 5, color: 'Dark' },\n { segment: 6, position: 6, color: 'Light' },\n { segment: 10, position: 7, color: 'Dark' },\n { segment: 15, position: 8, color: 'Light' },\n { segment: 2, position: 9, color: 'Dark' },\n { segment: 17, position: 10, color: 'Light' },\n { segment: 3, position: 11, color: 'Dark' },\n { segment: 19, position: 12, color: 'Light' },\n { segment: 7, position: 13, color: 'Dark' },\n { segment: 16, position: 14, color: 'Light' },\n { segment: 8, position: 15, color: 'Dark' },\n { segment: 11, position: 16, color: 'Light' },\n { segment: 14, position: 17, color: 'Dark' },\n { segment: 9, position: 18, color: 'Light' },\n { segment: 12, position: 19, color: 'Dark' },\n { segment: 5, position: 20, color: 'Light' },\n];\n","import type { Ring, Rings, Segment, Bed, BedTarget, ThrowDetail } from './types';\n\nconst SCORING_RINGS: (keyof Rings)[] = [\n 'DOUBLE',\n 'TRIPLE',\n 'OUTER_SINGLE',\n 'INNER_SINGLE',\n 'SINGLE_BULL',\n 'DOUBLE_BULL',\n];\n\nexport function buildThrowDetail(bed: Bed): ThrowDetail {\n return {\n bed: bed.ring.abbr + bed.segment,\n ring: bed.ring.name,\n score: bed.segment * bed.ring.multiplier,\n };\n}\n\nexport function asPercent(n: number): number {\n return parseFloat((n / 100).toFixed(2));\n}\n\nexport function addRingToSegments(ring: Ring, segments: Segment[]): Bed[] {\n return segments.map((segment) => ({ ...segment, ring }));\n}\n\nexport function parseBed(\n bed: string,\n rings: Rings,\n segments?: Segment[],\n): BedTarget[] {\n // 'miss' keyword — target all segments in the miss ring\n if (bed.toLowerCase() === 'miss') {\n if (!segments) {\n throw new Error(\n 'parseBed: segments are required to resolve the \"miss\" keyword',\n );\n }\n return segments.map((s) => ({ segment: s.segment, ring: 'MISS' as keyof Rings }));\n }\n\n // Number-only string — target all scoring rings on that segment\n const numOnly = bed.match(/^(\\d+)$/);\n if (numOnly) {\n const segment = parseInt(numOnly[1], 10);\n return SCORING_RINGS\n .filter((key) => key in rings)\n .map((ring) => ({ segment, ring }));\n }\n\n const match = bed.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid bed format: \"${bed}\"`);\n }\n\n const [, abbr, numStr] = match.map((s, i) => i === 1 ? s.toUpperCase() : s);\n const segment = parseInt(numStr, 10);\n\n const targets: BedTarget[] = [];\n for (const [key, ring] of Object.entries(rings)) {\n if (ring.abbr === abbr) {\n targets.push({ segment, ring: key as keyof Rings });\n }\n }\n\n if (targets.length === 0) {\n throw new Error(`Unknown bed abbreviation: \"${abbr}\"`);\n }\n\n return targets;\n}\n"],"mappings":"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","names":["segment"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/dartboard.ts","../src/constants.ts","../src/utils.ts"],"sourcesContent":["import './dartboard.css';\nexport { Dartboard } from './dartboard';\nexport type {\n Ring,\n Rings,\n Segment,\n Bed,\n DartboardOptions,\n ThrowDetail,\n HoverDetail,\n BedTarget,\n BedInput,\n HighlightOptions,\n} from './types';\nexport { DEFAULT_OPTIONS, MOBILE_OPTIONS, DEFAULT_RINGS, DEFAULT_SEGMENTS } from './constants';\nexport { buildThrowDetail, asPercent, addRingToSegments, parseBed } from './utils';\n","import { select, type Selection } from 'd3-selection';\nimport { arc, pie, type PieArcDatum } from 'd3-shape';\nimport type {\n DartboardOptions,\n Rings,\n Ring,\n Segment,\n Bed,\n ThrowDetail,\n HoverDetail,\n BedTarget,\n BedInput,\n HighlightOptions,\n} from './types';\nimport { DEFAULT_OPTIONS, DEFAULT_RINGS, DEFAULT_SEGMENTS } from './constants';\nimport { buildThrowDetail, asPercent, addRingToSegments, parseBed } from './utils';\n\n// D3's selection generics are deeply nested and don't compose well across\n// chained calls. Using `any` for internal state avoids 100+ lines of type\n// gymnastics while keeping the public API fully typed.\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface BoardState {\n container: HTMLElement;\n wrapper: Selection<any, any, any, any>;\n width: number;\n height: number;\n radius: number;\n rotation: number;\n segmentWidth: number;\n svg: Selection<any, any, any, any>;\n pie: ReturnType<typeof pie<Bed>>;\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\ninterface SizeMap {\n miss: number;\n double: number;\n outerSingle: number;\n triple: number;\n innerSingle: number;\n singleBull: number;\n doubleBull: number;\n}\n\nfunction buildAriaLabel(bed: Bed): string {\n const detail = buildThrowDetail(bed);\n return `${detail.bed}, scores ${detail.score}`;\n}\n\nexport class Dartboard {\n private board: BoardState | null = null;\n private sizes: SizeMap | null = null;\n private rendered = false;\n private _disabled = false;\n private readonly options: DartboardOptions;\n readonly segments: Segment[];\n readonly rings: Rings;\n\n constructor(\n container: string | HTMLElement,\n options: Partial<DartboardOptions> = {},\n segments: Segment[] = DEFAULT_SEGMENTS,\n rings: Rings = DEFAULT_RINGS,\n ) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.segments = segments;\n this.rings = rings;\n\n const percentSum =\n this.options.missPercent +\n this.options.doublePercent +\n this.options.outerSinglePercent +\n this.options.triplePercent +\n this.options.innerSinglePercent +\n this.options.singleBullPercent +\n this.options.doubleBullPercent;\n\n if (percentSum !== 100) {\n throw new Error(\n `Dartboard: ring percentages must sum to 100 (got ${percentSum})`,\n );\n }\n\n const boardContainer =\n typeof container === 'string'\n ? document.querySelector<HTMLElement>(container)\n : container;\n\n if (!boardContainer) {\n throw new Error(`Dartboard: container not found`);\n }\n\n const padding = this.options.padding;\n const boardSize =\n this.options.size ||\n Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);\n const width = boardSize - padding * 2;\n const viewBoxSize = boardSize;\n const segmentWidth = 360 / segments.length;\n const radius = width / 2;\n const rotation = segmentWidth / -2;\n\n const wrapper = select(boardContainer)\n .append('div')\n .classed('c-Dartboard', true);\n\n const svg = wrapper\n .append('svg')\n .attr('viewBox', `0 0 ${viewBoxSize} ${viewBoxSize}`)\n .attr('role', 'group')\n .attr('aria-label', 'Dartboard')\n .append('g')\n .attr(\n 'transform',\n `translate(${viewBoxSize / 2}, ${viewBoxSize / 2}) rotate(${rotation})`,\n );\n\n const pieFn = pie<Bed>()\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))\n .value(() => segmentWidth);\n\n this.board = {\n container: boardContainer,\n wrapper,\n width,\n height: width,\n radius,\n rotation,\n segmentWidth,\n svg,\n pie: pieFn,\n };\n\n this.sizes = {\n miss: radius * asPercent(this.options.missPercent),\n double: radius * asPercent(this.options.doublePercent),\n outerSingle: radius * asPercent(this.options.outerSinglePercent),\n triple: radius * asPercent(this.options.triplePercent),\n innerSingle: radius * asPercent(this.options.innerSinglePercent),\n singleBull: radius * asPercent(this.options.singleBullPercent),\n doubleBull: radius * asPercent(this.options.doubleBullPercent),\n };\n }\n\n render(): this {\n if (!this.board || !this.sizes) return this;\n if (this.rendered) return this;\n this.rendered = true;\n\n const { board, sizes } = this;\n\n let innerRadius = 0;\n let outerRadius = innerRadius + sizes.doubleBull;\n this.renderBeds(\n board,\n this.rings.DOUBLE_BULL,\n [{ segment: 25, color: 'Dark' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.singleBull;\n this.renderBeds(\n board,\n this.rings.SINGLE_BULL,\n [{ segment: 25, color: 'Light' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.innerSingle;\n this.renderBeds(\n board,\n this.rings.INNER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.triple;\n this.renderBeds(\n board,\n this.rings.TRIPLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.outerSingle;\n this.renderBeds(\n board,\n this.rings.OUTER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.double;\n this.renderBeds(\n board,\n this.rings.DOUBLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = board.radius - sizes.miss;\n outerRadius = board.radius;\n this.renderMissRing(\n board,\n this.rings.MISS,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n return this;\n }\n\n destroy(): void {\n if (this.board) {\n // Remove all D3 event listeners before removing from DOM\n this.board.wrapper.selectAll('.c-Dartboard-bed')\n .on('pointerup', null)\n .on('pointerenter', null)\n .on('pointerleave', null)\n .on('keydown', null);\n this.board.wrapper.remove();\n this.board = null;\n this.sizes = null;\n this.rendered = false;\n }\n }\n\n get disabled(): boolean {\n return this._disabled;\n }\n\n disable(): this {\n this._disabled = true;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', true);\n }\n return this;\n }\n\n enable(): this {\n this._disabled = false;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', false);\n }\n return this;\n }\n\n throwAt(target: BedInput): void {\n if (!this.board || this._disabled) return;\n\n const targets = this.resolveTargets([target]);\n if (targets.length === 0) return;\n const first = targets[0];\n\n if (!this.isValidTarget(first)) {\n throw new Error(`Dartboard: invalid throw target — segment ${first.segment} does not exist`);\n }\n\n const ring = this.rings[first.ring];\n const bed: Bed = { segment: first.segment, color: 'Dark', ring };\n const detail = buildThrowDetail(bed);\n\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n highlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, true);\n }\n }\n\n unhighlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, false);\n }\n }\n\n reset(className = 'is-highlighted'): void {\n if (!this.board) return;\n this.board.wrapper.selectAll(`.${className}`).classed(className, false);\n }\n\n private isValidTarget(target: Required<BedTarget>): boolean {\n const isBull = target.ring === 'DOUBLE_BULL' || target.ring === 'SINGLE_BULL';\n if (isBull) {\n return target.segment === 25;\n }\n return this.segments.some((s) => s.segment === target.segment);\n }\n\n private resolveTargets(inputs: BedInput[]): Required<BedTarget>[] {\n return inputs.flatMap((input): Required<BedTarget>[] => {\n if (typeof input === 'number') {\n return parseBed(String(input), this.rings, this.segments) as Required<BedTarget>[];\n }\n if (typeof input === 'string') {\n return parseBed(input, this.rings, this.segments) as Required<BedTarget>[];\n }\n if (!input.ring) {\n return parseBed(String(input.segment), this.rings, this.segments) as Required<BedTarget>[];\n }\n return [input as Required<BedTarget>];\n });\n }\n\n private dispatchThrow(bed: Bed): void {\n if (!this.board || this._disabled) return;\n const detail = buildThrowDetail(bed);\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n private dispatchHover(bed: Bed, hovering: boolean): void {\n if (!this.board || this._disabled) return;\n const throwDetail = buildThrowDetail(bed);\n const detail: HoverDetail = { ...throwDetail, hovering };\n this.board.container.dispatchEvent(\n new CustomEvent<HoverDetail>('hover', { detail }),\n );\n }\n\n private renderBeds(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const className = `c-Dartboard-${ring.name}`;\n const arcFn = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const beds = board.svg\n .append('g')\n .classed(className, true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} ${className}--${d.data.segment} is${d.data.color}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'pointerenter',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', true);\n this.dispatchHover(d.data, true);\n },\n )\n .on(\n 'pointerleave',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', false);\n this.dispatchHover(d.data, false);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n beds.append('path').attr('d', arcFn as never);\n }\n\n private renderMissRing(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const missArc = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const missBeds = board.svg\n .append('g')\n .classed('c-Dartboard-miss', true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} c-Dartboard-miss--${d.data.segment}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n missBeds.append('path').attr('d', missArc as never);\n\n const determineRotation = (bedData: Bed) =>\n -board.rotation + board.segmentWidth * ((bedData.position ?? 0) - 1);\n\n const determineX = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[0];\n\n const determineY = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[1];\n\n missBeds\n .append('text')\n .classed('c-Dartboard-missLabel', true)\n .attr('x', (d: PieArcDatum<Bed>) => determineX(d))\n .attr('y', (d: PieArcDatum<Bed>) => determineY(d))\n .attr('dy', '.35em')\n .attr(\n 'transform',\n (d: PieArcDatum<Bed>) =>\n `rotate(${determineRotation(d.data)}, ${determineX(d)}, ${determineY(d)})`,\n )\n .attr('text-anchor', 'middle')\n .text((d: PieArcDatum<Bed>) => d.data.segment);\n }\n}\n","import type { DartboardOptions, Rings, Segment } from './types';\n\nexport const DEFAULT_OPTIONS: DartboardOptions = {\n size: null,\n padding: 0,\n missPercent: 10,\n doublePercent: 10,\n outerSinglePercent: 25,\n triplePercent: 10,\n innerSinglePercent: 30,\n singleBullPercent: 8,\n doubleBullPercent: 7,\n};\n\nexport const DEFAULT_RINGS: Rings = {\n MISS: { name: 'miss', abbr: 'M', multiplier: 0 },\n DOUBLE: { name: 'double', abbr: 'D', multiplier: 2 },\n OUTER_SINGLE: { name: 'outerSingle', abbr: 'S', multiplier: 1 },\n TRIPLE: { name: 'triple', abbr: 'T', multiplier: 3 },\n INNER_SINGLE: { name: 'innerSingle', abbr: 'S', multiplier: 1 },\n SINGLE_BULL: { name: 'singleBull', abbr: 'B', multiplier: 1 },\n DOUBLE_BULL: { name: 'doubleBull', abbr: 'DB', multiplier: 2 },\n};\n\nexport const MOBILE_OPTIONS: Partial<DartboardOptions> = {\n missPercent: 7,\n doublePercent: 14,\n outerSinglePercent: 21,\n triplePercent: 14,\n innerSinglePercent: 26,\n singleBullPercent: 9,\n doubleBullPercent: 9,\n};\n\nexport const DEFAULT_SEGMENTS: Segment[] = [\n { segment: 20, position: 1, color: 'Dark' },\n { segment: 1, position: 2, color: 'Light' },\n { segment: 18, position: 3, color: 'Dark' },\n { segment: 4, position: 4, color: 'Light' },\n { segment: 13, position: 5, color: 'Dark' },\n { segment: 6, position: 6, color: 'Light' },\n { segment: 10, position: 7, color: 'Dark' },\n { segment: 15, position: 8, color: 'Light' },\n { segment: 2, position: 9, color: 'Dark' },\n { segment: 17, position: 10, color: 'Light' },\n { segment: 3, position: 11, color: 'Dark' },\n { segment: 19, position: 12, color: 'Light' },\n { segment: 7, position: 13, color: 'Dark' },\n { segment: 16, position: 14, color: 'Light' },\n { segment: 8, position: 15, color: 'Dark' },\n { segment: 11, position: 16, color: 'Light' },\n { segment: 14, position: 17, color: 'Dark' },\n { segment: 9, position: 18, color: 'Light' },\n { segment: 12, position: 19, color: 'Dark' },\n { segment: 5, position: 20, color: 'Light' },\n];\n","import type { Ring, Rings, Segment, Bed, BedTarget, ThrowDetail } from './types';\n\nconst SCORING_RINGS: (keyof Rings)[] = [\n 'DOUBLE',\n 'TRIPLE',\n 'OUTER_SINGLE',\n 'INNER_SINGLE',\n 'SINGLE_BULL',\n 'DOUBLE_BULL',\n];\n\nexport function buildThrowDetail(bed: Bed): ThrowDetail {\n return {\n bed: bed.ring.abbr + bed.segment,\n segment: bed.segment,\n ring: bed.ring.name,\n score: bed.segment * bed.ring.multiplier,\n };\n}\n\nexport function asPercent(n: number): number {\n return parseFloat((n / 100).toFixed(2));\n}\n\nexport function addRingToSegments(ring: Ring, segments: Segment[]): Bed[] {\n return segments.map((segment) => ({ ...segment, ring }));\n}\n\nexport function parseBed(\n bed: string,\n rings: Rings,\n segments?: Segment[],\n): BedTarget[] {\n // 'miss' keyword — target all segments in the miss ring\n if (bed.toLowerCase() === 'miss') {\n if (!segments) {\n throw new Error(\n 'parseBed: segments are required to resolve the \"miss\" keyword',\n );\n }\n return segments.map((s) => ({ segment: s.segment, ring: 'MISS' as keyof Rings }));\n }\n\n // Number-only string — target all scoring rings on that segment\n const numOnly = bed.match(/^(\\d+)$/);\n if (numOnly) {\n const segment = parseInt(numOnly[1], 10);\n return SCORING_RINGS\n .filter((key) => key in rings)\n .map((ring) => ({ segment, ring }));\n }\n\n const match = bed.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid bed format: \"${bed}\"`);\n }\n\n const [, abbr, numStr] = match.map((s, i) => i === 1 ? s.toUpperCase() : s);\n const segment = parseInt(numStr, 10);\n\n const targets: BedTarget[] = [];\n for (const [key, ring] of Object.entries(rings)) {\n if (ring.abbr === abbr) {\n targets.push({ segment, ring: key as keyof Rings });\n }\n }\n\n if (targets.length === 0) {\n throw new Error(`Unknown bed abbreviation: \"${abbr}\"`);\n }\n\n return targets;\n}\n"],"mappings":"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","names":["segment"]}
package/dist/index.d.cts CHANGED
@@ -22,6 +22,7 @@ interface Bed extends Segment {
22
22
  }
23
23
  interface DartboardOptions {
24
24
  size: number | null;
25
+ padding: number;
25
26
  missPercent: number;
26
27
  doublePercent: number;
27
28
  outerSinglePercent: number;
@@ -32,11 +33,13 @@ interface DartboardOptions {
32
33
  }
33
34
  interface ThrowDetail {
34
35
  bed: string;
36
+ segment: number;
35
37
  ring: string;
36
38
  score: number;
37
39
  }
38
40
  interface HoverDetail {
39
41
  bed: string;
42
+ segment: number;
40
43
  ring: string;
41
44
  score: number;
42
45
  hovering: boolean;
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ interface Bed extends Segment {
22
22
  }
23
23
  interface DartboardOptions {
24
24
  size: number | null;
25
+ padding: number;
25
26
  missPercent: number;
26
27
  doublePercent: number;
27
28
  outerSinglePercent: number;
@@ -32,11 +33,13 @@ interface DartboardOptions {
32
33
  }
33
34
  interface ThrowDetail {
34
35
  bed: string;
36
+ segment: number;
35
37
  ring: string;
36
38
  score: number;
37
39
  }
38
40
  interface HoverDetail {
39
41
  bed: string;
42
+ segment: number;
40
43
  ring: string;
41
44
  score: number;
42
45
  hovering: boolean;
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { arc, pie } from "d3-shape";
5
5
  // src/constants.ts
6
6
  var DEFAULT_OPTIONS = {
7
7
  size: null,
8
+ padding: 0,
8
9
  missPercent: 10,
9
10
  doublePercent: 10,
10
11
  outerSinglePercent: 25,
@@ -66,6 +67,7 @@ var SCORING_RINGS = [
66
67
  function buildThrowDetail(bed) {
67
68
  return {
68
69
  bed: bed.ring.abbr + bed.segment,
70
+ segment: bed.segment,
69
71
  ring: bed.ring.name,
70
72
  score: bed.segment * bed.ring.multiplier
71
73
  };
@@ -132,14 +134,17 @@ var Dartboard = class {
132
134
  if (!boardContainer) {
133
135
  throw new Error(`Dartboard: container not found`);
134
136
  }
135
- const width = this.options.size || Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);
137
+ const padding = this.options.padding;
138
+ const boardSize = this.options.size || Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);
139
+ const width = boardSize - padding * 2;
140
+ const viewBoxSize = boardSize;
136
141
  const segmentWidth = 360 / segments.length;
137
142
  const radius = width / 2;
138
143
  const rotation = segmentWidth / -2;
139
144
  const wrapper = select(boardContainer).append("div").classed("c-Dartboard", true);
140
- const svg = wrapper.append("svg").attr("viewBox", `0 0 ${width} ${width}`).attr("role", "group").attr("aria-label", "Dartboard").append("g").attr(
145
+ const svg = wrapper.append("svg").attr("viewBox", `0 0 ${viewBoxSize} ${viewBoxSize}`).attr("role", "group").attr("aria-label", "Dartboard").append("g").attr(
141
146
  "transform",
142
- `translate(${radius}, ${radius}) rotate(${rotation})`
147
+ `translate(${viewBoxSize / 2}, ${viewBoxSize / 2}) rotate(${rotation})`
143
148
  );
144
149
  const pieFn = pie().sort((a, b) => (a.position ?? 0) - (b.position ?? 0)).value(() => segmentWidth);
145
150
  this.board = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dartboard.ts","../src/constants.ts","../src/utils.ts"],"sourcesContent":["import { select, type Selection } from 'd3-selection';\nimport { arc, pie, type PieArcDatum } from 'd3-shape';\nimport type {\n DartboardOptions,\n Rings,\n Ring,\n Segment,\n Bed,\n ThrowDetail,\n HoverDetail,\n BedTarget,\n BedInput,\n HighlightOptions,\n} from './types';\nimport { DEFAULT_OPTIONS, DEFAULT_RINGS, DEFAULT_SEGMENTS } from './constants';\nimport { buildThrowDetail, asPercent, addRingToSegments, parseBed } from './utils';\n\n// D3's selection generics are deeply nested and don't compose well across\n// chained calls. Using `any` for internal state avoids 100+ lines of type\n// gymnastics while keeping the public API fully typed.\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface BoardState {\n container: HTMLElement;\n wrapper: Selection<any, any, any, any>;\n width: number;\n height: number;\n radius: number;\n rotation: number;\n segmentWidth: number;\n svg: Selection<any, any, any, any>;\n pie: ReturnType<typeof pie<Bed>>;\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\ninterface SizeMap {\n miss: number;\n double: number;\n outerSingle: number;\n triple: number;\n innerSingle: number;\n singleBull: number;\n doubleBull: number;\n}\n\nfunction buildAriaLabel(bed: Bed): string {\n const detail = buildThrowDetail(bed);\n return `${detail.bed}, scores ${detail.score}`;\n}\n\nexport class Dartboard {\n private board: BoardState | null = null;\n private sizes: SizeMap | null = null;\n private rendered = false;\n private _disabled = false;\n private readonly options: DartboardOptions;\n readonly segments: Segment[];\n readonly rings: Rings;\n\n constructor(\n container: string | HTMLElement,\n options: Partial<DartboardOptions> = {},\n segments: Segment[] = DEFAULT_SEGMENTS,\n rings: Rings = DEFAULT_RINGS,\n ) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.segments = segments;\n this.rings = rings;\n\n const percentSum =\n this.options.missPercent +\n this.options.doublePercent +\n this.options.outerSinglePercent +\n this.options.triplePercent +\n this.options.innerSinglePercent +\n this.options.singleBullPercent +\n this.options.doubleBullPercent;\n\n if (percentSum !== 100) {\n throw new Error(\n `Dartboard: ring percentages must sum to 100 (got ${percentSum})`,\n );\n }\n\n const boardContainer =\n typeof container === 'string'\n ? document.querySelector<HTMLElement>(container)\n : container;\n\n if (!boardContainer) {\n throw new Error(`Dartboard: container not found`);\n }\n\n const width =\n this.options.size ||\n Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);\n const segmentWidth = 360 / segments.length;\n const radius = width / 2;\n const rotation = segmentWidth / -2;\n\n const wrapper = select(boardContainer)\n .append('div')\n .classed('c-Dartboard', true);\n\n const svg = wrapper\n .append('svg')\n .attr('viewBox', `0 0 ${width} ${width}`)\n .attr('role', 'group')\n .attr('aria-label', 'Dartboard')\n .append('g')\n .attr(\n 'transform',\n `translate(${radius}, ${radius}) rotate(${rotation})`,\n );\n\n const pieFn = pie<Bed>()\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))\n .value(() => segmentWidth);\n\n this.board = {\n container: boardContainer,\n wrapper,\n width,\n height: width,\n radius,\n rotation,\n segmentWidth,\n svg,\n pie: pieFn,\n };\n\n this.sizes = {\n miss: radius * asPercent(this.options.missPercent),\n double: radius * asPercent(this.options.doublePercent),\n outerSingle: radius * asPercent(this.options.outerSinglePercent),\n triple: radius * asPercent(this.options.triplePercent),\n innerSingle: radius * asPercent(this.options.innerSinglePercent),\n singleBull: radius * asPercent(this.options.singleBullPercent),\n doubleBull: radius * asPercent(this.options.doubleBullPercent),\n };\n }\n\n render(): this {\n if (!this.board || !this.sizes) return this;\n if (this.rendered) return this;\n this.rendered = true;\n\n const { board, sizes } = this;\n\n let innerRadius = 0;\n let outerRadius = innerRadius + sizes.doubleBull;\n this.renderBeds(\n board,\n this.rings.DOUBLE_BULL,\n [{ segment: 25, color: 'Dark' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.singleBull;\n this.renderBeds(\n board,\n this.rings.SINGLE_BULL,\n [{ segment: 25, color: 'Light' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.innerSingle;\n this.renderBeds(\n board,\n this.rings.INNER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.triple;\n this.renderBeds(\n board,\n this.rings.TRIPLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.outerSingle;\n this.renderBeds(\n board,\n this.rings.OUTER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.double;\n this.renderBeds(\n board,\n this.rings.DOUBLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = board.radius - sizes.miss;\n outerRadius = board.radius;\n this.renderMissRing(\n board,\n this.rings.MISS,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n return this;\n }\n\n destroy(): void {\n if (this.board) {\n // Remove all D3 event listeners before removing from DOM\n this.board.wrapper.selectAll('.c-Dartboard-bed')\n .on('pointerup', null)\n .on('pointerenter', null)\n .on('pointerleave', null)\n .on('keydown', null);\n this.board.wrapper.remove();\n this.board = null;\n this.sizes = null;\n this.rendered = false;\n }\n }\n\n get disabled(): boolean {\n return this._disabled;\n }\n\n disable(): this {\n this._disabled = true;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', true);\n }\n return this;\n }\n\n enable(): this {\n this._disabled = false;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', false);\n }\n return this;\n }\n\n throwAt(target: BedInput): void {\n if (!this.board || this._disabled) return;\n\n const targets = this.resolveTargets([target]);\n if (targets.length === 0) return;\n const first = targets[0];\n\n if (!this.isValidTarget(first)) {\n throw new Error(`Dartboard: invalid throw target — segment ${first.segment} does not exist`);\n }\n\n const ring = this.rings[first.ring];\n const bed: Bed = { segment: first.segment, color: 'Dark', ring };\n const detail = buildThrowDetail(bed);\n\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n highlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, true);\n }\n }\n\n unhighlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, false);\n }\n }\n\n reset(className = 'is-highlighted'): void {\n if (!this.board) return;\n this.board.wrapper.selectAll(`.${className}`).classed(className, false);\n }\n\n private isValidTarget(target: Required<BedTarget>): boolean {\n const isBull = target.ring === 'DOUBLE_BULL' || target.ring === 'SINGLE_BULL';\n if (isBull) {\n return target.segment === 25;\n }\n return this.segments.some((s) => s.segment === target.segment);\n }\n\n private resolveTargets(inputs: BedInput[]): Required<BedTarget>[] {\n return inputs.flatMap((input): Required<BedTarget>[] => {\n if (typeof input === 'number') {\n return parseBed(String(input), this.rings, this.segments) as Required<BedTarget>[];\n }\n if (typeof input === 'string') {\n return parseBed(input, this.rings, this.segments) as Required<BedTarget>[];\n }\n if (!input.ring) {\n return parseBed(String(input.segment), this.rings, this.segments) as Required<BedTarget>[];\n }\n return [input as Required<BedTarget>];\n });\n }\n\n private dispatchThrow(bed: Bed): void {\n if (!this.board || this._disabled) return;\n const detail = buildThrowDetail(bed);\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n private dispatchHover(bed: Bed, hovering: boolean): void {\n if (!this.board || this._disabled) return;\n const throwDetail = buildThrowDetail(bed);\n const detail: HoverDetail = { ...throwDetail, hovering };\n this.board.container.dispatchEvent(\n new CustomEvent<HoverDetail>('hover', { detail }),\n );\n }\n\n private renderBeds(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const className = `c-Dartboard-${ring.name}`;\n const arcFn = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const beds = board.svg\n .append('g')\n .classed(className, true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} ${className}--${d.data.segment} is${d.data.color}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'pointerenter',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', true);\n this.dispatchHover(d.data, true);\n },\n )\n .on(\n 'pointerleave',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', false);\n this.dispatchHover(d.data, false);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n beds.append('path').attr('d', arcFn as never);\n }\n\n private renderMissRing(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const missArc = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const missBeds = board.svg\n .append('g')\n .classed('c-Dartboard-miss', true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} c-Dartboard-miss--${d.data.segment}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n missBeds.append('path').attr('d', missArc as never);\n\n const determineRotation = (bedData: Bed) =>\n -board.rotation + board.segmentWidth * ((bedData.position ?? 0) - 1);\n\n const determineX = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[0];\n\n const determineY = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[1];\n\n missBeds\n .append('text')\n .classed('c-Dartboard-missLabel', true)\n .attr('x', (d: PieArcDatum<Bed>) => determineX(d))\n .attr('y', (d: PieArcDatum<Bed>) => determineY(d))\n .attr('dy', '.35em')\n .attr(\n 'transform',\n (d: PieArcDatum<Bed>) =>\n `rotate(${determineRotation(d.data)}, ${determineX(d)}, ${determineY(d)})`,\n )\n .attr('text-anchor', 'middle')\n .text((d: PieArcDatum<Bed>) => d.data.segment);\n }\n}\n","import type { DartboardOptions, Rings, Segment } from './types';\n\nexport const DEFAULT_OPTIONS: DartboardOptions = {\n size: null,\n missPercent: 10,\n doublePercent: 10,\n outerSinglePercent: 25,\n triplePercent: 10,\n innerSinglePercent: 30,\n singleBullPercent: 8,\n doubleBullPercent: 7,\n};\n\nexport const DEFAULT_RINGS: Rings = {\n MISS: { name: 'miss', abbr: 'M', multiplier: 0 },\n DOUBLE: { name: 'double', abbr: 'D', multiplier: 2 },\n OUTER_SINGLE: { name: 'outerSingle', abbr: 'S', multiplier: 1 },\n TRIPLE: { name: 'triple', abbr: 'T', multiplier: 3 },\n INNER_SINGLE: { name: 'innerSingle', abbr: 'S', multiplier: 1 },\n SINGLE_BULL: { name: 'singleBull', abbr: 'B', multiplier: 1 },\n DOUBLE_BULL: { name: 'doubleBull', abbr: 'DB', multiplier: 2 },\n};\n\nexport const MOBILE_OPTIONS: Partial<DartboardOptions> = {\n missPercent: 7,\n doublePercent: 14,\n outerSinglePercent: 21,\n triplePercent: 14,\n innerSinglePercent: 26,\n singleBullPercent: 9,\n doubleBullPercent: 9,\n};\n\nexport const DEFAULT_SEGMENTS: Segment[] = [\n { segment: 20, position: 1, color: 'Dark' },\n { segment: 1, position: 2, color: 'Light' },\n { segment: 18, position: 3, color: 'Dark' },\n { segment: 4, position: 4, color: 'Light' },\n { segment: 13, position: 5, color: 'Dark' },\n { segment: 6, position: 6, color: 'Light' },\n { segment: 10, position: 7, color: 'Dark' },\n { segment: 15, position: 8, color: 'Light' },\n { segment: 2, position: 9, color: 'Dark' },\n { segment: 17, position: 10, color: 'Light' },\n { segment: 3, position: 11, color: 'Dark' },\n { segment: 19, position: 12, color: 'Light' },\n { segment: 7, position: 13, color: 'Dark' },\n { segment: 16, position: 14, color: 'Light' },\n { segment: 8, position: 15, color: 'Dark' },\n { segment: 11, position: 16, color: 'Light' },\n { segment: 14, position: 17, color: 'Dark' },\n { segment: 9, position: 18, color: 'Light' },\n { segment: 12, position: 19, color: 'Dark' },\n { segment: 5, position: 20, color: 'Light' },\n];\n","import type { Ring, Rings, Segment, Bed, BedTarget, ThrowDetail } from './types';\n\nconst SCORING_RINGS: (keyof Rings)[] = [\n 'DOUBLE',\n 'TRIPLE',\n 'OUTER_SINGLE',\n 'INNER_SINGLE',\n 'SINGLE_BULL',\n 'DOUBLE_BULL',\n];\n\nexport function buildThrowDetail(bed: Bed): ThrowDetail {\n return {\n bed: bed.ring.abbr + bed.segment,\n ring: bed.ring.name,\n score: bed.segment * bed.ring.multiplier,\n };\n}\n\nexport function asPercent(n: number): number {\n return parseFloat((n / 100).toFixed(2));\n}\n\nexport function addRingToSegments(ring: Ring, segments: Segment[]): Bed[] {\n return segments.map((segment) => ({ ...segment, ring }));\n}\n\nexport function parseBed(\n bed: string,\n rings: Rings,\n segments?: Segment[],\n): BedTarget[] {\n // 'miss' keyword — target all segments in the miss ring\n if (bed.toLowerCase() === 'miss') {\n if (!segments) {\n throw new Error(\n 'parseBed: segments are required to resolve the \"miss\" keyword',\n );\n }\n return segments.map((s) => ({ segment: s.segment, ring: 'MISS' as keyof Rings }));\n }\n\n // Number-only string — target all scoring rings on that segment\n const numOnly = bed.match(/^(\\d+)$/);\n if (numOnly) {\n const segment = parseInt(numOnly[1], 10);\n return SCORING_RINGS\n .filter((key) => key in rings)\n .map((ring) => ({ segment, ring }));\n }\n\n const match = bed.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid bed format: \"${bed}\"`);\n }\n\n const [, abbr, numStr] = match.map((s, i) => i === 1 ? s.toUpperCase() : s);\n const segment = parseInt(numStr, 10);\n\n const targets: BedTarget[] = [];\n for (const [key, ring] of Object.entries(rings)) {\n if (ring.abbr === abbr) {\n targets.push({ segment, ring: key as keyof Rings });\n }\n }\n\n if (targets.length === 0) {\n throw new Error(`Unknown bed abbreviation: \"${abbr}\"`);\n }\n\n return targets;\n}\n"],"mappings":"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","names":["segment"]}
1
+ {"version":3,"sources":["../src/dartboard.ts","../src/constants.ts","../src/utils.ts"],"sourcesContent":["import { select, type Selection } from 'd3-selection';\nimport { arc, pie, type PieArcDatum } from 'd3-shape';\nimport type {\n DartboardOptions,\n Rings,\n Ring,\n Segment,\n Bed,\n ThrowDetail,\n HoverDetail,\n BedTarget,\n BedInput,\n HighlightOptions,\n} from './types';\nimport { DEFAULT_OPTIONS, DEFAULT_RINGS, DEFAULT_SEGMENTS } from './constants';\nimport { buildThrowDetail, asPercent, addRingToSegments, parseBed } from './utils';\n\n// D3's selection generics are deeply nested and don't compose well across\n// chained calls. Using `any` for internal state avoids 100+ lines of type\n// gymnastics while keeping the public API fully typed.\n/* eslint-disable @typescript-eslint/no-explicit-any */\ninterface BoardState {\n container: HTMLElement;\n wrapper: Selection<any, any, any, any>;\n width: number;\n height: number;\n radius: number;\n rotation: number;\n segmentWidth: number;\n svg: Selection<any, any, any, any>;\n pie: ReturnType<typeof pie<Bed>>;\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\ninterface SizeMap {\n miss: number;\n double: number;\n outerSingle: number;\n triple: number;\n innerSingle: number;\n singleBull: number;\n doubleBull: number;\n}\n\nfunction buildAriaLabel(bed: Bed): string {\n const detail = buildThrowDetail(bed);\n return `${detail.bed}, scores ${detail.score}`;\n}\n\nexport class Dartboard {\n private board: BoardState | null = null;\n private sizes: SizeMap | null = null;\n private rendered = false;\n private _disabled = false;\n private readonly options: DartboardOptions;\n readonly segments: Segment[];\n readonly rings: Rings;\n\n constructor(\n container: string | HTMLElement,\n options: Partial<DartboardOptions> = {},\n segments: Segment[] = DEFAULT_SEGMENTS,\n rings: Rings = DEFAULT_RINGS,\n ) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.segments = segments;\n this.rings = rings;\n\n const percentSum =\n this.options.missPercent +\n this.options.doublePercent +\n this.options.outerSinglePercent +\n this.options.triplePercent +\n this.options.innerSinglePercent +\n this.options.singleBullPercent +\n this.options.doubleBullPercent;\n\n if (percentSum !== 100) {\n throw new Error(\n `Dartboard: ring percentages must sum to 100 (got ${percentSum})`,\n );\n }\n\n const boardContainer =\n typeof container === 'string'\n ? document.querySelector<HTMLElement>(container)\n : container;\n\n if (!boardContainer) {\n throw new Error(`Dartboard: container not found`);\n }\n\n const padding = this.options.padding;\n const boardSize =\n this.options.size ||\n Math.min(boardContainer.offsetHeight, boardContainer.offsetWidth);\n const width = boardSize - padding * 2;\n const viewBoxSize = boardSize;\n const segmentWidth = 360 / segments.length;\n const radius = width / 2;\n const rotation = segmentWidth / -2;\n\n const wrapper = select(boardContainer)\n .append('div')\n .classed('c-Dartboard', true);\n\n const svg = wrapper\n .append('svg')\n .attr('viewBox', `0 0 ${viewBoxSize} ${viewBoxSize}`)\n .attr('role', 'group')\n .attr('aria-label', 'Dartboard')\n .append('g')\n .attr(\n 'transform',\n `translate(${viewBoxSize / 2}, ${viewBoxSize / 2}) rotate(${rotation})`,\n );\n\n const pieFn = pie<Bed>()\n .sort((a, b) => (a.position ?? 0) - (b.position ?? 0))\n .value(() => segmentWidth);\n\n this.board = {\n container: boardContainer,\n wrapper,\n width,\n height: width,\n radius,\n rotation,\n segmentWidth,\n svg,\n pie: pieFn,\n };\n\n this.sizes = {\n miss: radius * asPercent(this.options.missPercent),\n double: radius * asPercent(this.options.doublePercent),\n outerSingle: radius * asPercent(this.options.outerSinglePercent),\n triple: radius * asPercent(this.options.triplePercent),\n innerSingle: radius * asPercent(this.options.innerSinglePercent),\n singleBull: radius * asPercent(this.options.singleBullPercent),\n doubleBull: radius * asPercent(this.options.doubleBullPercent),\n };\n }\n\n render(): this {\n if (!this.board || !this.sizes) return this;\n if (this.rendered) return this;\n this.rendered = true;\n\n const { board, sizes } = this;\n\n let innerRadius = 0;\n let outerRadius = innerRadius + sizes.doubleBull;\n this.renderBeds(\n board,\n this.rings.DOUBLE_BULL,\n [{ segment: 25, color: 'Dark' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.singleBull;\n this.renderBeds(\n board,\n this.rings.SINGLE_BULL,\n [{ segment: 25, color: 'Light' }],\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.innerSingle;\n this.renderBeds(\n board,\n this.rings.INNER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.triple;\n this.renderBeds(\n board,\n this.rings.TRIPLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.outerSingle;\n this.renderBeds(\n board,\n this.rings.OUTER_SINGLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = outerRadius;\n outerRadius = innerRadius + sizes.double;\n this.renderBeds(\n board,\n this.rings.DOUBLE,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n innerRadius = board.radius - sizes.miss;\n outerRadius = board.radius;\n this.renderMissRing(\n board,\n this.rings.MISS,\n this.segments,\n outerRadius,\n innerRadius,\n );\n\n return this;\n }\n\n destroy(): void {\n if (this.board) {\n // Remove all D3 event listeners before removing from DOM\n this.board.wrapper.selectAll('.c-Dartboard-bed')\n .on('pointerup', null)\n .on('pointerenter', null)\n .on('pointerleave', null)\n .on('keydown', null);\n this.board.wrapper.remove();\n this.board = null;\n this.sizes = null;\n this.rendered = false;\n }\n }\n\n get disabled(): boolean {\n return this._disabled;\n }\n\n disable(): this {\n this._disabled = true;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', true);\n }\n return this;\n }\n\n enable(): this {\n this._disabled = false;\n if (this.board) {\n this.board.wrapper.classed('is-disabled', false);\n }\n return this;\n }\n\n throwAt(target: BedInput): void {\n if (!this.board || this._disabled) return;\n\n const targets = this.resolveTargets([target]);\n if (targets.length === 0) return;\n const first = targets[0];\n\n if (!this.isValidTarget(first)) {\n throw new Error(`Dartboard: invalid throw target — segment ${first.segment} does not exist`);\n }\n\n const ring = this.rings[first.ring];\n const bed: Bed = { segment: first.segment, color: 'Dark', ring };\n const detail = buildThrowDetail(bed);\n\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n highlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, true);\n }\n }\n\n unhighlight(targets: BedInput[], options: HighlightOptions = {}): void {\n if (!this.board) return;\n const className = options.className || 'is-highlighted';\n\n for (const target of this.resolveTargets(targets)) {\n const ring = this.rings[target.ring];\n const selector = `.c-Dartboard-${ring.name} .c-Dartboard-bed--${target.segment}`;\n this.board.wrapper.selectAll(selector).classed(className, false);\n }\n }\n\n reset(className = 'is-highlighted'): void {\n if (!this.board) return;\n this.board.wrapper.selectAll(`.${className}`).classed(className, false);\n }\n\n private isValidTarget(target: Required<BedTarget>): boolean {\n const isBull = target.ring === 'DOUBLE_BULL' || target.ring === 'SINGLE_BULL';\n if (isBull) {\n return target.segment === 25;\n }\n return this.segments.some((s) => s.segment === target.segment);\n }\n\n private resolveTargets(inputs: BedInput[]): Required<BedTarget>[] {\n return inputs.flatMap((input): Required<BedTarget>[] => {\n if (typeof input === 'number') {\n return parseBed(String(input), this.rings, this.segments) as Required<BedTarget>[];\n }\n if (typeof input === 'string') {\n return parseBed(input, this.rings, this.segments) as Required<BedTarget>[];\n }\n if (!input.ring) {\n return parseBed(String(input.segment), this.rings, this.segments) as Required<BedTarget>[];\n }\n return [input as Required<BedTarget>];\n });\n }\n\n private dispatchThrow(bed: Bed): void {\n if (!this.board || this._disabled) return;\n const detail = buildThrowDetail(bed);\n this.board.container.dispatchEvent(\n new CustomEvent<ThrowDetail>('throw', { detail }),\n );\n }\n\n private dispatchHover(bed: Bed, hovering: boolean): void {\n if (!this.board || this._disabled) return;\n const throwDetail = buildThrowDetail(bed);\n const detail: HoverDetail = { ...throwDetail, hovering };\n this.board.container.dispatchEvent(\n new CustomEvent<HoverDetail>('hover', { detail }),\n );\n }\n\n private renderBeds(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const className = `c-Dartboard-${ring.name}`;\n const arcFn = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const beds = board.svg\n .append('g')\n .classed(className, true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} ${className}--${d.data.segment} is${d.data.color}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'pointerenter',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', true);\n this.dispatchHover(d.data, true);\n },\n )\n .on(\n 'pointerleave',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n select(_event.currentTarget as Element).classed('is-hovered', false);\n this.dispatchHover(d.data, false);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n beds.append('path').attr('d', arcFn as never);\n }\n\n private renderMissRing(\n board: BoardState,\n ring: Ring,\n segments: Segment[],\n outerRadius: number,\n innerRadius: number,\n ): void {\n const missArc = arc<PieArcDatum<Bed>>()\n .outerRadius(outerRadius)\n .innerRadius(innerRadius);\n\n const missBeds = board.svg\n .append('g')\n .classed('c-Dartboard-miss', true)\n .selectAll<SVGGElement, PieArcDatum<Bed>>('arc')\n .data(board.pie(addRingToSegments(ring, segments)))\n .enter()\n .append('g')\n .attr(\n 'class',\n (d: PieArcDatum<Bed>) =>\n `c-Dartboard-bed c-Dartboard-bed--${d.data.segment} c-Dartboard-miss--${d.data.segment}`,\n )\n .attr('role', 'button')\n .attr('tabindex', '0')\n .attr('aria-label', (d: PieArcDatum<Bed>) =>\n buildAriaLabel(d.data),\n )\n .on(\n 'pointerup',\n (_event: PointerEvent, d: PieArcDatum<Bed>) => {\n this.dispatchThrow(d.data);\n },\n )\n .on(\n 'keydown',\n (_event: KeyboardEvent, d: PieArcDatum<Bed>) => {\n if (_event.key === 'Enter' || _event.key === ' ') {\n _event.preventDefault();\n this.dispatchThrow(d.data);\n }\n },\n );\n\n missBeds.append('path').attr('d', missArc as never);\n\n const determineRotation = (bedData: Bed) =>\n -board.rotation + board.segmentWidth * ((bedData.position ?? 0) - 1);\n\n const determineX = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[0];\n\n const determineY = (d: PieArcDatum<Bed>) =>\n missArc.centroid(d)[1];\n\n missBeds\n .append('text')\n .classed('c-Dartboard-missLabel', true)\n .attr('x', (d: PieArcDatum<Bed>) => determineX(d))\n .attr('y', (d: PieArcDatum<Bed>) => determineY(d))\n .attr('dy', '.35em')\n .attr(\n 'transform',\n (d: PieArcDatum<Bed>) =>\n `rotate(${determineRotation(d.data)}, ${determineX(d)}, ${determineY(d)})`,\n )\n .attr('text-anchor', 'middle')\n .text((d: PieArcDatum<Bed>) => d.data.segment);\n }\n}\n","import type { DartboardOptions, Rings, Segment } from './types';\n\nexport const DEFAULT_OPTIONS: DartboardOptions = {\n size: null,\n padding: 0,\n missPercent: 10,\n doublePercent: 10,\n outerSinglePercent: 25,\n triplePercent: 10,\n innerSinglePercent: 30,\n singleBullPercent: 8,\n doubleBullPercent: 7,\n};\n\nexport const DEFAULT_RINGS: Rings = {\n MISS: { name: 'miss', abbr: 'M', multiplier: 0 },\n DOUBLE: { name: 'double', abbr: 'D', multiplier: 2 },\n OUTER_SINGLE: { name: 'outerSingle', abbr: 'S', multiplier: 1 },\n TRIPLE: { name: 'triple', abbr: 'T', multiplier: 3 },\n INNER_SINGLE: { name: 'innerSingle', abbr: 'S', multiplier: 1 },\n SINGLE_BULL: { name: 'singleBull', abbr: 'B', multiplier: 1 },\n DOUBLE_BULL: { name: 'doubleBull', abbr: 'DB', multiplier: 2 },\n};\n\nexport const MOBILE_OPTIONS: Partial<DartboardOptions> = {\n missPercent: 7,\n doublePercent: 14,\n outerSinglePercent: 21,\n triplePercent: 14,\n innerSinglePercent: 26,\n singleBullPercent: 9,\n doubleBullPercent: 9,\n};\n\nexport const DEFAULT_SEGMENTS: Segment[] = [\n { segment: 20, position: 1, color: 'Dark' },\n { segment: 1, position: 2, color: 'Light' },\n { segment: 18, position: 3, color: 'Dark' },\n { segment: 4, position: 4, color: 'Light' },\n { segment: 13, position: 5, color: 'Dark' },\n { segment: 6, position: 6, color: 'Light' },\n { segment: 10, position: 7, color: 'Dark' },\n { segment: 15, position: 8, color: 'Light' },\n { segment: 2, position: 9, color: 'Dark' },\n { segment: 17, position: 10, color: 'Light' },\n { segment: 3, position: 11, color: 'Dark' },\n { segment: 19, position: 12, color: 'Light' },\n { segment: 7, position: 13, color: 'Dark' },\n { segment: 16, position: 14, color: 'Light' },\n { segment: 8, position: 15, color: 'Dark' },\n { segment: 11, position: 16, color: 'Light' },\n { segment: 14, position: 17, color: 'Dark' },\n { segment: 9, position: 18, color: 'Light' },\n { segment: 12, position: 19, color: 'Dark' },\n { segment: 5, position: 20, color: 'Light' },\n];\n","import type { Ring, Rings, Segment, Bed, BedTarget, ThrowDetail } from './types';\n\nconst SCORING_RINGS: (keyof Rings)[] = [\n 'DOUBLE',\n 'TRIPLE',\n 'OUTER_SINGLE',\n 'INNER_SINGLE',\n 'SINGLE_BULL',\n 'DOUBLE_BULL',\n];\n\nexport function buildThrowDetail(bed: Bed): ThrowDetail {\n return {\n bed: bed.ring.abbr + bed.segment,\n segment: bed.segment,\n ring: bed.ring.name,\n score: bed.segment * bed.ring.multiplier,\n };\n}\n\nexport function asPercent(n: number): number {\n return parseFloat((n / 100).toFixed(2));\n}\n\nexport function addRingToSegments(ring: Ring, segments: Segment[]): Bed[] {\n return segments.map((segment) => ({ ...segment, ring }));\n}\n\nexport function parseBed(\n bed: string,\n rings: Rings,\n segments?: Segment[],\n): BedTarget[] {\n // 'miss' keyword — target all segments in the miss ring\n if (bed.toLowerCase() === 'miss') {\n if (!segments) {\n throw new Error(\n 'parseBed: segments are required to resolve the \"miss\" keyword',\n );\n }\n return segments.map((s) => ({ segment: s.segment, ring: 'MISS' as keyof Rings }));\n }\n\n // Number-only string — target all scoring rings on that segment\n const numOnly = bed.match(/^(\\d+)$/);\n if (numOnly) {\n const segment = parseInt(numOnly[1], 10);\n return SCORING_RINGS\n .filter((key) => key in rings)\n .map((ring) => ({ segment, ring }));\n }\n\n const match = bed.match(/^([A-Za-z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid bed format: \"${bed}\"`);\n }\n\n const [, abbr, numStr] = match.map((s, i) => i === 1 ? s.toUpperCase() : s);\n const segment = parseInt(numStr, 10);\n\n const targets: BedTarget[] = [];\n for (const [key, ring] of Object.entries(rings)) {\n if (ring.abbr === abbr) {\n targets.push({ segment, ring: key as keyof Rings });\n }\n }\n\n if (targets.length === 0) {\n throw new Error(`Unknown bed abbreviation: \"${abbr}\"`);\n }\n\n return targets;\n}\n"],"mappings":"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","names":["segment"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tungstenstudio/dartboard-input",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.2",
4
4
  "description": "Interactive SVG dartboard input component built with D3",
5
5
  "type": "module",
6
6
  "sideEffects": [