poker-irongrid 1.2.0 → 1.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 +1 -0
- package/dist/poker-grid/components/DeadCardsInput.svelte +8 -19
- package/dist/poker-grid/components/Grid.svelte +42 -13
- package/dist/poker-grid/components/Grid.svelte.d.ts +2 -0
- package/dist/poker-grid/components/PokerGridPanel.svelte +3 -0
- package/dist/poker-grid/components/PokerGridPanel.svelte.d.ts +2 -0
- package/dist/poker-grid/components/SelectionSummary.svelte +5 -1
- package/dist/poker-grid/theme.css +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,6 +85,7 @@ npm install poker-irongrid
|
|
|
85
85
|
| `defaultColor` | `string` | `'hsl(0, 0%, 100%)'` | Default background color for uncolored hands |
|
|
86
86
|
| `defaultSelectedColor` | `string` | `'hsl(0, 0%, 85%)'` | Default color for selected hands without explicit color |
|
|
87
87
|
| `evaluator` | `boolean` | `false` | Show hero's live equity against the hands on the grid (requires hero cards) |
|
|
88
|
+
| `subgrid` | `boolean` | `false` | Split the grid into 3x3 blocks (A–T, 9–6, 5–2) with space after the T and 6 rows/columns; spacing set by `--irongrid-subgrid-gap` (default `6px`) |
|
|
88
89
|
| `preflopTableUrl` | `string \| null` | `null` | URL of poker-bitvaljs's `bench/preflop-table.bin` for exact preflop equity (Monte Carlo without it) |
|
|
89
90
|
|
|
90
91
|
#### Initial State Props
|
|
@@ -130,25 +130,14 @@
|
|
|
130
130
|
function normalizeTokens(input) {
|
|
131
131
|
if (!input || !input.trim()) return [];
|
|
132
132
|
const symbolMap = { '♣': 'c', '♦': 'd', '♥': 'h', '♠': 's' };
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
.
|
|
138
|
-
.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
let t = tok.trim();
|
|
142
|
-
t = t.replace(/[♣♦♥♠]/g, (m) => symbolMap[m] || m);
|
|
143
|
-
const rank = t.charAt(0).toUpperCase();
|
|
144
|
-
const suitRaw = t.charAt(1) || '';
|
|
145
|
-
const suit = suitRaw.toLowerCase();
|
|
146
|
-
if (validRanks.has(rank) && validSuits.has(suit)) {
|
|
147
|
-
return rank + suit;
|
|
148
|
-
}
|
|
149
|
-
return null;
|
|
150
|
-
})
|
|
151
|
-
.filter(Boolean);
|
|
133
|
+
const text = input.replace(/[♣♦♥♠]/g, (m) => symbolMap[m]);
|
|
134
|
+
// Cards with or without separators: 'As Ks', 'AsKs', 'A♠K♠', 'as,ks' all give ['As', 'Ks']
|
|
135
|
+
const cards = [];
|
|
136
|
+
for (const [, rank, suit] of text.matchAll(/([AKQJT2-9])([cdhs])/gi)) {
|
|
137
|
+
const card = rank.toUpperCase() + suit.toLowerCase();
|
|
138
|
+
if (!cards.includes(card)) cards.push(card);
|
|
139
|
+
}
|
|
140
|
+
return cards;
|
|
152
141
|
}
|
|
153
142
|
|
|
154
143
|
/**
|
|
@@ -18,6 +18,28 @@
|
|
|
18
18
|
export let showTips = false;
|
|
19
19
|
/** Whether to enable double-click details panel. */
|
|
20
20
|
export let enableDetailsPanel = false;
|
|
21
|
+
/**
|
|
22
|
+
* Split the grid into 3x3 blocks: extra space after the T and 6 rows/columns (A-T, 9-6, 5-2).
|
|
23
|
+
* The space is set by the --irongrid-subgrid-gap CSS variable.
|
|
24
|
+
*/
|
|
25
|
+
export let subgrid = false;
|
|
26
|
+
|
|
27
|
+
/** CSS grid line for a row/column index: with subgrid, spacer tracks follow T (index 4) and 6 (index 8). */
|
|
28
|
+
function gridLine(index, split) {
|
|
29
|
+
return index + 1 + (split ? (index >= 5 ? 1 : 0) + (index >= 9 ? 1 : 0) : 0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The grid cell under a point (or null), from the cells' own positions, so it works with any spacing. */
|
|
33
|
+
function cellAtPoint(gridElement, x, y) {
|
|
34
|
+
const cells = gridElement.querySelectorAll('[data-row]');
|
|
35
|
+
for (const cell of cells) {
|
|
36
|
+
const r = cell.getBoundingClientRect();
|
|
37
|
+
if (x >= r.left && x < r.right && y >= r.top && y < r.bottom) {
|
|
38
|
+
return { element: cell, rect: r, row: Number(cell.dataset.row), col: Number(cell.dataset.col) };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
21
43
|
|
|
22
44
|
let isDragging = false;
|
|
23
45
|
let tooltip = { visible: false, x: 0, y: 0, content: '' };
|
|
@@ -187,19 +209,16 @@
|
|
|
187
209
|
function handleMouseMove(event) {
|
|
188
210
|
if (!isDragging) return;
|
|
189
211
|
const gridElement = event.currentTarget;
|
|
190
|
-
const rect = gridElement.getBoundingClientRect();
|
|
191
|
-
const cellSize = rect.width / 13;
|
|
192
212
|
const coords = getEventCoordinates(event);
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
if (colIndex < 0 || colIndex >= 13 || rowIndex < 0 || rowIndex >= 13) return;
|
|
198
|
-
const cellInfo = getCellInfo(rowIndex, colIndex);
|
|
199
|
-
const cellRect = { left: colIndex * cellSize, top: rowIndex * cellSize, width: cellSize, height: cellSize };
|
|
213
|
+
const hit = cellAtPoint(gridElement, coords.x, coords.y);
|
|
214
|
+
if (!hit) return;
|
|
215
|
+
const cellInfo = getCellInfo(hit.row, hit.col);
|
|
216
|
+
const cellSize = Math.min(hit.rect.width, hit.rect.height);
|
|
200
217
|
const bufferSize = cellSize * 0.75;
|
|
201
218
|
const bufferOffset = (cellSize - bufferSize) / 2;
|
|
202
|
-
const
|
|
219
|
+
const x = coords.x - hit.rect.left;
|
|
220
|
+
const y = coords.y - hit.rect.top;
|
|
221
|
+
const inHitZone = x >= bufferOffset && x <= bufferOffset + bufferSize && y >= bufferOffset && y <= bufferOffset + bufferSize;
|
|
203
222
|
if (!inHitZone) return;
|
|
204
223
|
if (!dragCells.has(cellInfo.hand)) {
|
|
205
224
|
dragCells.add(cellInfo.hand);
|
|
@@ -404,7 +423,7 @@
|
|
|
404
423
|
</script>
|
|
405
424
|
|
|
406
425
|
<div class="poker-grid-container" role="region" aria-label="Poker hand grid container">
|
|
407
|
-
<div class="poker-grid" bind:this={gridElement} onmousemove={handleMouseMove} role="application" aria-label="Poker hand selection grid" tabindex={interactive ? 0 : -1} onmouseup={handleMouseUp}>
|
|
426
|
+
<div class="poker-grid" class:subgrid bind:this={gridElement} onmousemove={handleMouseMove} role="application" aria-label="Poker hand selection grid" tabindex={interactive ? 0 : -1} onmouseup={handleMouseUp}>
|
|
408
427
|
{#each Array(13) as _, rowIndex}
|
|
409
428
|
{#each Array(13) as __, colIndex}
|
|
410
429
|
{@const cellInfo = getCellInfo(rowIndex, colIndex)}
|
|
@@ -412,7 +431,9 @@
|
|
|
412
431
|
<button
|
|
413
432
|
type="button"
|
|
414
433
|
class="grid-cell {isDragging ? 'dragging' : ''} {interactive ? '' : showTips ? 'non-interactive show-tips' : 'non-interactive'}"
|
|
415
|
-
style="background: {gradients[cellInfo.hand]} !important"
|
|
434
|
+
style="background: {gradients[cellInfo.hand]} !important; grid-row: {gridLine(rowIndex, subgrid)}; grid-column: {gridLine(colIndex, subgrid)};"
|
|
435
|
+
data-row={rowIndex}
|
|
436
|
+
data-col={colIndex}
|
|
416
437
|
onclick={(e) => handleClick(e, cellInfo)}
|
|
417
438
|
ondblclick={(e) => handleDoubleClick(e, cellInfo)}
|
|
418
439
|
onmousedown={(e) => handleMouseDown(e, cellInfo)}
|
|
@@ -425,7 +446,9 @@
|
|
|
425
446
|
{:else}
|
|
426
447
|
<div
|
|
427
448
|
class="grid-cell non-interactive"
|
|
428
|
-
style="background: {gradients[cellInfo.hand]} !important"
|
|
449
|
+
style="background: {gradients[cellInfo.hand]} !important; grid-row: {gridLine(rowIndex, subgrid)}; grid-column: {gridLine(colIndex, subgrid)};"
|
|
450
|
+
data-row={rowIndex}
|
|
451
|
+
data-col={colIndex}
|
|
429
452
|
role="presentation"
|
|
430
453
|
title={cellInfo.display}
|
|
431
454
|
>
|
|
@@ -463,6 +486,12 @@
|
|
|
463
486
|
gap: 0;
|
|
464
487
|
border: var(--irongrid-border-width) solid var(--irongrid-color-border);
|
|
465
488
|
}
|
|
489
|
+
/* 3x3 blocks: spacer tracks after T and 6 (A-T | 9-6 | 5-2) */
|
|
490
|
+
.poker-grid.subgrid {
|
|
491
|
+
grid-template-columns: repeat(5, 1fr) var(--irongrid-subgrid-gap, 6px) repeat(4, 1fr) var(--irongrid-subgrid-gap, 6px) repeat(4, 1fr);
|
|
492
|
+
grid-template-rows: repeat(5, auto) var(--irongrid-subgrid-gap, 6px) repeat(4, auto) var(--irongrid-subgrid-gap, 6px) repeat(4, auto);
|
|
493
|
+
border: none;
|
|
494
|
+
}
|
|
466
495
|
.grid-cell {
|
|
467
496
|
aspect-ratio: 1;
|
|
468
497
|
display: flex;
|
|
@@ -8,6 +8,7 @@ type Grid = SvelteComponent<{
|
|
|
8
8
|
interactive?: boolean;
|
|
9
9
|
showTips?: boolean;
|
|
10
10
|
enableDetailsPanel?: boolean;
|
|
11
|
+
subgrid?: boolean;
|
|
11
12
|
}, {
|
|
12
13
|
cellDetails: CustomEvent<any>;
|
|
13
14
|
cellClick: CustomEvent<any>;
|
|
@@ -26,6 +27,7 @@ declare const Grid: $$__sveltets_2_IsomorphicComponent<{
|
|
|
26
27
|
interactive?: boolean;
|
|
27
28
|
showTips?: boolean;
|
|
28
29
|
enableDetailsPanel?: boolean;
|
|
30
|
+
subgrid?: boolean;
|
|
29
31
|
}, {
|
|
30
32
|
cellDetails: CustomEvent<any>;
|
|
31
33
|
cellClick: CustomEvent<any>;
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
export let showSummary = true;
|
|
26
26
|
export let showTips = false;
|
|
27
27
|
export let enableDetailsPanel = false;
|
|
28
|
+
/** Split the grid into 3x3 blocks (A-T, 9-6, 5-2) with space between them. */
|
|
29
|
+
export let subgrid = false;
|
|
28
30
|
export let evaluator = false;
|
|
29
31
|
export let defaultColor = 'hsl(0, 0%, 100%)';
|
|
30
32
|
export let defaultSelectedColor = 'hsl(0, 0%, 85%)';
|
|
@@ -265,6 +267,7 @@
|
|
|
265
267
|
{interactive}
|
|
266
268
|
{showTips}
|
|
267
269
|
{enableDetailsPanel}
|
|
270
|
+
{subgrid}
|
|
268
271
|
{manager}
|
|
269
272
|
on:selectionChange={handleSelectionChange}
|
|
270
273
|
on:cellDetails={handleCellDetails}
|
|
@@ -10,6 +10,7 @@ type PokerGridPanel = SvelteComponent<{
|
|
|
10
10
|
interactive?: boolean;
|
|
11
11
|
showTips?: boolean;
|
|
12
12
|
enableDetailsPanel?: boolean;
|
|
13
|
+
subgrid?: boolean;
|
|
13
14
|
evaluator?: boolean;
|
|
14
15
|
visibleHands?: {};
|
|
15
16
|
ranges?: any[];
|
|
@@ -42,6 +43,7 @@ declare const PokerGridPanel: $$__sveltets_2_IsomorphicComponent<{
|
|
|
42
43
|
interactive?: boolean;
|
|
43
44
|
showTips?: boolean;
|
|
44
45
|
enableDetailsPanel?: boolean;
|
|
46
|
+
subgrid?: boolean;
|
|
45
47
|
evaluator?: boolean;
|
|
46
48
|
visibleHands?: {};
|
|
47
49
|
ranges?: any[];
|
|
@@ -74,7 +74,11 @@
|
|
|
74
74
|
</span>
|
|
75
75
|
</span>
|
|
76
76
|
<div class="flex items-center gap-2">
|
|
77
|
-
{#if
|
|
77
|
+
{#if evaluator && heroCards?.length !== 2 && selected + highlighted > 0}
|
|
78
|
+
<div class="text-xs" style="color: var(--irongrid-color-text-secondary);">
|
|
79
|
+
<span>Enter 2 hero cards for equity</span>
|
|
80
|
+
</div>
|
|
81
|
+
{:else if showEquity}
|
|
78
82
|
<div
|
|
79
83
|
class="text-xs equity-readout"
|
|
80
84
|
class:equity-pending={equityPending}
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
|
|
54
54
|
/* Border Variables */
|
|
55
55
|
--irongrid-border-width: 1px;
|
|
56
|
+
--irongrid-subgrid-gap: 6px; /* space between the 3x3 blocks with subgrid */
|
|
56
57
|
--irongrid-border-radius-sm: 0.125rem;
|
|
57
58
|
--irongrid-border-radius-md: 0.25rem;
|
|
58
59
|
--irongrid-border-radius-lg: 0.375rem;
|