@spotlab/hand-matrix 0.3.0 → 0.5.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/README.md +50 -45
- package/dist/editor/cells.d.ts +11 -5
- package/dist/editor/matrix-editor.d.ts +5 -12
- package/dist/hand-matrix.d.ts +26 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +282 -270
- package/dist/range-matrix.d.ts +10 -0
- package/dist/range-to-matrix.d.ts +19 -0
- package/package.json +1 -1
- package/dist/range-grid.d.ts +0 -13
package/README.md
CHANGED
|
@@ -5,13 +5,13 @@ and [`@spotlab/range`](../range) — no Tailwind, no bundler-plugin
|
|
|
5
5
|
requirement.
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
|
-
import {
|
|
8
|
+
import { RangeMatrix, rangeToMatrix } from "@spotlab/hand-matrix";
|
|
9
9
|
import "@spotlab/hand-matrix/style.css";
|
|
10
10
|
import { initRange } from "@spotlab/range";
|
|
11
11
|
|
|
12
12
|
await initRange(); // once, at startup
|
|
13
13
|
|
|
14
|
-
<
|
|
14
|
+
<RangeMatrix {...rangeToMatrix("AKs:0.5,QQ")} />;
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## Exports
|
|
@@ -20,31 +20,33 @@ Everything below is exported from the package root.
|
|
|
20
20
|
|
|
21
21
|
### Display
|
|
22
22
|
|
|
23
|
-
- `
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- `className?: string
|
|
37
|
-
- `
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
`
|
|
41
|
-
to `
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
23
|
+
- `RangeMatrix` — the read-only grid, for one range or several actions at
|
|
24
|
+
once, drawn exactly as `RangeMatrixEditor` draws it but without painting.
|
|
25
|
+
Each cell stacks its actions' weights as colored bands, dead cells
|
|
26
|
+
(`avail` 0) are hatched, and capped cells (`avail` below 1) show a cap
|
|
27
|
+
line with the rest hatched. Each cell carries a `data-combo` attribute.
|
|
28
|
+
Props (`RangeMatrixProps`):
|
|
29
|
+
- `cells: EditorCell[]` — one per combo, in `@spotlab/range`'s `COMBOS`
|
|
30
|
+
order (see [Editing](#editing)).
|
|
31
|
+
- `actions: EditorActionSpec[]` — index-aligned with each cell's
|
|
32
|
+
`weights`.
|
|
33
|
+
- `order: number[]` — indices into `actions`, in the order bands stack.
|
|
34
|
+
An action left out isn't drawn, so its share of a cell stays
|
|
35
|
+
transparent; include it to give it a color.
|
|
36
|
+
- `className?: string`.
|
|
37
|
+
- `rangeToMatrix(range, { color?, labels? }): RangeMatrixProps` (without
|
|
38
|
+
`className`) — `RangeMatrix`'s props for drawing one range:
|
|
39
|
+
`<RangeMatrix {...rangeToMatrix(range)} />`. Takes a range string (parsed
|
|
40
|
+
via `@spotlab/range`) or the expanded `HandFrequency[]` form, and fills
|
|
41
|
+
each cell to its combo's mean weight in `color` (default
|
|
42
|
+
`var(--spotlab-hm-fill)`), leaving the rest blank. The returned `actions`
|
|
43
|
+
are `in` and `out`, labeled by `labels.in` (default `"In range"`) and
|
|
44
|
+
`labels.out` (default `"Out of range"`), for building your own legend.
|
|
45
|
+
Memoize the result (e.g. `useMemo`) rather than calling it on every
|
|
46
|
+
render.
|
|
47
|
+
|
|
48
|
+
`rangeToMatrix`'s parse and combo collapse (`toComboWeights`) are wasm
|
|
49
|
+
calls, so `initRange()` must have resolved before calling it — see
|
|
48
50
|
[`@spotlab/range`](../range)'s own README for why that call is explicit
|
|
49
51
|
rather than automatic.
|
|
50
52
|
|
|
@@ -55,9 +57,8 @@ raise). Its state is an array of 169 `EditorCell`s, one per combo in
|
|
|
55
57
|
`@spotlab/range`'s `COMBOS` order. Every component is fully controlled: state
|
|
56
58
|
goes in as props and changes come out through `on*Change` callbacks.
|
|
57
59
|
|
|
58
|
-
- `RangeMatrixEditor` — the paintable grid
|
|
59
|
-
|
|
60
|
-
wires brush/eyedropper painting onto `HandMatrix` for mouse and touch.
|
|
60
|
+
- `RangeMatrixEditor` — the paintable grid: `RangeMatrix`'s cells with
|
|
61
|
+
brush/eyedropper painting wired on for mouse and touch.
|
|
61
62
|
Props (`RangeMatrixEditorProps`):
|
|
62
63
|
- `cells: EditorCell[]` and `onCellsChange(cells)`.
|
|
63
64
|
- `actions: EditorActionSpec[]` — index-aligned with each cell's
|
|
@@ -85,9 +86,9 @@ goes in as props and changes come out through `on*Change` callbacks.
|
|
|
85
86
|
- `useRangePainting(opts)` — the brush/eyedropper state machine behind
|
|
86
87
|
`RangeMatrixEditor`, for building your own grid. `opts` takes the editor's
|
|
87
88
|
`cells`, `brush`, `tool` and their three `on*Change` callbacks. Returns
|
|
88
|
-
`{ onCellDown(combo), onCellEnter(combo) }
|
|
89
|
-
|
|
90
|
-
or `pointercancel`.
|
|
89
|
+
`{ onCellDown(combo), onCellEnter(combo) }`: call `onCellDown` when a
|
|
90
|
+
pointer goes down on a cell and `onCellEnter` each time it moves onto
|
|
91
|
+
another one. A stroke ends on any window `pointerup` or `pointercancel`.
|
|
91
92
|
- `seedCells(avail, actionWeights, passive): EditorCell[]` — build the
|
|
92
93
|
initial grid from a parent range's per-combo availability (`null` for
|
|
93
94
|
unconstrained) and each action's absolute per-combo weights (the
|
|
@@ -95,13 +96,16 @@ goes in as props and changes come out through `on*Change` callbacks.
|
|
|
95
96
|
produces).
|
|
96
97
|
- `cellsToComboWeights(cells, actionIndex): Map<string, number>` — collapse
|
|
97
98
|
one action back to absolute per-combo weights, ready to save as a range.
|
|
98
|
-
- `cellsToRanges(original, seed, cells): HandFrequency[][]` — turn
|
|
99
|
-
edited grid back into one hand-keyed range per action. `original`
|
|
100
|
-
each action's range (or `null`) in editor action order, `seed` the
|
|
101
|
-
the editor opened with, and `cells` the cells after editing.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
- `cellsToRanges(original, seed, cells, avail?): HandFrequency[][]` — turn
|
|
100
|
+
the edited grid back into one hand-keyed range per action. `original`
|
|
101
|
+
holds each action's range (or `null`) in editor action order, `seed` the
|
|
102
|
+
cells the editor opened with, and `cells` the cells after editing.
|
|
103
|
+
`avail` is the parent range per hand (`null` for unconstrained); leave it
|
|
104
|
+
out when the parent gives every hand of a combo the same weight. Combos
|
|
105
|
+
whose cell still matches its seed keep each action's original hands
|
|
106
|
+
verbatim, and a `null` action takes what's left of each hand there.
|
|
107
|
+
Changed combos are rebuilt from the cells. Either way, each hand's
|
|
108
|
+
actions sum to its parent weight.
|
|
105
109
|
- `comboWeightsToCells(cells, actionWeights, passive): EditorCell[]` — the
|
|
106
110
|
inverse: re-derive the cells' conditional weights from absolute
|
|
107
111
|
per-action ranges, keeping each cell's `avail`.
|
|
@@ -112,7 +116,7 @@ goes in as props and changes come out through `on*Change` callbacks.
|
|
|
112
116
|
is the combo's cap in the parent range and `weights` are each action's
|
|
113
117
|
share of it, summing to 100), `EditorActionSpec`
|
|
114
118
|
(`{ id: string; label: string; color: string }`), `PaintTool`,
|
|
115
|
-
`
|
|
119
|
+
`RangeMatrixEditorProps`, `ActionWeightSlidersProps`,
|
|
116
120
|
`WeightInputProps`.
|
|
117
121
|
|
|
118
122
|
**The editor works at combo level.** A cell is one of the 169 combos (`AKs`,
|
|
@@ -130,7 +134,7 @@ custom property has a default declared on `.spotlab-hm-root`, so the
|
|
|
130
134
|
component renders correctly with zero theming.
|
|
131
135
|
|
|
132
136
|
Because the `className` you pass to a component lands on that same root, a
|
|
133
|
-
class that sets variables works there too (`<
|
|
137
|
+
class that sets variables works there too (`<RangeMatrix className="my-theme" … />`
|
|
134
138
|
with `.my-theme { --spotlab-hm-border: … }`), in addition to the
|
|
135
139
|
`.spotlab-hm-root` selector form below.
|
|
136
140
|
|
|
@@ -192,9 +196,10 @@ Available variables: `--spotlab-hm-border`, `--spotlab-hm-border-width`,
|
|
|
192
196
|
`--spotlab-hm-muted-bg`, `--spotlab-hm-muted-fg`, `--spotlab-hm-track-bg`,
|
|
193
197
|
`--spotlab-hm-row-passive-bg`, `--spotlab-hm-dead-hatch`.
|
|
194
198
|
|
|
195
|
-
Action
|
|
196
|
-
they are data, passed as props.
|
|
197
|
-
when `
|
|
199
|
+
Action colors (each `EditorActionSpec`'s `color`, or `rangeToMatrix`'s
|
|
200
|
+
`color` option) are **not** theme variables — they are data, passed as props.
|
|
201
|
+
`--spotlab-hm-fill` is only the default `rangeToMatrix` uses when `color` is
|
|
202
|
+
omitted.
|
|
198
203
|
|
|
199
204
|
## License
|
|
200
205
|
|
package/dist/editor/cells.d.ts
CHANGED
|
@@ -31,17 +31,23 @@ export declare function comboWeightsToCells(cells: EditorCell[], actionWeights:
|
|
|
31
31
|
* Turn an edited grid back into one hand-keyed range per action, keeping each
|
|
32
32
|
* action's original hands wherever the editor didn't touch them. `original`
|
|
33
33
|
* holds each action's range in editor action order, `seed` the cells the
|
|
34
|
-
* editor opened with, and `cells` the cells after editing.
|
|
34
|
+
* editor opened with, and `cells` the cells after editing. `avail` is the
|
|
35
|
+
* parent range per hand, as passed (collapsed) to `seedCells`: `null` means
|
|
36
|
+
* unconstrained, and leaving it out takes each hand's weight from its cell's
|
|
37
|
+
* `avail`, which is exact whenever the parent gives every hand of a combo the
|
|
38
|
+
* same weight.
|
|
35
39
|
*
|
|
36
40
|
* A combo whose cell still equals its seed cell (same `avail`, same weights)
|
|
37
41
|
* keeps every action's original hands verbatim, so input the whole-percent grid
|
|
38
42
|
* can't represent — a single suit (`AhKh:0.7`) or a fractional weight
|
|
39
|
-
* (`QQ:0.333`) — survives a save.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
43
|
+
* (`QQ:0.333`) — survives a save. An action whose original is `null` (e.g. an
|
|
44
|
+
* implicit fold) takes what's left of each hand there: its parent weight minus
|
|
45
|
+
* the preserved originals, never below 0, split across `null` actions by their
|
|
46
|
+
* cell weights. A changed combo is rebuilt from its cell for every action, each
|
|
47
|
+
* hand getting the action's share of its own parent weight.
|
|
42
48
|
*
|
|
43
49
|
* Each rebuilt combo takes its first original hand's place, and combos the
|
|
44
50
|
* original didn't have follow in matrix order, so an unedited range formats
|
|
45
51
|
* back to the string it came from.
|
|
46
52
|
*/
|
|
47
|
-
export declare function cellsToRanges(original: (HandFrequency[] | null)[], seed: EditorCell[], cells: EditorCell[]): HandFrequency[][];
|
|
53
|
+
export declare function cellsToRanges(original: (HandFrequency[] | null)[], seed: EditorCell[], cells: EditorCell[], avail?: HandFrequency[] | null): HandFrequency[][];
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
+
import { MatrixDisplayProps } from '../hand-matrix';
|
|
2
3
|
import { PaintTool } from './use-range-painting';
|
|
3
4
|
import { EditorCell } from './cells';
|
|
4
|
-
|
|
5
|
-
export type RangeMatrixEditorProps = {
|
|
6
|
-
/** The 169-cell grid, in `@spotlab/range`'s `COMBOS` order. */
|
|
7
|
-
cells: EditorCell[];
|
|
8
|
-
/** Index-aligned with each cell's `weights` array. */
|
|
9
|
-
actions: EditorActionSpec[];
|
|
10
|
-
/** Indices into `actions`/`weights`, in the order bands should stack — a display concern the consumer owns (e.g. biggest raise first). */
|
|
11
|
-
order: number[];
|
|
5
|
+
export type RangeMatrixEditorProps = MatrixDisplayProps & {
|
|
12
6
|
brush: number[];
|
|
13
7
|
tool: PaintTool;
|
|
14
8
|
onCellsChange: (cells: EditorCell[]) => void;
|
|
15
9
|
onBrushChange: (brush: number[]) => void;
|
|
16
10
|
onToolChange: (tool: PaintTool) => void;
|
|
17
|
-
className?: string;
|
|
18
11
|
};
|
|
19
12
|
/**
|
|
20
|
-
* The paintable 13x13 range grid:
|
|
21
|
-
*
|
|
22
|
-
*
|
|
13
|
+
* The paintable 13x13 range grid: `RangeMatrix`'s cells with brush/eyedropper
|
|
14
|
+
* painting wired onto them. Fully controlled; `useRangePainting` drives the
|
|
15
|
+
* state changes.
|
|
23
16
|
*/
|
|
24
17
|
export declare const RangeMatrixEditor: FC<RangeMatrixEditorProps>;
|
package/dist/hand-matrix.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { CSSProperties, FC, PointerEvent as ReactPointerEvent } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
type ComboStyleProp = {
|
|
6
|
-
comboStyle?: (combo: string) => CSSProperties;
|
|
7
|
-
};
|
|
2
|
+
import { EditorCell } from './editor/cells';
|
|
3
|
+
import { EditorActionSpec } from './editor/weights';
|
|
4
|
+
type CellPointerHandler = (combo: string, event: ReactPointerEvent<HTMLDivElement>) => void;
|
|
8
5
|
type GridPointerHandlers = {
|
|
9
6
|
/**
|
|
10
7
|
* A pointer (mouse, pen or touch) went down on `combo`'s cell. The grid
|
|
@@ -22,12 +19,29 @@ type GridPointerHandlers = {
|
|
|
22
19
|
*/
|
|
23
20
|
onPointerEnter?: CellPointerHandler;
|
|
24
21
|
};
|
|
22
|
+
/** The cell data both `RangeMatrix` and `RangeMatrixEditor` draw from. */
|
|
23
|
+
export type MatrixDisplayProps = {
|
|
24
|
+
/** The 169-cell grid, in `@spotlab/range`'s `COMBOS` order. */
|
|
25
|
+
cells: EditorCell[];
|
|
26
|
+
/** Index-aligned with each cell's `weights` array. */
|
|
27
|
+
actions: EditorActionSpec[];
|
|
28
|
+
/**
|
|
29
|
+
* Indices into `actions`/`weights`, in the order bands should stack. An
|
|
30
|
+
* action left out isn't drawn, so its share of a cell stays transparent.
|
|
31
|
+
*/
|
|
32
|
+
order: number[];
|
|
33
|
+
className?: string;
|
|
34
|
+
};
|
|
25
35
|
/**
|
|
26
|
-
* The
|
|
27
|
-
*
|
|
28
|
-
*
|
|
36
|
+
* The 13x13 grid that `RangeMatrix` and `RangeMatrixEditor` both render, so
|
|
37
|
+
* the two draw cells identically: each cell stacks its actions' weights as
|
|
38
|
+
* bands in `order`, with dead and capped cells marked. Each cell carries a
|
|
39
|
+
* `data-combo` attribute. The editor adds a per-cell cursor and the painting
|
|
40
|
+
* handlers; passing `onPointerDown` also makes the grid a drag surface
|
|
41
|
+
* (`dragSurfaceStyle`), so a drag reaches the handlers instead of scrolling
|
|
42
|
+
* the page or selecting text. Internal: not exported from the package root.
|
|
29
43
|
*/
|
|
30
|
-
export declare const HandMatrix: FC<{
|
|
31
|
-
|
|
32
|
-
}
|
|
44
|
+
export declare const HandMatrix: FC<MatrixDisplayProps & GridPointerHandlers & {
|
|
45
|
+
cursorOf?: (cell: EditorCell) => CSSProperties["cursor"];
|
|
46
|
+
}>;
|
|
33
47
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { RangeMatrix, type RangeMatrixProps } from './range-matrix';
|
|
2
|
+
export { rangeToMatrix } from './range-to-matrix';
|
|
3
3
|
export { RangeMatrixEditor, type RangeMatrixEditorProps, } from './editor/matrix-editor';
|
|
4
4
|
export { ActionWeightSliders, type ActionWeightSlidersProps, type WeightInputProps, } from './editor/action-sliders';
|
|
5
5
|
export { useRangePainting, type PaintTool } from './editor/use-range-painting';
|
package/dist/index.js
CHANGED
|
@@ -1,356 +1,368 @@
|
|
|
1
|
-
import { useCallback as
|
|
2
|
-
import { COMBOS as
|
|
3
|
-
import { jsx as
|
|
4
|
-
var
|
|
5
|
-
const e = t.target;
|
|
6
|
-
e.hasPointerCapture(t.pointerId) && e.releasePointerCapture(t.pointerId);
|
|
7
|
-
}, $ = (t, e, n) => {
|
|
8
|
-
const r = t.ownerDocument.elementFromPoint(e, n)?.closest("[data-combo]");
|
|
9
|
-
return !r || !t.contains(r) ? null : r.getAttribute("data-combo");
|
|
10
|
-
}, B = ({ combo: t, onPointerDown: e, comboStyle: n }) => /* @__PURE__ */ p("div", {
|
|
11
|
-
className: "spotlab-hm-cell",
|
|
12
|
-
"data-combo": t,
|
|
13
|
-
style: n?.(t),
|
|
14
|
-
onPointerDown: e && ((r) => {
|
|
15
|
-
O(r), e(t, r);
|
|
16
|
-
}),
|
|
17
|
-
children: /* @__PURE__ */ p("div", {
|
|
18
|
-
className: "spotlab-hm-cell-inner",
|
|
19
|
-
children: /* @__PURE__ */ p("div", {
|
|
20
|
-
"data-combo": t,
|
|
21
|
-
children: t
|
|
22
|
-
})
|
|
23
|
-
})
|
|
24
|
-
}), F = ({ row: t, ...e }) => /* @__PURE__ */ p("div", {
|
|
25
|
-
className: "spotlab-hm-row",
|
|
26
|
-
children: t.map((n, r) => /* @__PURE__ */ p(B, {
|
|
27
|
-
combo: n,
|
|
28
|
-
...e
|
|
29
|
-
}, r))
|
|
30
|
-
}), X = {
|
|
31
|
-
touchAction: "none",
|
|
32
|
-
userSelect: "none",
|
|
33
|
-
WebkitUserSelect: "none",
|
|
34
|
-
WebkitTouchCallout: "none"
|
|
35
|
-
}, x = ({ className: t, onPointerDown: e, onPointerEnter: n, ...r }) => {
|
|
36
|
-
const a = b(null), o = (s) => {
|
|
37
|
-
const l = $(s.currentTarget, s.clientX, s.clientY);
|
|
38
|
-
l !== a.current && (a.current = l, l && n?.(l, s));
|
|
39
|
-
};
|
|
40
|
-
return /* @__PURE__ */ p("div", {
|
|
41
|
-
className: ["spotlab-hm-root", t].filter(Boolean).join(" "),
|
|
42
|
-
style: e ? X : void 0,
|
|
43
|
-
onPointerDown: n && ((s) => {
|
|
44
|
-
a.current = $(s.currentTarget, s.clientX, s.clientY);
|
|
45
|
-
}),
|
|
46
|
-
onPointerMove: n && o,
|
|
47
|
-
onPointerLeave: n && (() => a.current = null),
|
|
48
|
-
children: D(v, 13).map((s, l) => /* @__PURE__ */ p(F, {
|
|
49
|
-
row: s,
|
|
50
|
-
onPointerDown: e,
|
|
51
|
-
...r
|
|
52
|
-
}, l))
|
|
53
|
-
});
|
|
54
|
-
}, _ = (t, e) => ({ background: R([`${t} 0 ${e * 100}%`, `transparent ${e * 100}% 100%`]) }), rt = ({ range: t, fill: e = "var(--spotlab-hm-fill)", className: n }) => {
|
|
55
|
-
const r = I(() => {
|
|
56
|
-
const a = typeof t == "string" ? P(t) : t;
|
|
57
|
-
return W(a);
|
|
58
|
-
}, [t]);
|
|
59
|
-
return /* @__PURE__ */ p(x, {
|
|
60
|
-
className: n,
|
|
61
|
-
comboStyle: (a) => {
|
|
62
|
-
const o = r.get(a);
|
|
63
|
-
return o ? _(e, o) : {};
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}, j = (t) => Math.max(0, Math.min(100, Math.round(t))), q = (t, e) => {
|
|
1
|
+
import { useCallback as M, useEffect as R, useLayoutEffect as L, useRef as y } from "react";
|
|
2
|
+
import { COMBOS as C, comboOf as P, handsOfCombo as T, parseRange as W, toComboWeights as D } from "@spotlab/range";
|
|
3
|
+
import { jsx as v, jsxs as E } from "react/jsx-runtime";
|
|
4
|
+
var B = (t) => Math.max(0, Math.min(100, Math.round(t))), F = (t, r) => {
|
|
67
5
|
const n = t.map(Math.round);
|
|
68
|
-
let
|
|
69
|
-
if (
|
|
70
|
-
for (let a = 0; a < n.length; a++) if (a !==
|
|
71
|
-
n[a] +=
|
|
6
|
+
let e = 100 - n.reduce((a, o) => a + o, 0);
|
|
7
|
+
if (e !== 0) {
|
|
8
|
+
for (let a = 0; a < n.length; a++) if (a !== r && n[a] + e >= 0) {
|
|
9
|
+
n[a] += e, e = 0;
|
|
72
10
|
break;
|
|
73
11
|
}
|
|
74
|
-
if (
|
|
75
|
-
for (let a = 0; a < n.length; a++) if (a !==
|
|
76
|
-
const o = Math.min(n[a], -
|
|
77
|
-
if (n[a] -= o,
|
|
12
|
+
if (e !== 0) {
|
|
13
|
+
for (let a = 0; a < n.length; a++) if (a !== r && n[a] > 0) {
|
|
14
|
+
const o = Math.min(n[a], -e);
|
|
15
|
+
if (n[a] -= o, e += o, e === 0) break;
|
|
78
16
|
}
|
|
79
|
-
n[
|
|
17
|
+
n[r] = Math.max(0, n[r] + e);
|
|
80
18
|
}
|
|
81
19
|
}
|
|
82
20
|
return n;
|
|
83
|
-
},
|
|
84
|
-
const a =
|
|
85
|
-
o[
|
|
86
|
-
const
|
|
87
|
-
for (let
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
} else
|
|
94
|
-
return
|
|
95
|
-
},
|
|
96
|
-
const
|
|
97
|
-
return
|
|
98
|
-
},
|
|
21
|
+
}, X = (t, r, n, e) => {
|
|
22
|
+
const a = B(n), o = t.slice();
|
|
23
|
+
o[r] = a;
|
|
24
|
+
const c = 100 - a, i = [];
|
|
25
|
+
for (let l = 0; l < t.length; l++) l !== r && i.push(l);
|
|
26
|
+
const u = i.reduce((l, f) => l + t[f], 0);
|
|
27
|
+
if (u <= 0) {
|
|
28
|
+
i.forEach((f) => o[f] = 0);
|
|
29
|
+
const l = r === e ? i[0] : e;
|
|
30
|
+
l != null && (o[l] = c);
|
|
31
|
+
} else i.forEach((l) => o[l] = Math.round(t[l] / u * c));
|
|
32
|
+
return F(o, r);
|
|
33
|
+
}, N = (t, r) => t.reduce((n, e, a) => a === r ? n : n + e, 0), k = new Map(C.map((t, r) => [t, r])), j = (t, r, n) => {
|
|
34
|
+
const e = t.slice();
|
|
35
|
+
return e[k.get(r)] = n, e;
|
|
36
|
+
}, I = (t, r) => {
|
|
99
37
|
const n = t.slice();
|
|
100
|
-
let
|
|
101
|
-
if (
|
|
102
|
-
const a = 100 /
|
|
103
|
-
for (let o = 0; o < n.length; o++) o !==
|
|
104
|
-
|
|
38
|
+
let e = N(n, r);
|
|
39
|
+
if (e > 100) {
|
|
40
|
+
const a = 100 / e;
|
|
41
|
+
for (let o = 0; o < n.length; o++) o !== r && (n[o] = Math.round(n[o] * a));
|
|
42
|
+
e = N(n, r);
|
|
105
43
|
}
|
|
106
|
-
return n[
|
|
44
|
+
return n[r] = Math.max(0, 100 - e), n;
|
|
107
45
|
};
|
|
108
|
-
function
|
|
109
|
-
return
|
|
110
|
-
const a = t ? t.get(
|
|
46
|
+
function et(t, r, n) {
|
|
47
|
+
return C.map((e) => {
|
|
48
|
+
const a = t ? t.get(e) ?? 0 : 1, o = r.map(() => 0);
|
|
111
49
|
return a <= 0 ? (o[n] = 100, {
|
|
112
50
|
avail: 0,
|
|
113
51
|
weights: o
|
|
114
|
-
}) : (
|
|
115
|
-
const
|
|
116
|
-
o[
|
|
52
|
+
}) : (r.forEach((c, i) => {
|
|
53
|
+
const u = c?.get(e) ?? 0;
|
|
54
|
+
o[i] = Math.round(u / a * 100);
|
|
117
55
|
}), {
|
|
118
56
|
avail: a,
|
|
119
|
-
weights:
|
|
57
|
+
weights: I(o, n)
|
|
120
58
|
});
|
|
121
59
|
});
|
|
122
60
|
}
|
|
123
|
-
var
|
|
124
|
-
function
|
|
61
|
+
var S = 8;
|
|
62
|
+
function rt(t, r) {
|
|
125
63
|
const n = /* @__PURE__ */ new Map();
|
|
126
|
-
return t.forEach((
|
|
127
|
-
if (
|
|
128
|
-
const o =
|
|
64
|
+
return t.forEach((e, a) => {
|
|
65
|
+
if (e.avail <= 0) return;
|
|
66
|
+
const o = e.weights.reduce((i, u) => i + u, 0);
|
|
129
67
|
if (!o) return;
|
|
130
|
-
const
|
|
131
|
-
|
|
68
|
+
const c = Number((e.weights[r] / o * e.avail).toFixed(S));
|
|
69
|
+
c && n.set(C[a], c);
|
|
132
70
|
}), n;
|
|
133
71
|
}
|
|
134
|
-
function
|
|
135
|
-
return t.map((
|
|
136
|
-
const o =
|
|
137
|
-
if (
|
|
72
|
+
function nt(t, r, n) {
|
|
73
|
+
return t.map((e, a) => {
|
|
74
|
+
const o = r.map(() => 0);
|
|
75
|
+
if (e.avail <= 0)
|
|
138
76
|
return o[n] = 100, {
|
|
139
|
-
avail:
|
|
77
|
+
avail: e.avail,
|
|
140
78
|
weights: o
|
|
141
79
|
};
|
|
142
|
-
const
|
|
143
|
-
return
|
|
144
|
-
const
|
|
145
|
-
o[
|
|
80
|
+
const c = C[a];
|
|
81
|
+
return r.forEach((i, u) => {
|
|
82
|
+
const l = i?.get(c) ?? 0;
|
|
83
|
+
o[u] = Math.round(l / e.avail * 100);
|
|
146
84
|
}), {
|
|
147
|
-
avail:
|
|
148
|
-
weights:
|
|
85
|
+
avail: e.avail,
|
|
86
|
+
weights: I(o, n)
|
|
149
87
|
};
|
|
150
88
|
});
|
|
151
89
|
}
|
|
152
|
-
var
|
|
153
|
-
function
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
90
|
+
var q = (t, r) => t.avail !== r.avail || t.weights.length !== r.weights.length || t.weights.some((n, e) => n !== r.weights[e]);
|
|
91
|
+
function at(t, r, n, e) {
|
|
92
|
+
const a = e && new Map(e.map(({ hand: s, frequency: h }) => [s, h])), o = (s, h) => e === void 0 ? h.avail : a ? a.get(s) ?? 0 : 1, c = t.map((s) => s && new Map(s.map(({ hand: h, frequency: g }) => [h, g]))), i = (s) => c.reduce((h, g) => h + (g?.get(s) ?? 0), 0), u = t.flatMap((s, h) => s ? [] : [h]), l = (s, h) => T(s).flatMap((g) => {
|
|
93
|
+
const b = Number(h(g).toFixed(S));
|
|
94
|
+
return b > 0 ? [{
|
|
95
|
+
hand: g,
|
|
96
|
+
frequency: b
|
|
97
|
+
}] : [];
|
|
98
|
+
}), f = (s, h) => {
|
|
99
|
+
const g = n[k.get(s)], b = g.weights.reduce((m, w) => m + w, 0);
|
|
100
|
+
return g.avail <= 0 || !b ? [] : l(s, (m) => g.weights[h] / b * o(m, g));
|
|
101
|
+
}, p = (s, h) => {
|
|
102
|
+
const g = n[k.get(s)], b = u.reduce((w, O) => w + g.weights[O], 0), m = b ? g.weights[h] / b : 1 / u.length;
|
|
103
|
+
return l(s, (w) => Math.max(0, o(w, g) - i(w)) * m);
|
|
104
|
+
}, d = new Set(C.filter((s, h) => q(r[h], n[h])));
|
|
105
|
+
return t.map((s, h) => {
|
|
106
|
+
if (s === null) return C.flatMap((m) => d.has(m) ? f(m, h) : p(m, h));
|
|
107
|
+
const g = [], b = /* @__PURE__ */ new Set();
|
|
108
|
+
for (const m of s) {
|
|
109
|
+
const w = P(m.hand);
|
|
110
|
+
d.has(w) ? b.has(w) || (b.add(w), g.push(...f(w, h))) : g.push(m);
|
|
165
111
|
}
|
|
166
|
-
for (const
|
|
167
|
-
return
|
|
112
|
+
for (const m of d) b.has(m) || g.push(...f(m, h));
|
|
113
|
+
return g;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
var _ = (t, r) => Array.from({ length: Math.ceil(t.length / r) }, (n, e) => t.slice(e * r, e * r + r)), U = (t) => `linear-gradient(to right, ${t.join(", ")})`, $ = (t, r, n) => {
|
|
117
|
+
const e = [];
|
|
118
|
+
let a = 0;
|
|
119
|
+
return n.forEach((o) => {
|
|
120
|
+
const c = (t.weights[o] || 0) / 100;
|
|
121
|
+
if (c <= 0) return;
|
|
122
|
+
const i = r[o].color;
|
|
123
|
+
e.push(`${i} ${a * 100}%`), e.push(`${i} ${(a + c) * 100}%`), a += c;
|
|
124
|
+
}), e.length > 0 && a < 1 - 1e-9 && e.push(`transparent ${a * 100}% 100%`), e.length > 0 ? U(e) : "none";
|
|
125
|
+
}, Y = (t, r, n) => {
|
|
126
|
+
if (t.avail <= 0) return {
|
|
127
|
+
backgroundImage: "var(--spotlab-hm-dead-hatch)",
|
|
128
|
+
backgroundColor: "var(--spotlab-hm-muted-bg)",
|
|
129
|
+
color: "var(--spotlab-hm-muted-fg)"
|
|
130
|
+
};
|
|
131
|
+
if (t.avail < 1) {
|
|
132
|
+
const e = `${t.avail * 100}%`;
|
|
133
|
+
return {
|
|
134
|
+
backgroundImage: `repeating-linear-gradient(180deg, var(--spotlab-hm-muted-fg) 0 4px, transparent 4px 8px), var(--spotlab-hm-dead-hatch), ${$(t, r, n)}`,
|
|
135
|
+
backgroundSize: `1px 100%, ${(1 - t.avail) * 100}% 100%, ${t.avail * 100}% 100%`,
|
|
136
|
+
backgroundPosition: `${e} center, right center, left center`,
|
|
137
|
+
backgroundRepeat: "no-repeat, no-repeat, no-repeat"
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return { backgroundImage: $(t, r, n) };
|
|
141
|
+
}, G = (t) => {
|
|
142
|
+
const r = t.target;
|
|
143
|
+
r.hasPointerCapture(t.pointerId) && r.releasePointerCapture(t.pointerId);
|
|
144
|
+
}, x = (t, r, n) => {
|
|
145
|
+
const e = t.ownerDocument.elementFromPoint(r, n)?.closest("[data-combo]");
|
|
146
|
+
return !e || !t.contains(e) ? null : e.getAttribute("data-combo");
|
|
147
|
+
}, H = {
|
|
148
|
+
touchAction: "none",
|
|
149
|
+
userSelect: "none",
|
|
150
|
+
WebkitUserSelect: "none",
|
|
151
|
+
WebkitTouchCallout: "none"
|
|
152
|
+
}, A = ({ cells: t, actions: r, order: n, className: e, cursorOf: a, onPointerDown: o, onPointerEnter: c }) => {
|
|
153
|
+
const i = y(null), u = (l) => {
|
|
154
|
+
const f = x(l.currentTarget, l.clientX, l.clientY);
|
|
155
|
+
f !== i.current && (i.current = f, f && c?.(f, l));
|
|
156
|
+
};
|
|
157
|
+
return /* @__PURE__ */ v("div", {
|
|
158
|
+
className: ["spotlab-hm-root", e].filter(Boolean).join(" "),
|
|
159
|
+
style: o ? H : void 0,
|
|
160
|
+
onPointerDown: c && ((l) => {
|
|
161
|
+
i.current = x(l.currentTarget, l.clientX, l.clientY);
|
|
162
|
+
}),
|
|
163
|
+
onPointerMove: c && u,
|
|
164
|
+
onPointerLeave: c && (() => i.current = null),
|
|
165
|
+
children: _(C, 13).map((l, f) => /* @__PURE__ */ v("div", {
|
|
166
|
+
className: "spotlab-hm-row",
|
|
167
|
+
children: l.map((p) => {
|
|
168
|
+
const d = t[k.get(p)];
|
|
169
|
+
return /* @__PURE__ */ v("div", {
|
|
170
|
+
className: "spotlab-hm-cell",
|
|
171
|
+
"data-combo": p,
|
|
172
|
+
style: {
|
|
173
|
+
...Y(d, r, n),
|
|
174
|
+
cursor: a?.(d)
|
|
175
|
+
},
|
|
176
|
+
onPointerDown: o && ((s) => {
|
|
177
|
+
G(s), o(p, s);
|
|
178
|
+
}),
|
|
179
|
+
children: /* @__PURE__ */ v("div", {
|
|
180
|
+
className: "spotlab-hm-cell-inner",
|
|
181
|
+
children: /* @__PURE__ */ v("div", {
|
|
182
|
+
"data-combo": p,
|
|
183
|
+
children: p
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
}, p);
|
|
187
|
+
})
|
|
188
|
+
}, f))
|
|
168
189
|
});
|
|
190
|
+
}, ot = A;
|
|
191
|
+
function lt(t, { color: r = "var(--spotlab-hm-fill)", labels: n = {} } = {}) {
|
|
192
|
+
const e = D(typeof t == "string" ? W(t) : t);
|
|
193
|
+
return {
|
|
194
|
+
cells: C.map((a) => {
|
|
195
|
+
const o = (e.get(a) ?? 0) * 100;
|
|
196
|
+
return {
|
|
197
|
+
avail: 1,
|
|
198
|
+
weights: [o, 100 - o]
|
|
199
|
+
};
|
|
200
|
+
}),
|
|
201
|
+
actions: [{
|
|
202
|
+
id: "in",
|
|
203
|
+
label: n.in ?? "In range",
|
|
204
|
+
color: r
|
|
205
|
+
}, {
|
|
206
|
+
id: "out",
|
|
207
|
+
label: n.out ?? "Out of range",
|
|
208
|
+
color: "transparent"
|
|
209
|
+
}],
|
|
210
|
+
order: [0]
|
|
211
|
+
};
|
|
169
212
|
}
|
|
170
|
-
function
|
|
171
|
-
const { cells:
|
|
172
|
-
|
|
213
|
+
function Q(t) {
|
|
214
|
+
const { cells: r, brush: n, tool: e, onCellsChange: a, onBrushChange: o, onToolChange: c } = t, i = y(null), u = M(() => {
|
|
215
|
+
i.current?.abort(), i.current = null;
|
|
173
216
|
}, []);
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}, [
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
if (
|
|
182
|
-
const
|
|
183
|
-
avail:
|
|
217
|
+
R(() => u, [u]);
|
|
218
|
+
const l = y(r);
|
|
219
|
+
L(() => {
|
|
220
|
+
l.current = r;
|
|
221
|
+
}, [r]);
|
|
222
|
+
const f = M((d) => {
|
|
223
|
+
const s = l.current, { avail: h } = s[k.get(d)];
|
|
224
|
+
if (h <= 0) return;
|
|
225
|
+
const g = j(s, d, {
|
|
226
|
+
avail: h,
|
|
184
227
|
weights: [...n]
|
|
185
228
|
});
|
|
186
|
-
|
|
187
|
-
}, [n, a]),
|
|
188
|
-
const
|
|
189
|
-
|
|
229
|
+
l.current = g, a(g);
|
|
230
|
+
}, [n, a]), p = M((d) => {
|
|
231
|
+
const s = k.get(d);
|
|
232
|
+
r[s].avail <= 0 || (o([...r[s].weights]), c("brush"));
|
|
190
233
|
}, [
|
|
191
|
-
|
|
234
|
+
r,
|
|
192
235
|
o,
|
|
193
|
-
|
|
236
|
+
c
|
|
194
237
|
]);
|
|
195
238
|
return {
|
|
196
|
-
onCellDown:
|
|
197
|
-
if (
|
|
198
|
-
|
|
239
|
+
onCellDown: M((d) => {
|
|
240
|
+
if (e === "eyedropper") {
|
|
241
|
+
p(d);
|
|
199
242
|
return;
|
|
200
243
|
}
|
|
201
|
-
|
|
202
|
-
const
|
|
203
|
-
|
|
244
|
+
u();
|
|
245
|
+
const s = new AbortController();
|
|
246
|
+
i.current = s, window.addEventListener("pointerup", u, { signal: s.signal }), window.addEventListener("pointercancel", u, { signal: s.signal }), f(d);
|
|
204
247
|
}, [
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
248
|
+
e,
|
|
249
|
+
p,
|
|
250
|
+
f,
|
|
251
|
+
u
|
|
209
252
|
]),
|
|
210
|
-
onCellEnter:
|
|
211
|
-
|
|
212
|
-
}, [
|
|
253
|
+
onCellEnter: M((d) => {
|
|
254
|
+
i.current && e === "brush" && f(d);
|
|
255
|
+
}, [e, f])
|
|
213
256
|
};
|
|
214
257
|
}
|
|
215
|
-
var
|
|
216
|
-
const
|
|
217
|
-
let a = 0;
|
|
218
|
-
return n.forEach((o) => {
|
|
219
|
-
const s = (t.weights[o] || 0) / 100;
|
|
220
|
-
if (s <= 0) return;
|
|
221
|
-
const l = e[o].color;
|
|
222
|
-
r.push(`${l} ${a * 100}%`), r.push(`${l} ${(a + s) * 100}%`), a += s;
|
|
223
|
-
}), r.length > 0 && a < 1 - 1e-9 && r.push(`transparent ${a * 100}% 100%`), R(r);
|
|
224
|
-
}, lt = ({ cells: t, actions: e, order: n, brush: r, tool: a, onCellsChange: o, onBrushChange: s, onToolChange: l, className: c }) => {
|
|
225
|
-
const { onCellDown: i, onCellEnter: d } = J({
|
|
258
|
+
var st = ({ cells: t, actions: r, order: n, brush: e, tool: a, onCellsChange: o, onBrushChange: c, onToolChange: i, className: u }) => {
|
|
259
|
+
const { onCellDown: l, onCellEnter: f } = Q({
|
|
226
260
|
cells: t,
|
|
227
|
-
brush:
|
|
261
|
+
brush: e,
|
|
228
262
|
tool: a,
|
|
229
263
|
onCellsChange: o,
|
|
230
|
-
onBrushChange:
|
|
231
|
-
onToolChange:
|
|
264
|
+
onBrushChange: c,
|
|
265
|
+
onToolChange: i
|
|
232
266
|
});
|
|
233
|
-
return /* @__PURE__ */
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
color: "var(--spotlab-hm-muted-fg)"
|
|
242
|
-
};
|
|
243
|
-
const f = a === "eyedropper" ? "copy" : "pointer";
|
|
244
|
-
if (u.avail < 1) {
|
|
245
|
-
const m = `${u.avail * 100}%`;
|
|
246
|
-
return {
|
|
247
|
-
background: `repeating-linear-gradient(180deg, var(--spotlab-hm-muted-fg) 0 4px, transparent 4px 8px), var(--spotlab-hm-dead-hatch), ${y(u, e, n)}`,
|
|
248
|
-
backgroundSize: `1px 100%, ${(1 - u.avail) * 100}% 100%, ${u.avail * 100}% 100%`,
|
|
249
|
-
backgroundPosition: `${m} center, right center, left center`,
|
|
250
|
-
backgroundRepeat: "no-repeat, no-repeat, no-repeat",
|
|
251
|
-
cursor: f
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
return {
|
|
255
|
-
background: y(u, e, n),
|
|
256
|
-
cursor: f
|
|
257
|
-
};
|
|
258
|
-
},
|
|
259
|
-
onPointerDown: i,
|
|
260
|
-
onPointerEnter: d
|
|
267
|
+
return /* @__PURE__ */ v(A, {
|
|
268
|
+
cells: t,
|
|
269
|
+
actions: r,
|
|
270
|
+
order: n,
|
|
271
|
+
className: u,
|
|
272
|
+
cursorOf: (p) => p.avail <= 0 ? "not-allowed" : a === "eyedropper" ? "copy" : "pointer",
|
|
273
|
+
onPointerDown: l,
|
|
274
|
+
onPointerEnter: f
|
|
261
275
|
});
|
|
262
|
-
},
|
|
276
|
+
}, J = (t) => /* @__PURE__ */ v("input", {
|
|
263
277
|
type: "number",
|
|
264
278
|
className: "spotlab-hm-weight-input",
|
|
265
279
|
...t
|
|
266
|
-
}),
|
|
267
|
-
const a =
|
|
268
|
-
const
|
|
269
|
-
if (!
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
}, [
|
|
273
|
-
return
|
|
274
|
-
const
|
|
275
|
-
o.current &&
|
|
276
|
-
},
|
|
277
|
-
return window.addEventListener("pointermove",
|
|
278
|
-
window.removeEventListener("pointermove",
|
|
280
|
+
}), K = ({ value: t, color: r, passive: n, onChange: e }) => {
|
|
281
|
+
const a = y(null), o = y(!1), c = M((i) => {
|
|
282
|
+
const u = a.current;
|
|
283
|
+
if (!u) return;
|
|
284
|
+
const l = u.getBoundingClientRect();
|
|
285
|
+
e((i - l.left) / l.width * 100);
|
|
286
|
+
}, [e]);
|
|
287
|
+
return R(() => {
|
|
288
|
+
const i = (l) => {
|
|
289
|
+
o.current && c(l.clientX);
|
|
290
|
+
}, u = () => o.current = !1;
|
|
291
|
+
return window.addEventListener("pointermove", i), window.addEventListener("pointerup", u), () => {
|
|
292
|
+
window.removeEventListener("pointermove", i), window.removeEventListener("pointerup", u);
|
|
279
293
|
};
|
|
280
|
-
}, [
|
|
294
|
+
}, [c]), /* @__PURE__ */ v("div", {
|
|
281
295
|
ref: a,
|
|
282
296
|
role: "slider",
|
|
283
297
|
"aria-valuenow": t,
|
|
284
298
|
"aria-valuemin": 0,
|
|
285
299
|
"aria-valuemax": 100,
|
|
286
300
|
className: "spotlab-hm-slider-track",
|
|
287
|
-
style: { background: `linear-gradient(to right, ${
|
|
288
|
-
onPointerDown: (
|
|
289
|
-
o.current = !0,
|
|
301
|
+
style: { background: `linear-gradient(to right, ${r} 0 ${t}%, var(--spotlab-hm-track-bg) ${t}% 100%)` },
|
|
302
|
+
onPointerDown: (i) => {
|
|
303
|
+
o.current = !0, c(i.clientX);
|
|
290
304
|
},
|
|
291
|
-
children: /* @__PURE__ */
|
|
305
|
+
children: /* @__PURE__ */ v("div", {
|
|
292
306
|
className: "spotlab-hm-slider-thumb",
|
|
293
307
|
style: {
|
|
294
308
|
left: `${t}%`,
|
|
295
|
-
border: `2px solid ${n ? "var(--spotlab-hm-muted-fg)" :
|
|
309
|
+
border: `2px solid ${n ? "var(--spotlab-hm-muted-fg)" : r}`
|
|
296
310
|
}
|
|
297
311
|
})
|
|
298
312
|
});
|
|
299
|
-
},
|
|
313
|
+
}, V = (t, r) => /* @__PURE__ */ E("span", {
|
|
300
314
|
className: "spotlab-hm-slider-label",
|
|
301
|
-
children: [t.label,
|
|
315
|
+
children: [t.label, r && /* @__PURE__ */ v("span", {
|
|
302
316
|
className: "spotlab-hm-slider-remainder",
|
|
303
317
|
children: " · remainder"
|
|
304
318
|
})]
|
|
305
|
-
}),
|
|
306
|
-
const
|
|
307
|
-
a(
|
|
319
|
+
}), it = ({ actions: t, order: r, weights: n, passive: e, onWeightsChange: a, renderActionLabel: o, renderActionExtra: c, components: i, className: u }) => {
|
|
320
|
+
const l = i?.WeightInput ?? J, f = (p, d) => {
|
|
321
|
+
a(X(n, p, d, e));
|
|
308
322
|
};
|
|
309
|
-
return /* @__PURE__ */
|
|
310
|
-
className: ["spotlab-hm-root spotlab-hm-sliders",
|
|
311
|
-
children:
|
|
312
|
-
const
|
|
313
|
-
return /* @__PURE__ */
|
|
323
|
+
return /* @__PURE__ */ v("div", {
|
|
324
|
+
className: ["spotlab-hm-root spotlab-hm-sliders", u].filter(Boolean).join(" "),
|
|
325
|
+
children: r.map((p) => {
|
|
326
|
+
const d = t[p], s = p === e;
|
|
327
|
+
return /* @__PURE__ */ E("div", {
|
|
314
328
|
className: "spotlab-hm-slider-row",
|
|
315
|
-
"data-passive":
|
|
316
|
-
children: [/* @__PURE__ */
|
|
329
|
+
"data-passive": s,
|
|
330
|
+
children: [/* @__PURE__ */ E("div", {
|
|
317
331
|
className: "spotlab-hm-slider-header",
|
|
318
332
|
children: [
|
|
319
|
-
/* @__PURE__ */
|
|
333
|
+
/* @__PURE__ */ v("span", {
|
|
320
334
|
className: "spotlab-hm-slider-swatch",
|
|
321
|
-
style: { background:
|
|
335
|
+
style: { background: d.color }
|
|
322
336
|
}),
|
|
323
|
-
o?.(
|
|
324
|
-
|
|
337
|
+
o?.(d, p, s) ?? V(d, s),
|
|
338
|
+
c?.(d, p)
|
|
325
339
|
]
|
|
326
|
-
}), /* @__PURE__ */
|
|
340
|
+
}), /* @__PURE__ */ E("div", {
|
|
327
341
|
className: "spotlab-hm-slider-track-row",
|
|
328
|
-
children: [/* @__PURE__ */
|
|
329
|
-
value: n[
|
|
330
|
-
color:
|
|
331
|
-
passive:
|
|
332
|
-
onChange: (
|
|
333
|
-
}), /* @__PURE__ */
|
|
334
|
-
value: n[
|
|
335
|
-
"aria-label": `${
|
|
336
|
-
onChange: (
|
|
342
|
+
children: [/* @__PURE__ */ v(K, {
|
|
343
|
+
value: n[p],
|
|
344
|
+
color: d.color,
|
|
345
|
+
passive: s,
|
|
346
|
+
onChange: (h) => f(p, h)
|
|
347
|
+
}), /* @__PURE__ */ v(l, {
|
|
348
|
+
value: n[p],
|
|
349
|
+
"aria-label": `${d.label} weight`,
|
|
350
|
+
onChange: (h) => f(p, parseInt(h.target.value || "0", 10))
|
|
337
351
|
})]
|
|
338
352
|
})]
|
|
339
|
-
},
|
|
353
|
+
}, d.id);
|
|
340
354
|
})
|
|
341
355
|
});
|
|
342
356
|
};
|
|
343
357
|
export {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
rt as
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
nt as seedCells,
|
|
355
|
-
J as useRangePainting
|
|
358
|
+
it as ActionWeightSliders,
|
|
359
|
+
ot as RangeMatrix,
|
|
360
|
+
st as RangeMatrixEditor,
|
|
361
|
+
rt as cellsToComboWeights,
|
|
362
|
+
at as cellsToRanges,
|
|
363
|
+
nt as comboWeightsToCells,
|
|
364
|
+
lt as rangeToMatrix,
|
|
365
|
+
X as rebalance,
|
|
366
|
+
et as seedCells,
|
|
367
|
+
Q as useRangePainting
|
|
356
368
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { MatrixDisplayProps } from './hand-matrix';
|
|
3
|
+
export type RangeMatrixProps = MatrixDisplayProps;
|
|
4
|
+
/**
|
|
5
|
+
* A read-only 13x13 grid of several actions at once: each cell stacks its
|
|
6
|
+
* actions' weights as colored bands in `order`, hatches dead cells (`avail`
|
|
7
|
+
* 0), and marks capped cells (`avail` below 1) with a cap line and hatched
|
|
8
|
+
* remainder. Draws exactly what `RangeMatrixEditor` does, without painting.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RangeMatrix: FC<RangeMatrixProps>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { HandFrequency } from '@spotlab/range';
|
|
2
|
+
import { RangeMatrixProps } from './range-matrix';
|
|
3
|
+
/**
|
|
4
|
+
* `RangeMatrix`'s props for drawing one range: every cell is fully available
|
|
5
|
+
* and filled to its combo's mean weight in `color` (default
|
|
6
|
+
* `var(--spotlab-hm-fill)`), with the rest left blank. The two actions are
|
|
7
|
+
* `in` and `out`, labeled `labels.in` (default "In range") and `labels.out`
|
|
8
|
+
* (default "Out of range") for a legend of your own. Takes a range string or
|
|
9
|
+
* its expanded hand-keyed form; a string is parsed via `@spotlab/range`, so
|
|
10
|
+
* `initRange()` must have resolved. Parsing and collapsing are wasm calls, so
|
|
11
|
+
* memoize the result rather than calling this on every render.
|
|
12
|
+
*/
|
|
13
|
+
export declare function rangeToMatrix(range: HandFrequency[] | string, { color, labels, }?: {
|
|
14
|
+
color?: string;
|
|
15
|
+
labels?: {
|
|
16
|
+
in?: string;
|
|
17
|
+
out?: string;
|
|
18
|
+
};
|
|
19
|
+
}): Omit<RangeMatrixProps, "className">;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spotlab/hand-matrix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A 13x13 poker hand-matrix React component: the read-only grid primitive and a range-string-aware display component, themed through CSS custom properties.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/dist/range-grid.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
2
|
-
import { HandFrequency } from '@spotlab/range';
|
|
3
|
-
/**
|
|
4
|
-
* A read-only 13x13 range grid: each cell fills to its combo's mean weight.
|
|
5
|
-
* Accepts the expanded hand-keyed form or a range string directly — a range
|
|
6
|
-
* string is parsed via `@spotlab/range`, so the caller never needs to touch
|
|
7
|
-
* the parser itself to render one.
|
|
8
|
-
*/
|
|
9
|
-
export declare const RangeGrid: FC<{
|
|
10
|
-
range: HandFrequency[] | string;
|
|
11
|
-
fill?: string;
|
|
12
|
-
className?: string;
|
|
13
|
-
}>;
|