@spotlab/hand-matrix 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/dist/editor/cells.d.ts +27 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +193 -163
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -95,6 +95,16 @@ goes in as props and changes come out through `on*Change` callbacks.
|
|
|
95
95
|
produces).
|
|
96
96
|
- `cellsToComboWeights(cells, actionIndex): Map<string, number>` — collapse
|
|
97
97
|
one action back to absolute per-combo weights, ready to save as a range.
|
|
98
|
+
- `cellsToRanges(original, seed, cells, avail?): HandFrequency[][]` — turn
|
|
99
|
+
the edited grid back into one hand-keyed range per action. `original`
|
|
100
|
+
holds each action's range (or `null`) in editor action order, `seed` the
|
|
101
|
+
cells the editor opened with, and `cells` the cells after editing.
|
|
102
|
+
`avail` is the parent range per hand (`null` for unconstrained); leave it
|
|
103
|
+
out when the parent gives every hand of a combo the same weight. Combos
|
|
104
|
+
whose cell still matches its seed keep each action's original hands
|
|
105
|
+
verbatim, and a `null` action takes what's left of each hand there.
|
|
106
|
+
Changed combos are rebuilt from the cells. Either way, each hand's
|
|
107
|
+
actions sum to its parent weight.
|
|
98
108
|
- `comboWeightsToCells(cells, actionWeights, passive): EditorCell[]` — the
|
|
99
109
|
inverse: re-derive the cells' conditional weights from absolute
|
|
100
110
|
per-action ranges, keeping each cell's `avail`.
|
|
@@ -109,10 +119,10 @@ goes in as props and changes come out through `on*Change` callbacks.
|
|
|
109
119
|
`WeightInputProps`.
|
|
110
120
|
|
|
111
121
|
**The editor works at combo level.** A cell is one of the 169 combos (`AKs`,
|
|
112
|
-
`AKo`, `QQ`), so suit-specific hands such as
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
`AKo`, `QQ`) at a whole-percent weight, so suit-specific hands such as
|
|
123
|
+
`AsKd:0.7` and fractional weights such as `QQ:0.333` can't be shown exactly:
|
|
124
|
+
`seedCells` takes combo weights, and `cellsToComboWeights` returns them. Save
|
|
125
|
+
with `cellsToRanges` to keep them for every combo the user didn't repaint.
|
|
116
126
|
|
|
117
127
|
## Theming
|
|
118
128
|
|
package/dist/editor/cells.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { HandFrequency } from '@spotlab/range';
|
|
1
2
|
export declare const COMBO_INDEX: Map<string, number>;
|
|
2
3
|
/**
|
|
3
4
|
* One matrix cell's painted state: `avail` is the combo's cap (its weight in the
|
|
@@ -8,6 +9,8 @@ export type EditorCell = {
|
|
|
8
9
|
avail: number;
|
|
9
10
|
weights: number[];
|
|
10
11
|
};
|
|
12
|
+
/** A copy of `cells` with `combo`'s cell replaced by `cell`. */
|
|
13
|
+
export declare const withCell: (cells: EditorCell[], combo: string, cell: EditorCell) => EditorCell[];
|
|
11
14
|
/**
|
|
12
15
|
* Seed the 169-cell grid from a parent range's per-combo availability and each
|
|
13
16
|
* action's own per-combo range, both expressed as absolute weights (a share of
|
|
@@ -24,3 +27,27 @@ export declare function cellsToComboWeights(cells: EditorCell[], actionIndex: nu
|
|
|
24
27
|
* `actionWeights` naming the remainder action.
|
|
25
28
|
*/
|
|
26
29
|
export declare function comboWeightsToCells(cells: EditorCell[], actionWeights: (Map<string, number> | null)[], passive: number): EditorCell[];
|
|
30
|
+
/**
|
|
31
|
+
* Turn an edited grid back into one hand-keyed range per action, keeping each
|
|
32
|
+
* action's original hands wherever the editor didn't touch them. `original`
|
|
33
|
+
* holds each action's range in editor action order, `seed` the cells the
|
|
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.
|
|
39
|
+
*
|
|
40
|
+
* A combo whose cell still equals its seed cell (same `avail`, same weights)
|
|
41
|
+
* keeps every action's original hands verbatim, so input the whole-percent grid
|
|
42
|
+
* can't represent — a single suit (`AhKh:0.7`) or a fractional weight
|
|
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.
|
|
48
|
+
*
|
|
49
|
+
* Each rebuilt combo takes its first original hand's place, and combos the
|
|
50
|
+
* original didn't have follow in matrix order, so an unedited range formats
|
|
51
|
+
* back to the string it came from.
|
|
52
|
+
*/
|
|
53
|
+
export declare function cellsToRanges(original: (HandFrequency[] | null)[], seed: EditorCell[], cells: EditorCell[], avail?: HandFrequency[] | null): HandFrequency[][];
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export { RangeGrid } from './range-grid';
|
|
|
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';
|
|
6
|
-
export { seedCells, cellsToComboWeights, comboWeightsToCells, type EditorCell, } from './editor/cells';
|
|
6
|
+
export { seedCells, cellsToComboWeights, cellsToRanges, comboWeightsToCells, type EditorCell, } from './editor/cells';
|
|
7
7
|
export { rebalance, type EditorActionSpec } from './editor/weights';
|
package/dist/index.js
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
import { useCallback as
|
|
2
|
-
import { COMBOS as
|
|
3
|
-
import { jsx as
|
|
4
|
-
var
|
|
1
|
+
import { useCallback as M, useEffect as x, useLayoutEffect as P, useMemo as T, useRef as $ } from "react";
|
|
2
|
+
import { COMBOS as C, comboOf as W, handsOfCombo as D, parseRange as F, toComboWeights as B } from "@spotlab/range";
|
|
3
|
+
import { jsx as g, jsxs as y } from "react/jsx-runtime";
|
|
4
|
+
var X = (t, e) => Array.from({ length: Math.ceil(t.length / e) }, (n, r) => t.slice(r * e, r * e + e)), _ = "to right", L = (t) => t.length === 0 ? "transparent" : `linear-gradient(${_}, ${t.join(", ")})`, j = (t) => {
|
|
5
5
|
const e = t.target;
|
|
6
6
|
e.hasPointerCapture(t.pointerId) && e.releasePointerCapture(t.pointerId);
|
|
7
|
-
},
|
|
7
|
+
}, E = (t, e, n) => {
|
|
8
8
|
const r = t.ownerDocument.elementFromPoint(e, n)?.closest("[data-combo]");
|
|
9
9
|
return !r || !t.contains(r) ? null : r.getAttribute("data-combo");
|
|
10
|
-
},
|
|
10
|
+
}, q = ({ combo: t, onPointerDown: e, comboStyle: n }) => /* @__PURE__ */ g("div", {
|
|
11
11
|
className: "spotlab-hm-cell",
|
|
12
12
|
"data-combo": t,
|
|
13
13
|
style: n?.(t),
|
|
14
14
|
onPointerDown: e && ((r) => {
|
|
15
|
-
|
|
15
|
+
j(r), e(t, r);
|
|
16
16
|
}),
|
|
17
|
-
children: /* @__PURE__ */
|
|
17
|
+
children: /* @__PURE__ */ g("div", {
|
|
18
18
|
className: "spotlab-hm-cell-inner",
|
|
19
|
-
children: /* @__PURE__ */
|
|
19
|
+
children: /* @__PURE__ */ g("div", {
|
|
20
20
|
"data-combo": t,
|
|
21
21
|
children: t
|
|
22
22
|
})
|
|
23
23
|
})
|
|
24
|
-
}),
|
|
24
|
+
}), G = ({ row: t, ...e }) => /* @__PURE__ */ g("div", {
|
|
25
25
|
className: "spotlab-hm-row",
|
|
26
|
-
children: t.map((n, r) => /* @__PURE__ */
|
|
26
|
+
children: t.map((n, r) => /* @__PURE__ */ g(q, {
|
|
27
27
|
combo: n,
|
|
28
28
|
...e
|
|
29
29
|
}, r))
|
|
30
|
-
}),
|
|
30
|
+
}), U = {
|
|
31
31
|
touchAction: "none",
|
|
32
32
|
userSelect: "none",
|
|
33
33
|
WebkitUserSelect: "none",
|
|
34
34
|
WebkitTouchCallout: "none"
|
|
35
|
-
},
|
|
36
|
-
const a =
|
|
37
|
-
const
|
|
38
|
-
|
|
35
|
+
}, S = ({ className: t, onPointerDown: e, onPointerEnter: n, ...r }) => {
|
|
36
|
+
const a = $(null), o = (c) => {
|
|
37
|
+
const s = E(c.currentTarget, c.clientX, c.clientY);
|
|
38
|
+
s !== a.current && (a.current = s, s && n?.(s, c));
|
|
39
39
|
};
|
|
40
|
-
return /* @__PURE__ */
|
|
40
|
+
return /* @__PURE__ */ g("div", {
|
|
41
41
|
className: ["spotlab-hm-root", t].filter(Boolean).join(" "),
|
|
42
|
-
style: e ?
|
|
43
|
-
onPointerDown: n && ((
|
|
44
|
-
a.current =
|
|
42
|
+
style: e ? U : void 0,
|
|
43
|
+
onPointerDown: n && ((c) => {
|
|
44
|
+
a.current = E(c.currentTarget, c.clientX, c.clientY);
|
|
45
45
|
}),
|
|
46
46
|
onPointerMove: n && o,
|
|
47
47
|
onPointerLeave: n && (() => a.current = null),
|
|
48
|
-
children:
|
|
49
|
-
row:
|
|
48
|
+
children: X(C, 13).map((c, s) => /* @__PURE__ */ g(G, {
|
|
49
|
+
row: c,
|
|
50
50
|
onPointerDown: e,
|
|
51
51
|
...r
|
|
52
|
-
},
|
|
52
|
+
}, s))
|
|
53
53
|
});
|
|
54
|
-
},
|
|
55
|
-
const r =
|
|
56
|
-
const a = typeof t == "string" ?
|
|
57
|
-
return
|
|
54
|
+
}, Y = (t, e) => ({ background: L([`${t} 0 ${e * 100}%`, `transparent ${e * 100}% 100%`]) }), ot = ({ range: t, fill: e = "var(--spotlab-hm-fill)", className: n }) => {
|
|
55
|
+
const r = T(() => {
|
|
56
|
+
const a = typeof t == "string" ? F(t) : t;
|
|
57
|
+
return B(a);
|
|
58
58
|
}, [t]);
|
|
59
|
-
return /* @__PURE__ */
|
|
59
|
+
return /* @__PURE__ */ g(S, {
|
|
60
60
|
className: n,
|
|
61
61
|
comboStyle: (a) => {
|
|
62
62
|
const o = r.get(a);
|
|
63
|
-
return o ?
|
|
63
|
+
return o ? Y(e, o) : {};
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
|
-
},
|
|
66
|
+
}, H = (t) => Math.max(0, Math.min(100, Math.round(t))), Q = (t, e) => {
|
|
67
67
|
const n = t.map(Math.round);
|
|
68
68
|
let r = 100 - n.reduce((a, o) => a + o, 0);
|
|
69
69
|
if (r !== 0) {
|
|
@@ -80,55 +80,58 @@ var P = (t, e) => Array.from({ length: Math.ceil(t.length / e) }, (n, r) => t.sl
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
return n;
|
|
83
|
-
},
|
|
84
|
-
const a =
|
|
83
|
+
}, J = (t, e, n, r) => {
|
|
84
|
+
const a = H(n), o = t.slice();
|
|
85
85
|
o[e] = a;
|
|
86
|
-
const
|
|
87
|
-
for (let
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
} else
|
|
94
|
-
return
|
|
95
|
-
},
|
|
86
|
+
const c = 100 - a, s = [];
|
|
87
|
+
for (let h = 0; h < t.length; h++) h !== e && s.push(h);
|
|
88
|
+
const d = s.reduce((h, p) => h + t[p], 0);
|
|
89
|
+
if (d <= 0) {
|
|
90
|
+
s.forEach((p) => o[p] = 0);
|
|
91
|
+
const h = e === r ? s[0] : r;
|
|
92
|
+
h != null && (o[h] = c);
|
|
93
|
+
} else s.forEach((h) => o[h] = Math.round(t[h] / d * c));
|
|
94
|
+
return Q(o, e);
|
|
95
|
+
}, N = (t, e) => t.reduce((n, r, a) => a === e ? n : n + r, 0), k = new Map(C.map((t, e) => [t, e])), K = (t, e, n) => {
|
|
96
|
+
const r = t.slice();
|
|
97
|
+
return r[k.get(e)] = n, r;
|
|
98
|
+
}, I = (t, e) => {
|
|
96
99
|
const n = t.slice();
|
|
97
|
-
let r =
|
|
100
|
+
let r = N(n, e);
|
|
98
101
|
if (r > 100) {
|
|
99
102
|
const a = 100 / r;
|
|
100
103
|
for (let o = 0; o < n.length; o++) o !== e && (n[o] = Math.round(n[o] * a));
|
|
101
|
-
r =
|
|
104
|
+
r = N(n, e);
|
|
102
105
|
}
|
|
103
106
|
return n[e] = Math.max(0, 100 - r), n;
|
|
104
107
|
};
|
|
105
|
-
function
|
|
106
|
-
return
|
|
108
|
+
function lt(t, e, n) {
|
|
109
|
+
return C.map((r) => {
|
|
107
110
|
const a = t ? t.get(r) ?? 0 : 1, o = e.map(() => 0);
|
|
108
111
|
return a <= 0 ? (o[n] = 100, {
|
|
109
112
|
avail: 0,
|
|
110
113
|
weights: o
|
|
111
|
-
}) : (e.forEach((
|
|
112
|
-
const
|
|
113
|
-
o[
|
|
114
|
+
}) : (e.forEach((c, s) => {
|
|
115
|
+
const d = c?.get(r) ?? 0;
|
|
116
|
+
o[s] = Math.round(d / a * 100);
|
|
114
117
|
}), {
|
|
115
118
|
avail: a,
|
|
116
|
-
weights:
|
|
119
|
+
weights: I(o, n)
|
|
117
120
|
});
|
|
118
121
|
});
|
|
119
122
|
}
|
|
120
|
-
var
|
|
121
|
-
function
|
|
123
|
+
var A = 8;
|
|
124
|
+
function st(t, e) {
|
|
122
125
|
const n = /* @__PURE__ */ new Map();
|
|
123
126
|
return t.forEach((r, a) => {
|
|
124
127
|
if (r.avail <= 0) return;
|
|
125
|
-
const o = r.weights.reduce((
|
|
128
|
+
const o = r.weights.reduce((s, d) => s + d, 0);
|
|
126
129
|
if (!o) return;
|
|
127
|
-
const
|
|
128
|
-
|
|
130
|
+
const c = Number((r.weights[e] / o * r.avail).toFixed(A));
|
|
131
|
+
c && n.set(C[a], c);
|
|
129
132
|
}), n;
|
|
130
133
|
}
|
|
131
|
-
function
|
|
134
|
+
function ct(t, e, n) {
|
|
132
135
|
return t.map((r, a) => {
|
|
133
136
|
const o = e.map(() => 0);
|
|
134
137
|
if (r.avail <= 0)
|
|
@@ -136,127 +139,153 @@ function tt(t, e, n) {
|
|
|
136
139
|
avail: r.avail,
|
|
137
140
|
weights: o
|
|
138
141
|
};
|
|
139
|
-
const
|
|
140
|
-
return e.forEach((
|
|
141
|
-
const
|
|
142
|
-
o[
|
|
142
|
+
const c = C[a];
|
|
143
|
+
return e.forEach((s, d) => {
|
|
144
|
+
const h = s?.get(c) ?? 0;
|
|
145
|
+
o[d] = Math.round(h / r.avail * 100);
|
|
143
146
|
}), {
|
|
144
147
|
avail: r.avail,
|
|
145
|
-
weights:
|
|
148
|
+
weights: I(o, n)
|
|
146
149
|
};
|
|
147
150
|
});
|
|
148
151
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
var V = (t, e) => t.avail !== e.avail || t.weights.length !== e.weights.length || t.weights.some((n, r) => n !== e.weights[r]);
|
|
153
|
+
function it(t, e, n, r) {
|
|
154
|
+
const a = r && new Map(r.map(({ hand: l, frequency: i }) => [l, i])), o = (l, i) => r === void 0 ? i.avail : a ? a.get(l) ?? 0 : 1, c = t.map((l) => l && new Map(l.map(({ hand: i, frequency: f }) => [i, f]))), s = (l) => c.reduce((i, f) => i + (f?.get(l) ?? 0), 0), d = t.flatMap((l, i) => l ? [] : [i]), h = (l, i) => D(l).flatMap((f) => {
|
|
155
|
+
const b = Number(i(f).toFixed(A));
|
|
156
|
+
return b > 0 ? [{
|
|
157
|
+
hand: f,
|
|
158
|
+
frequency: b
|
|
159
|
+
}] : [];
|
|
160
|
+
}), p = (l, i) => {
|
|
161
|
+
const f = n[k.get(l)], b = f.weights.reduce((v, w) => v + w, 0);
|
|
162
|
+
return f.avail <= 0 || !b ? [] : h(l, (v) => f.weights[i] / b * o(v, f));
|
|
163
|
+
}, m = (l, i) => {
|
|
164
|
+
const f = n[k.get(l)], b = d.reduce((w, O) => w + f.weights[O], 0), v = b ? f.weights[i] / b : 1 / d.length;
|
|
165
|
+
return h(l, (w) => Math.max(0, o(w, f) - s(w)) * v);
|
|
166
|
+
}, u = new Set(C.filter((l, i) => V(e[i], n[i])));
|
|
167
|
+
return t.map((l, i) => {
|
|
168
|
+
if (l === null) return C.flatMap((v) => u.has(v) ? p(v, i) : m(v, i));
|
|
169
|
+
const f = [], b = /* @__PURE__ */ new Set();
|
|
170
|
+
for (const v of l) {
|
|
171
|
+
const w = W(v.hand);
|
|
172
|
+
u.has(w) ? b.has(w) || (b.add(w), f.push(...p(w, i))) : f.push(v);
|
|
173
|
+
}
|
|
174
|
+
for (const v of u) b.has(v) || f.push(...p(v, i));
|
|
175
|
+
return f;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function Z(t) {
|
|
179
|
+
const { cells: e, brush: n, tool: r, onCellsChange: a, onBrushChange: o, onToolChange: c } = t, s = $(null), d = M(() => {
|
|
180
|
+
s.current?.abort(), s.current = null;
|
|
152
181
|
}, []);
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
182
|
+
x(() => d, [d]);
|
|
183
|
+
const h = $(e);
|
|
184
|
+
P(() => {
|
|
185
|
+
h.current = e;
|
|
157
186
|
}, [e]);
|
|
158
|
-
const p =
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
avail: d[f].avail,
|
|
187
|
+
const p = M((u) => {
|
|
188
|
+
const l = h.current, { avail: i } = l[k.get(u)];
|
|
189
|
+
if (i <= 0) return;
|
|
190
|
+
const f = K(l, u, {
|
|
191
|
+
avail: i,
|
|
164
192
|
weights: [...n]
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
193
|
+
});
|
|
194
|
+
h.current = f, a(f);
|
|
195
|
+
}, [n, a]), m = M((u) => {
|
|
196
|
+
const l = k.get(u);
|
|
197
|
+
e[l].avail <= 0 || (o([...e[l].weights]), c("brush"));
|
|
169
198
|
}, [
|
|
170
199
|
e,
|
|
171
200
|
o,
|
|
172
|
-
|
|
201
|
+
c
|
|
173
202
|
]);
|
|
174
203
|
return {
|
|
175
|
-
onCellDown:
|
|
204
|
+
onCellDown: M((u) => {
|
|
176
205
|
if (r === "eyedropper") {
|
|
177
|
-
m(
|
|
206
|
+
m(u);
|
|
178
207
|
return;
|
|
179
208
|
}
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
209
|
+
d();
|
|
210
|
+
const l = new AbortController();
|
|
211
|
+
s.current = l, window.addEventListener("pointerup", d, { signal: l.signal }), window.addEventListener("pointercancel", d, { signal: l.signal }), p(u);
|
|
183
212
|
}, [
|
|
184
213
|
r,
|
|
185
214
|
m,
|
|
186
215
|
p,
|
|
187
|
-
|
|
216
|
+
d
|
|
188
217
|
]),
|
|
189
|
-
onCellEnter:
|
|
190
|
-
|
|
218
|
+
onCellEnter: M((u) => {
|
|
219
|
+
s.current && r === "brush" && p(u);
|
|
191
220
|
}, [r, p])
|
|
192
221
|
};
|
|
193
222
|
}
|
|
194
|
-
var
|
|
223
|
+
var R = (t, e, n) => {
|
|
195
224
|
const r = [];
|
|
196
225
|
let a = 0;
|
|
197
226
|
return n.forEach((o) => {
|
|
198
|
-
const
|
|
199
|
-
if (
|
|
200
|
-
const
|
|
201
|
-
r.push(`${
|
|
202
|
-
}), r.length > 0 && a < 1 - 1e-9 && r.push(`transparent ${a * 100}% 100%`),
|
|
203
|
-
},
|
|
204
|
-
const { onCellDown:
|
|
227
|
+
const c = (t.weights[o] || 0) / 100;
|
|
228
|
+
if (c <= 0) return;
|
|
229
|
+
const s = e[o].color;
|
|
230
|
+
r.push(`${s} ${a * 100}%`), r.push(`${s} ${(a + c) * 100}%`), a += c;
|
|
231
|
+
}), r.length > 0 && a < 1 - 1e-9 && r.push(`transparent ${a * 100}% 100%`), L(r);
|
|
232
|
+
}, ut = ({ cells: t, actions: e, order: n, brush: r, tool: a, onCellsChange: o, onBrushChange: c, onToolChange: s, className: d }) => {
|
|
233
|
+
const { onCellDown: h, onCellEnter: p } = Z({
|
|
205
234
|
cells: t,
|
|
206
235
|
brush: r,
|
|
207
236
|
tool: a,
|
|
208
237
|
onCellsChange: o,
|
|
209
|
-
onBrushChange:
|
|
210
|
-
onToolChange:
|
|
238
|
+
onBrushChange: c,
|
|
239
|
+
onToolChange: s
|
|
211
240
|
});
|
|
212
|
-
return /* @__PURE__ */
|
|
213
|
-
className:
|
|
241
|
+
return /* @__PURE__ */ g(S, {
|
|
242
|
+
className: d,
|
|
214
243
|
comboStyle: (m) => {
|
|
215
|
-
const
|
|
216
|
-
if (
|
|
244
|
+
const u = t[k.get(m)];
|
|
245
|
+
if (u.avail <= 0) return {
|
|
217
246
|
background: "var(--spotlab-hm-dead-hatch)",
|
|
218
247
|
backgroundColor: "var(--spotlab-hm-muted-bg)",
|
|
219
248
|
cursor: "not-allowed",
|
|
220
249
|
color: "var(--spotlab-hm-muted-fg)"
|
|
221
250
|
};
|
|
222
|
-
const
|
|
223
|
-
if (
|
|
224
|
-
const
|
|
251
|
+
const l = a === "eyedropper" ? "copy" : "pointer";
|
|
252
|
+
if (u.avail < 1) {
|
|
253
|
+
const i = `${u.avail * 100}%`;
|
|
225
254
|
return {
|
|
226
|
-
background: `repeating-linear-gradient(180deg, var(--spotlab-hm-muted-fg) 0 4px, transparent 4px 8px), var(--spotlab-hm-dead-hatch), ${
|
|
227
|
-
backgroundSize: `1px 100%, ${(1 -
|
|
228
|
-
backgroundPosition: `${
|
|
255
|
+
background: `repeating-linear-gradient(180deg, var(--spotlab-hm-muted-fg) 0 4px, transparent 4px 8px), var(--spotlab-hm-dead-hatch), ${R(u, e, n)}`,
|
|
256
|
+
backgroundSize: `1px 100%, ${(1 - u.avail) * 100}% 100%, ${u.avail * 100}% 100%`,
|
|
257
|
+
backgroundPosition: `${i} center, right center, left center`,
|
|
229
258
|
backgroundRepeat: "no-repeat, no-repeat, no-repeat",
|
|
230
|
-
cursor:
|
|
259
|
+
cursor: l
|
|
231
260
|
};
|
|
232
261
|
}
|
|
233
262
|
return {
|
|
234
|
-
background:
|
|
235
|
-
cursor:
|
|
263
|
+
background: R(u, e, n),
|
|
264
|
+
cursor: l
|
|
236
265
|
};
|
|
237
266
|
},
|
|
238
|
-
onPointerDown:
|
|
267
|
+
onPointerDown: h,
|
|
239
268
|
onPointerEnter: p
|
|
240
269
|
});
|
|
241
|
-
},
|
|
270
|
+
}, z = (t) => /* @__PURE__ */ g("input", {
|
|
242
271
|
type: "number",
|
|
243
272
|
className: "spotlab-hm-weight-input",
|
|
244
273
|
...t
|
|
245
|
-
}),
|
|
246
|
-
const a =
|
|
247
|
-
const
|
|
248
|
-
if (!
|
|
249
|
-
const
|
|
250
|
-
r((
|
|
274
|
+
}), tt = ({ value: t, color: e, passive: n, onChange: r }) => {
|
|
275
|
+
const a = $(null), o = $(!1), c = M((s) => {
|
|
276
|
+
const d = a.current;
|
|
277
|
+
if (!d) return;
|
|
278
|
+
const h = d.getBoundingClientRect();
|
|
279
|
+
r((s - h.left) / h.width * 100);
|
|
251
280
|
}, [r]);
|
|
252
|
-
return
|
|
253
|
-
const
|
|
254
|
-
o.current &&
|
|
255
|
-
},
|
|
256
|
-
return window.addEventListener("pointermove",
|
|
257
|
-
window.removeEventListener("pointermove",
|
|
281
|
+
return x(() => {
|
|
282
|
+
const s = (h) => {
|
|
283
|
+
o.current && c(h.clientX);
|
|
284
|
+
}, d = () => o.current = !1;
|
|
285
|
+
return window.addEventListener("pointermove", s), window.addEventListener("pointerup", d), () => {
|
|
286
|
+
window.removeEventListener("pointermove", s), window.removeEventListener("pointerup", d);
|
|
258
287
|
};
|
|
259
|
-
}, [
|
|
288
|
+
}, [c]), /* @__PURE__ */ g("div", {
|
|
260
289
|
ref: a,
|
|
261
290
|
role: "slider",
|
|
262
291
|
"aria-valuenow": t,
|
|
@@ -264,10 +293,10 @@ var E = (t, e, n) => {
|
|
|
264
293
|
"aria-valuemax": 100,
|
|
265
294
|
className: "spotlab-hm-slider-track",
|
|
266
295
|
style: { background: `linear-gradient(to right, ${e} 0 ${t}%, var(--spotlab-hm-track-bg) ${t}% 100%)` },
|
|
267
|
-
onPointerDown: (
|
|
268
|
-
o.current = !0,
|
|
296
|
+
onPointerDown: (s) => {
|
|
297
|
+
o.current = !0, c(s.clientX);
|
|
269
298
|
},
|
|
270
|
-
children: /* @__PURE__ */
|
|
299
|
+
children: /* @__PURE__ */ g("div", {
|
|
271
300
|
className: "spotlab-hm-slider-thumb",
|
|
272
301
|
style: {
|
|
273
302
|
left: `${t}%`,
|
|
@@ -275,60 +304,61 @@ var E = (t, e, n) => {
|
|
|
275
304
|
}
|
|
276
305
|
})
|
|
277
306
|
});
|
|
278
|
-
},
|
|
307
|
+
}, et = (t, e) => /* @__PURE__ */ y("span", {
|
|
279
308
|
className: "spotlab-hm-slider-label",
|
|
280
|
-
children: [t.label, e && /* @__PURE__ */
|
|
309
|
+
children: [t.label, e && /* @__PURE__ */ g("span", {
|
|
281
310
|
className: "spotlab-hm-slider-remainder",
|
|
282
311
|
children: " · remainder"
|
|
283
312
|
})]
|
|
284
|
-
}),
|
|
285
|
-
const
|
|
286
|
-
a(
|
|
313
|
+
}), ht = ({ actions: t, order: e, weights: n, passive: r, onWeightsChange: a, renderActionLabel: o, renderActionExtra: c, components: s, className: d }) => {
|
|
314
|
+
const h = s?.WeightInput ?? z, p = (m, u) => {
|
|
315
|
+
a(J(n, m, u, r));
|
|
287
316
|
};
|
|
288
|
-
return /* @__PURE__ */
|
|
289
|
-
className: ["spotlab-hm-root spotlab-hm-sliders",
|
|
317
|
+
return /* @__PURE__ */ g("div", {
|
|
318
|
+
className: ["spotlab-hm-root spotlab-hm-sliders", d].filter(Boolean).join(" "),
|
|
290
319
|
children: e.map((m) => {
|
|
291
|
-
const
|
|
292
|
-
return /* @__PURE__ */
|
|
320
|
+
const u = t[m], l = m === r;
|
|
321
|
+
return /* @__PURE__ */ y("div", {
|
|
293
322
|
className: "spotlab-hm-slider-row",
|
|
294
|
-
"data-passive":
|
|
295
|
-
children: [/* @__PURE__ */
|
|
323
|
+
"data-passive": l,
|
|
324
|
+
children: [/* @__PURE__ */ y("div", {
|
|
296
325
|
className: "spotlab-hm-slider-header",
|
|
297
326
|
children: [
|
|
298
|
-
/* @__PURE__ */
|
|
327
|
+
/* @__PURE__ */ g("span", {
|
|
299
328
|
className: "spotlab-hm-slider-swatch",
|
|
300
|
-
style: { background:
|
|
329
|
+
style: { background: u.color }
|
|
301
330
|
}),
|
|
302
|
-
o?.(
|
|
303
|
-
|
|
331
|
+
o?.(u, m, l) ?? et(u, l),
|
|
332
|
+
c?.(u, m)
|
|
304
333
|
]
|
|
305
|
-
}), /* @__PURE__ */
|
|
334
|
+
}), /* @__PURE__ */ y("div", {
|
|
306
335
|
className: "spotlab-hm-slider-track-row",
|
|
307
|
-
children: [/* @__PURE__ */
|
|
336
|
+
children: [/* @__PURE__ */ g(tt, {
|
|
308
337
|
value: n[m],
|
|
309
|
-
color:
|
|
310
|
-
passive:
|
|
311
|
-
onChange: (
|
|
312
|
-
}), /* @__PURE__ */ h
|
|
338
|
+
color: u.color,
|
|
339
|
+
passive: l,
|
|
340
|
+
onChange: (i) => p(m, i)
|
|
341
|
+
}), /* @__PURE__ */ g(h, {
|
|
313
342
|
value: n[m],
|
|
314
|
-
"aria-label": `${
|
|
315
|
-
onChange: (
|
|
343
|
+
"aria-label": `${u.label} weight`,
|
|
344
|
+
onChange: (i) => p(m, parseInt(i.target.value || "0", 10))
|
|
316
345
|
})]
|
|
317
346
|
})]
|
|
318
|
-
},
|
|
347
|
+
}, u.id);
|
|
319
348
|
})
|
|
320
349
|
});
|
|
321
350
|
};
|
|
322
351
|
export {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
352
|
+
ht as ActionWeightSliders,
|
|
353
|
+
_ as CELL_FILL_DIRECTION,
|
|
354
|
+
S as HandMatrix,
|
|
355
|
+
ot as RangeGrid,
|
|
356
|
+
ut as RangeMatrixEditor,
|
|
357
|
+
L as cellFillGradient,
|
|
358
|
+
st as cellsToComboWeights,
|
|
359
|
+
it as cellsToRanges,
|
|
360
|
+
ct as comboWeightsToCells,
|
|
361
|
+
J as rebalance,
|
|
362
|
+
lt as seedCells,
|
|
363
|
+
Z as useRangePainting
|
|
334
364
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spotlab/hand-matrix",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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",
|
|
@@ -40,19 +40,19 @@
|
|
|
40
40
|
"LICENSE"
|
|
41
41
|
],
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@spotlab/range": "^0.
|
|
43
|
+
"@spotlab/range": "^0.3.0",
|
|
44
44
|
"react": "^19.0.0",
|
|
45
45
|
"react-dom": "^19.0.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@spotlab/range": "0.
|
|
48
|
+
"@spotlab/range": "0.3.0",
|
|
49
49
|
"@storybook/addon-vitest": "^10.5.5",
|
|
50
50
|
"@storybook/react-vite": "^10.5.5",
|
|
51
51
|
"@types/react": "^19.2.16",
|
|
52
52
|
"@types/react-dom": "^19.2.3",
|
|
53
53
|
"@vitejs/plugin-react": "^6.0.0",
|
|
54
|
-
"@vitest/browser": "^
|
|
55
|
-
"@vitest/browser-playwright": "
|
|
54
|
+
"@vitest/browser": "^5.0.0",
|
|
55
|
+
"@vitest/browser-playwright": "^5.0.0",
|
|
56
56
|
"playwright": "^1.49.1",
|
|
57
57
|
"react": "^19.2.7",
|
|
58
58
|
"react-dom": "^19.2.7",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"typescript": "^6.0.0",
|
|
61
61
|
"vite": "^8.3.1",
|
|
62
62
|
"vite-plugin-dts": "^5.1.2",
|
|
63
|
-
"vitest": "^
|
|
63
|
+
"vitest": "^5.0.0"
|
|
64
64
|
},
|
|
65
65
|
"publishConfig": {
|
|
66
66
|
"access": "public"
|