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