@joystyk/cards-ui 0.0.0-stage → 0.2.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/dist/table.js ADDED
@@ -0,0 +1,629 @@
1
+ import { DEFAULT_OPTIONS, EMPTY_LAYOUT, isFaceCard, isTableLayout, isTableOptions } from "./layout.js";
2
+ import { initialCtl, isQuiet, step, sync } from "./controller.js";
3
+ import { cardFace, suitDefs } from "./faces.js";
4
+ import { tableStyles } from "./styles.js";
5
+ import { define, defineHook, each, focus, intentsOf, nothing, outputs, prop } from "@gyral/core";
6
+ import { compiled } from "@gyral/core/compiled";
7
+ //#region src/table.ts
8
+ var _gyral$t0 = {
9
+ "id": "23sujkldcai",
10
+ "html": "<div></div>",
11
+ "parts": [[
12
+ 4,
13
+ [0],
14
+ "class",
15
+ ["card down ", ""]
16
+ ], [
17
+ 3,
18
+ [0],
19
+ "data-depth"
20
+ ]],
21
+ "segments": [
22
+ "<div",
23
+ {
24
+ "k": "attr",
25
+ "name": "class",
26
+ "strings": ["card down ", ""]
27
+ },
28
+ {
29
+ "k": "attr",
30
+ "name": "data-depth"
31
+ },
32
+ "></div>"
33
+ ]
34
+ };
35
+ var _gyral$t1 = {
36
+ "id": "c89xslobig",
37
+ "html": "<div></div>",
38
+ "parts": [
39
+ [
40
+ 4,
41
+ [0],
42
+ "class",
43
+ [
44
+ "card up s-",
45
+ " ",
46
+ ""
47
+ ]
48
+ ],
49
+ [
50
+ 3,
51
+ [0],
52
+ "data-depth"
53
+ ],
54
+ [7, [0]],
55
+ [1, [0]]
56
+ ],
57
+ "segments": [
58
+ "<div",
59
+ {
60
+ "k": "attr",
61
+ "name": "class",
62
+ "strings": [
63
+ "card up s-",
64
+ " ",
65
+ ""
66
+ ]
67
+ },
68
+ {
69
+ "k": "attr",
70
+ "name": "data-depth"
71
+ },
72
+ { "k": "hook" },
73
+ ">",
74
+ {
75
+ "k": "child",
76
+ "in": "div"
77
+ },
78
+ "</div>"
79
+ ]
80
+ };
81
+ var _gyral$t2 = {
82
+ "id": "23i2fc2fy2w",
83
+ "html": "<div role=\"button\"><span class=\"slot\" aria-hidden=\"true\"></span> <!----> <span class=\"drop\" aria-hidden=\"true\"></span> </div>",
84
+ "parts": [
85
+ [
86
+ 3,
87
+ [0],
88
+ "class"
89
+ ],
90
+ [
91
+ 4,
92
+ [0],
93
+ "part",
94
+ ["pile pile-", ""]
95
+ ],
96
+ [
97
+ 3,
98
+ [0],
99
+ "tabindex"
100
+ ],
101
+ [
102
+ 3,
103
+ [0],
104
+ "data-pile"
105
+ ],
106
+ [
107
+ 3,
108
+ [0],
109
+ "data-region"
110
+ ],
111
+ [
112
+ 3,
113
+ [0],
114
+ "aria-label"
115
+ ],
116
+ [
117
+ 3,
118
+ [0],
119
+ "aria-keyshortcuts"
120
+ ],
121
+ [
122
+ 4,
123
+ [0, 0],
124
+ "part",
125
+ ["slot slot-", ""]
126
+ ],
127
+ [1, [0, 0]],
128
+ [
129
+ 2,
130
+ [0],
131
+ 2
132
+ ],
133
+ [0, [0]]
134
+ ],
135
+ "segments": [
136
+ "<div role=\"button\"",
137
+ {
138
+ "k": "attr",
139
+ "name": "class"
140
+ },
141
+ {
142
+ "k": "attr",
143
+ "name": "part",
144
+ "strings": ["pile pile-", ""]
145
+ },
146
+ {
147
+ "k": "attr",
148
+ "name": "tabindex"
149
+ },
150
+ {
151
+ "k": "attr",
152
+ "name": "data-pile"
153
+ },
154
+ {
155
+ "k": "attr",
156
+ "name": "data-region"
157
+ },
158
+ {
159
+ "k": "attr",
160
+ "name": "aria-label"
161
+ },
162
+ {
163
+ "k": "attr",
164
+ "name": "aria-keyshortcuts"
165
+ },
166
+ "><span class=\"slot\" aria-hidden=\"true\"",
167
+ {
168
+ "k": "attr",
169
+ "name": "part",
170
+ "strings": ["slot slot-", ""]
171
+ },
172
+ ">",
173
+ {
174
+ "k": "child",
175
+ "in": "span"
176
+ },
177
+ "</span> ",
178
+ {
179
+ "k": "child",
180
+ "in": "div"
181
+ },
182
+ "<!----> <span class=\"drop\" aria-hidden=\"true\"></span> ",
183
+ {
184
+ "k": "child",
185
+ "in": "div"
186
+ },
187
+ "</div>"
188
+ ]
189
+ };
190
+ var _gyral$t3 = {
191
+ "id": "a5d1o1xv5w",
192
+ "html": "<span class=\"pile-badge\" aria-hidden=\"true\"></span>",
193
+ "parts": [[1, [0]]],
194
+ "segments": [
195
+ "<span class=\"pile-badge\" aria-hidden=\"true\">",
196
+ {
197
+ "k": "child",
198
+ "in": "span"
199
+ },
200
+ "</span>"
201
+ ]
202
+ };
203
+ var _gyral$t4 = {
204
+ "id": "10zd8ziqlbi",
205
+ "html": "<div role=\"toolbar\"></div>",
206
+ "parts": [
207
+ [
208
+ 4,
209
+ [0],
210
+ "class",
211
+ [
212
+ "region at-",
213
+ " n-",
214
+ " ",
215
+ ""
216
+ ]
217
+ ],
218
+ [
219
+ 3,
220
+ [0],
221
+ "aria-label"
222
+ ],
223
+ [
224
+ 3,
225
+ [0],
226
+ "data-region"
227
+ ],
228
+ [1, [0]]
229
+ ],
230
+ "segments": [
231
+ "<div role=\"toolbar\"",
232
+ {
233
+ "k": "attr",
234
+ "name": "class",
235
+ "strings": [
236
+ "region at-",
237
+ " n-",
238
+ " ",
239
+ ""
240
+ ]
241
+ },
242
+ {
243
+ "k": "attr",
244
+ "name": "aria-label"
245
+ },
246
+ {
247
+ "k": "attr",
248
+ "name": "data-region"
249
+ },
250
+ ">",
251
+ {
252
+ "k": "child",
253
+ "in": "div"
254
+ },
255
+ "</div>"
256
+ ]
257
+ };
258
+ var _gyral$t5 = {
259
+ "id": "1r4dqlbm8hj",
260
+ "html": "<div class=\"t-events\"><div role=\"group\"></div></div>",
261
+ "parts": [
262
+ [
263
+ 2,
264
+ [],
265
+ 0
266
+ ],
267
+ [
268
+ 3,
269
+ [0],
270
+ "data-intent-keydown"
271
+ ],
272
+ [
273
+ 3,
274
+ [0],
275
+ "data-intent-pointermove"
276
+ ],
277
+ [
278
+ 3,
279
+ [0],
280
+ "data-intent-pointerup"
281
+ ],
282
+ [
283
+ 3,
284
+ [0],
285
+ "data-intent-pointercancel"
286
+ ],
287
+ [
288
+ 3,
289
+ [0],
290
+ "data-intent-focusin"
291
+ ],
292
+ [
293
+ 3,
294
+ [0],
295
+ "data-intent-pointerdown"
296
+ ],
297
+ [
298
+ 3,
299
+ [0, 0],
300
+ "class"
301
+ ],
302
+ [
303
+ 3,
304
+ [0, 0],
305
+ "aria-label"
306
+ ],
307
+ [1, [0, 0]]
308
+ ],
309
+ "segments": [
310
+ { "k": "child" },
311
+ "<div class=\"t-events\"",
312
+ {
313
+ "k": "attr",
314
+ "name": "data-intent-keydown"
315
+ },
316
+ {
317
+ "k": "attr",
318
+ "name": "data-intent-pointermove"
319
+ },
320
+ {
321
+ "k": "attr",
322
+ "name": "data-intent-pointerup"
323
+ },
324
+ {
325
+ "k": "attr",
326
+ "name": "data-intent-pointercancel"
327
+ },
328
+ {
329
+ "k": "attr",
330
+ "name": "data-intent-focusin"
331
+ },
332
+ {
333
+ "k": "attr",
334
+ "name": "data-intent-pointerdown"
335
+ },
336
+ "><div role=\"group\"",
337
+ {
338
+ "k": "attr",
339
+ "name": "class"
340
+ },
341
+ {
342
+ "k": "attr",
343
+ "name": "aria-label"
344
+ },
345
+ ">",
346
+ {
347
+ "k": "child",
348
+ "in": "div"
349
+ },
350
+ "</div></div>"
351
+ ]
352
+ };
353
+ var props = {
354
+ layout: prop.value(isTableLayout, { default: EMPTY_LAYOUT }),
355
+ options: prop.value(isTableOptions, { default: DEFAULT_OPTIONS })
356
+ };
357
+ var emit = outputs();
358
+ var i = intentsOf();
359
+ /** Card flight time when motion is on. */
360
+ var FLIGHT_MS = 180;
361
+ var memories = /* @__PURE__ */ new WeakMap();
362
+ /**
363
+ * Card motion, through the CSSOM (the site's CSP refuses style attributes): a dragged card
364
+ * follows the pointer, and a card that moved between two layouts flies from where it was
365
+ * (a FLIP animation with the Web Animations API). Flights are decoration, skipped with
366
+ * reduced motion and after a drag drop.
367
+ */
368
+ var motion = defineHook({ client: (el, [id, version, calm, dx, dy]) => {
369
+ if (!(el instanceof HTMLElement)) return;
370
+ el.style.translate = dx === 0 && dy === 0 ? "" : `${dx}px ${dy}px`;
371
+ const root = el.getRootNode();
372
+ const host = root instanceof ShadowRoot ? root.host : null;
373
+ if (host === null) return;
374
+ let memory = memories.get(root);
375
+ if (memory === void 0) {
376
+ memory = {
377
+ current: version,
378
+ previous: version,
379
+ spots: /* @__PURE__ */ new Map()
380
+ };
381
+ memories.set(root, memory);
382
+ }
383
+ if (version !== memory.current) {
384
+ memory.previous = memory.current;
385
+ memory.current = version;
386
+ }
387
+ const origin = host.getBoundingClientRect();
388
+ const rect = el.getBoundingClientRect();
389
+ const here = {
390
+ x: rect.left - origin.left,
391
+ y: rect.top - origin.top,
392
+ v: version
393
+ };
394
+ const before = memory.spots.get(id);
395
+ memory.spots.set(id, here);
396
+ if (calm || before === void 0 || before.v !== memory.previous || before.v === version) return;
397
+ const fx = before.x - here.x;
398
+ const fy = before.y - here.y;
399
+ if (Math.abs(fx) < 1 && Math.abs(fy) < 1) return;
400
+ el.animate([{ translate: `${fx}px ${fy}px` }, { translate: "0 0" }], {
401
+ duration: 180,
402
+ easing: "cubic-bezier(0.2, 0.7, 0.3, 1)"
403
+ });
404
+ } });
405
+ var CardRow = (shown, view) => {
406
+ const card = shown.card;
407
+ if (!isFaceCard(card)) return compiled(_gyral$t0, [view.cls, shown.depth]);
408
+ return compiled(_gyral$t1, [
409
+ card.suit,
410
+ view.cls,
411
+ shown.depth,
412
+ motion(card.id, view.version, view.calm, view.dx, view.dy),
413
+ cardFace(card.rank, card.suit)
414
+ ]);
415
+ };
416
+ /** The cards a pile draws: every card in a column; the top few of a stack or fan. */
417
+ var shownCards = (pile) => {
418
+ const n = pile.cards.length;
419
+ const show = pile.fan === "down" ? n : Math.max(1, pile.show ?? (pile.fan === "stack" ? 2 : 3));
420
+ return pile.cards.slice(Math.max(0, n - show)).map((card, k, list) => {
421
+ const depth = list.length - k;
422
+ return {
423
+ key: isFaceCard(card) ? card.id : `down-${n - depth}`,
424
+ card,
425
+ depth
426
+ };
427
+ });
428
+ };
429
+ /** How tightly a column overlaps, by length. */
430
+ var density = (pile) => {
431
+ if (pile.fan !== "down") return 0;
432
+ const n = pile.cards.length;
433
+ return n <= 12 ? 0 : n <= 16 ? 1 : n <= 21 ? 2 : 3;
434
+ };
435
+ /** The cards of `pile` that the current pick-up, drag or hint marks, by depth. */
436
+ var cardClasses = (s, layout, pile, focused, depth) => {
437
+ const { held, press } = s.ctl;
438
+ const parts = [];
439
+ if (held !== null && held.from === pile.id && depth <= held.count) {
440
+ parts.push("held");
441
+ if (press?.dragging === true) parts.push("dragging");
442
+ }
443
+ if (focused && held === null && depth === Math.max(1, Math.min(s.ctl.depth, pile.pickable))) parts.push("pointed");
444
+ const hint = layout.hint;
445
+ if (hint !== null && hint.from === pile.id && depth <= hint.count) parts.push("hinted");
446
+ return parts.join(" ");
447
+ };
448
+ var pileClasses = (s, layout, pile) => {
449
+ const { held, press } = s.ctl;
450
+ const source = held === null ? null : layout.regions.flatMap((r) => r.piles).find((p) => p.id === held.from);
451
+ const target = held !== null && source !== void 0 && source !== null && held.from !== pile.id && source.targets?.[held.count - 1]?.includes(pile.id) === true;
452
+ const parts = [`pile fan-${pile.fan} k-${pile.kind} w-${pile.span ?? 1}`, `dense-${density(pile)}`];
453
+ if (pile.position !== void 0) parts.push(`pos-r-${pile.position.row} pos-c-${Math.round(pile.position.column * 2)}`);
454
+ if (target) parts.push("target");
455
+ if (press?.dragging === true && press.over === pile.id && target) parts.push("over");
456
+ if (layout.hint?.to === pile.id) parts.push("hint-to");
457
+ if (pile.cards.length === 0) parts.push("empty");
458
+ return parts.join(" ");
459
+ };
460
+ var Pile = (s, layout, options, region, r, pile, index) => {
461
+ const remembered = (s.ctl.piles[r] ?? 0) === index;
462
+ const focused = remembered && s.ctl.region === r;
463
+ const quiet = isQuiet(s.ctl, layout, options);
464
+ const press = s.ctl.press;
465
+ const dragging = press?.dragging === true && s.ctl.held?.from === pile.id;
466
+ const held = s.ctl.held;
467
+ const label = held !== null && held.from === pile.id ? `${pile.label} Picked up: ${held.count === 1 ? "top card" : `top ${held.count} cards`}.` : pile.label;
468
+ return compiled(_gyral$t2, [
469
+ pileClasses(s, layout, pile),
470
+ pile.kind,
471
+ remembered ? 0 : -1,
472
+ pile.id,
473
+ region.id,
474
+ label,
475
+ options.singleKeys && pile.key !== void 0 ? pile.key : null,
476
+ pile.kind,
477
+ pile.cards.length === 0 ? pile.mark ?? "" : "",
478
+ each(shownCards(pile), (shown) => shown.key, CardRow, (shown) => ({
479
+ cls: cardClasses(s, layout, pile, focused, shown.depth),
480
+ version: layout.version,
481
+ calm: quiet,
482
+ dx: dragging && held !== null && shown.depth <= held.count ? press?.dx ?? 0 : 0,
483
+ dy: dragging && held !== null && shown.depth <= held.count ? press?.dy ?? 0 : 0
484
+ })),
485
+ pile.badge === void 0 ? nothing : compiled(_gyral$t3, [pile.badge])
486
+ ]);
487
+ };
488
+ var Region = (s, layout, options, region, r) => {
489
+ const span = region.piles.reduce((n, p) => n + (p.span ?? 1), 0);
490
+ return compiled(_gyral$t4, [
491
+ region.place,
492
+ span,
493
+ region.placement === "free" ? "free-placement" : "",
494
+ region.label,
495
+ region.id,
496
+ region.piles.map((pile, index) => Pile(s, layout, options, region, r, pile, index))
497
+ ]);
498
+ };
499
+ /** The pile and card depth under an event's target. */
500
+ var pileAt = (target) => {
501
+ const el = target instanceof Element ? target : null;
502
+ const pile = el?.closest("[data-pile]")?.getAttribute("data-pile") ?? null;
503
+ const depth = Number(el?.closest("[data-depth]")?.getAttribute("data-depth") ?? 0);
504
+ return {
505
+ pile,
506
+ depth: Number.isInteger(depth) ? depth : 0
507
+ };
508
+ };
509
+ /** The pile under a point, ignoring dragged cards (they don't take pointer events). */
510
+ var pileUnder = (inside, x, y) => {
511
+ const root = inside instanceof Node ? inside.getRootNode() : null;
512
+ if (!(root instanceof ShadowRoot)) return null;
513
+ for (const el of root.elementsFromPoint(x, y)) {
514
+ const pile = el.closest("[data-pile]");
515
+ if (pile !== null) return pile.getAttribute("data-pile");
516
+ }
517
+ return null;
518
+ };
519
+ /** Keys the table always handles on a pile; their browser defaults (scrolling) are suppressed. */
520
+ var TABLE_KEYS = /* @__PURE__ */ new Set([
521
+ "ArrowLeft",
522
+ "ArrowRight",
523
+ "ArrowUp",
524
+ "ArrowDown",
525
+ "Home",
526
+ "End",
527
+ "Enter",
528
+ " "
529
+ ]);
530
+ var run = (s, m, layout, options) => {
531
+ const result = step(s.ctl, layout, options, m);
532
+ const commands = result.outs.map((out) => emit(out));
533
+ if (result.focus !== null) commands.push(focus(`[data-pile="${result.focus}"]`));
534
+ return commands.length === 0 ? { ctl: result.ctl } : [{ ctl: result.ctl }, commands];
535
+ };
536
+ var CardTable = define()("jy-card-table", {
537
+ props,
538
+ init: (p) => ({ ctl: initialCtl(p.layout) }),
539
+ renderOnFrame: ["Move"],
540
+ intent: {
541
+ Key: ({ key, event }, { props: { layout, options } }) => {
542
+ if (key === void 0 || !(event instanceof KeyboardEvent)) return void 0;
543
+ if (!(event.target instanceof Element && event.target.hasAttribute("data-pile"))) return void 0;
544
+ const plain = !event.ctrlKey && !event.metaKey && !event.altKey;
545
+ const lower = key.toLowerCase();
546
+ const single = plain && !event.shiftKey && options.singleKeys && (lower >= "0" && lower <= "9" && lower.length === 1 || layout.keys.includes(lower));
547
+ if (plain && TABLE_KEYS.has(key) || single || plain && key === "Escape") event.preventDefault();
548
+ return {
549
+ _tag: "Key",
550
+ key,
551
+ ctrl: event.ctrlKey,
552
+ alt: event.altKey,
553
+ meta: event.metaKey,
554
+ shift: event.shiftKey
555
+ };
556
+ },
557
+ Focus: ({ event }) => {
558
+ const pile = pileAt(event.target).pile;
559
+ return pile === null ? void 0 : {
560
+ _tag: "Focus",
561
+ pile
562
+ };
563
+ },
564
+ Down: ({ event, target }) => {
565
+ if (!(event instanceof PointerEvent) || !event.isPrimary || event.button !== 0) return void 0;
566
+ const at = pileAt(event.target);
567
+ if (at.pile !== null && target instanceof Element && target.isConnected) try {
568
+ target.setPointerCapture(event.pointerId);
569
+ } catch {}
570
+ return {
571
+ _tag: "Down",
572
+ pile: at.pile,
573
+ depth: at.depth,
574
+ x: event.clientX,
575
+ y: event.clientY
576
+ };
577
+ },
578
+ Move: ({ event, target }) => {
579
+ if (!(event instanceof PointerEvent) || !event.isPrimary || event.buttons === 0) return void 0;
580
+ return {
581
+ _tag: "Move",
582
+ x: event.clientX,
583
+ y: event.clientY,
584
+ over: pileUnder(target, event.clientX, event.clientY)
585
+ };
586
+ },
587
+ Up: ({ event, target }) => {
588
+ if (!(event instanceof PointerEvent) || !event.isPrimary) return void 0;
589
+ return {
590
+ _tag: "Up",
591
+ over: pileUnder(target, event.clientX, event.clientY)
592
+ };
593
+ },
594
+ Cancel: () => ({ _tag: "Cancel" })
595
+ },
596
+ update: {
597
+ Key: (s, m, { props: p }) => run(s, m, p.layout, p.options),
598
+ Focus: (s, m, { props: p }) => run(s, m, p.layout, p.options),
599
+ Down: (s, m, { props: p }) => run(s, m, p.layout, p.options),
600
+ Move: (s, m, { props: p }) => run(s, m, p.layout, p.options),
601
+ Up: (s, m, { props: p }) => run(s, m, p.layout, p.options),
602
+ Cancel: (s, m, { props: p }) => run(s, m, p.layout, p.options),
603
+ PropsChanged: (s, { props: p }) => {
604
+ const ctl = sync(s.ctl, p.layout);
605
+ return ctl === s.ctl ? s : { ctl };
606
+ }
607
+ },
608
+ view: (s, _i, { props: p }) => {
609
+ const { layout, options } = p;
610
+ const cls = `table cols-${layout.columns} back-${options.back}${options.fourColor ? " four" : ""}${options.calm ? " calm" : ""}`;
611
+ return compiled(_gyral$t5, [
612
+ suitDefs(),
613
+ i.Key,
614
+ i.Move,
615
+ i.Up,
616
+ i.Cancel,
617
+ i.Focus,
618
+ i.Down,
619
+ cls,
620
+ layout.label,
621
+ layout.regions.map((region, r) => Region(s, layout, options, region, r))
622
+ ]);
623
+ },
624
+ styles: tableStyles
625
+ });
626
+ //#endregion
627
+ export { CardTable, FLIGHT_MS, density, shownCards };
628
+
629
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","names":["_gyral$compiled"],"sources":["../src/table.ts"],"sourcesContent":["import type { ChildValue } from '@gyral/core';\n// <jy-card-table>: the shared card table. A game passes its table as data (`layout`) and the\n// player's preferences (`options`); the table draws the piles with the shared card art and\n// runs the pile controller (controller.ts), so drag and drop, click-to-move, smart moves and\n// the keyboard model behave the same in every card game. It reports what the player asks for\n// as outputs: `Move`, `Smart`, `Activate`, `Key` and `Announce` (listen with `child()`).\n//\n// Each region is a toolbar: one Tab stop, Left and Right between its piles. Each pile is a\n// focusable control named by the game (\"Column 3: 2 face-down cards, then 9 of spades\").\n// Games theme it through inherited custom properties (styles.ts) and two parts per pile kind:\n// `::part(pile-<kind>)` for the pile (custom properties set there reach its cards, so\n// `--card-w` and `--card-h` make a pile's cards smaller) and `::part(slot-<kind>)` for the\n// outline an empty pile shows.\nimport { defineHook, define, each, focus, html, intentsOf, nothing, outputs, prop, type Command } from '@gyral/core';\nimport {\n DEFAULT_OPTIONS,\n EMPTY_LAYOUT,\n isFaceCard,\n isTableLayout,\n isTableOptions,\n type PileCard,\n type PileSpec,\n type RegionSpec,\n type TableLayout,\n type TableOptions,\n} from './layout.ts';\nimport { initialCtl, isQuiet, step, sync, type Ctl, type CtlMsg, type TableOut } from './controller.ts';\nimport { cardFace, suitDefs } from './faces.ts';\nimport { tableStyles } from './styles.ts';\n\nconst props = {\n layout: prop.value(isTableLayout, { default: EMPTY_LAYOUT }),\n options: prop.value(isTableOptions, { default: DEFAULT_OPTIONS }),\n};\n\nexport type TableProps = { readonly layout: TableLayout; readonly options: TableOptions };\n\nexport type TableState = { readonly ctl: Ctl };\n\nexport type TableMsg = CtlMsg;\n\nconst emit = outputs<TableOut>();\nconst i = intentsOf<typeof CardTable>();\n\n/** Card flight time when motion is on. */\nexport const FLIGHT_MS = 180;\n\ntype Spot = { readonly x: number; readonly y: number; readonly v: number };\ntype Memory = { current: number; previous: number; spots: Map<string, Spot> };\nconst memories = new WeakMap<Node, Memory>();\n\n/**\n * Card motion, through the CSSOM (the site's CSP refuses style attributes): a dragged card\n * follows the pointer, and a card that moved between two layouts flies from where it was\n * (a FLIP animation with the Web Animations API). Flights are decoration, skipped with\n * reduced motion and after a drag drop.\n */\nconst motion = defineHook<[id: string, version: number, calm: boolean, dx: number, dy: number]>({\n client: (el, [id, version, calm, dx, dy]) => {\n if (!(el instanceof HTMLElement)) return;\n el.style.translate = dx === 0 && dy === 0 ? '' : `${dx}px ${dy}px`;\n const root = el.getRootNode();\n const host = root instanceof ShadowRoot ? root.host : null;\n if (host === null) return;\n let memory = memories.get(root);\n if (memory === undefined) {\n memory = { current: version, previous: version, spots: new Map() };\n memories.set(root, memory);\n }\n if (version !== memory.current) {\n memory.previous = memory.current;\n memory.current = version;\n }\n const origin = host.getBoundingClientRect();\n const rect = el.getBoundingClientRect();\n const here: Spot = { x: rect.left - origin.left, y: rect.top - origin.top, v: version };\n const before = memory.spots.get(id);\n memory.spots.set(id, here);\n if (calm || before === undefined || before.v !== memory.previous || before.v === version) return;\n const fx = before.x - here.x;\n const fy = before.y - here.y;\n if (Math.abs(fx) < 1 && Math.abs(fy) < 1) return;\n el.animate([{ translate: `${fx}px ${fy}px` }, { translate: '0 0' }], {\n duration: FLIGHT_MS,\n easing: 'cubic-bezier(0.2, 0.7, 0.3, 1)',\n });\n },\n});\n\n/** What one card row needs beyond the card: its depth and classes, and the motion inputs. */\ntype CardView = {\n readonly cls: string;\n readonly version: number;\n readonly calm: boolean;\n readonly dx: number;\n readonly dy: number;\n};\n\ntype Shown = { readonly key: string; readonly card: PileCard; readonly depth: number };\n\nconst CardRow = (shown: Shown, view: CardView) => {\n const card = shown.card;\n if (!isFaceCard(card)) return html`<div class=\"card down ${view.cls}\" data-depth=${shown.depth}></div>`;\n return html`<div class=\"card up s-${card.suit} ${view.cls}\" data-depth=${shown.depth} ${motion(card.id, view.version, view.calm, view.dx, view.dy)}>\n ${cardFace(card.rank, card.suit)}\n </div>`;\n};\n\n/** The cards a pile draws: every card in a column; the top few of a stack or fan. */\nexport const shownCards = (pile: PileSpec): Shown[] => {\n const n = pile.cards.length;\n const show = pile.fan === 'down' ? n : Math.max(1, pile.show ?? (pile.fan === 'stack' ? 2 : 3));\n return pile.cards.slice(Math.max(0, n - show)).map((card, k, list) => {\n const depth = list.length - k;\n return { key: isFaceCard(card) ? card.id : `down-${n - depth}`, card, depth };\n });\n};\n\n/** How tightly a column overlaps, by length. */\nexport const density = (pile: PileSpec): number => {\n if (pile.fan !== 'down') return 0;\n const n = pile.cards.length;\n return n <= 12 ? 0 : n <= 16 ? 1 : n <= 21 ? 2 : 3;\n};\n\n/** The cards of `pile` that the current pick-up, drag or hint marks, by depth. */\nconst cardClasses = (s: TableState, layout: TableLayout, pile: PileSpec, focused: boolean, depth: number): string => {\n const { held, press } = s.ctl;\n const parts: string[] = [];\n if (held !== null && held.from === pile.id && depth <= held.count) {\n parts.push('held');\n if (press?.dragging === true) parts.push('dragging');\n }\n if (focused && held === null && depth === Math.max(1, Math.min(s.ctl.depth, pile.pickable))) parts.push('pointed');\n const hint = layout.hint;\n if (hint !== null && hint.from === pile.id && depth <= hint.count) parts.push('hinted');\n return parts.join(' ');\n};\n\nconst pileClasses = (s: TableState, layout: TableLayout, pile: PileSpec): string => {\n const { held, press } = s.ctl;\n const source = held === null ? null : layout.regions.flatMap((r) => r.piles).find((p) => p.id === held.from);\n const target =\n held !== null &&\n source !== undefined &&\n source !== null &&\n held.from !== pile.id &&\n source.targets?.[held.count - 1]?.includes(pile.id) === true;\n const parts = [`pile fan-${pile.fan} k-${pile.kind} w-${pile.span ?? 1}`, `dense-${density(pile)}`];\n if (pile.position !== undefined)\n parts.push(`pos-r-${pile.position.row} pos-c-${Math.round(pile.position.column * 2)}`);\n if (target) parts.push('target');\n if (press?.dragging === true && press.over === pile.id && target) parts.push('over');\n if (layout.hint?.to === pile.id) parts.push('hint-to');\n if (pile.cards.length === 0) parts.push('empty');\n return parts.join(' ');\n};\n\nconst Pile = (\n s: TableState,\n layout: TableLayout,\n options: TableOptions,\n region: RegionSpec,\n r: number,\n pile: PileSpec,\n index: number,\n) => {\n const remembered = (s.ctl.piles[r] ?? 0) === index;\n const focused = remembered && s.ctl.region === r;\n const quiet = isQuiet(s.ctl, layout, options);\n const press = s.ctl.press;\n const dragging = press?.dragging === true && s.ctl.held?.from === pile.id;\n const held = s.ctl.held;\n const heldHere = held !== null && held.from === pile.id;\n const label = heldHere\n ? `${pile.label} Picked up: ${held.count === 1 ? 'top card' : `top ${held.count} cards`}.`\n : pile.label;\n return html`<div\n class=${pileClasses(s, layout, pile)}\n part=\"pile pile-${pile.kind}\"\n role=\"button\"\n tabindex=${remembered ? 0 : -1}\n data-pile=${pile.id}\n data-region=${region.id}\n aria-label=${label}\n aria-keyshortcuts=${options.singleKeys && pile.key !== undefined ? pile.key : null}\n >\n <span class=\"slot\" part=\"slot slot-${pile.kind}\" aria-hidden=\"true\">${pile.cards.length === 0 ? (pile.mark ?? '') : ''}</span>\n ${each(\n shownCards(pile),\n (shown) => shown.key,\n CardRow,\n (shown): CardView => ({\n cls: cardClasses(s, layout, pile, focused, shown.depth),\n version: layout.version,\n calm: quiet,\n dx: dragging && held !== null && shown.depth <= held.count ? (press?.dx ?? 0) : 0,\n dy: dragging && held !== null && shown.depth <= held.count ? (press?.dy ?? 0) : 0,\n }),\n )}\n <span class=\"drop\" aria-hidden=\"true\"></span>\n ${pile.badge === undefined ? nothing : html`<span class=\"pile-badge\" aria-hidden=\"true\">${pile.badge}</span>`}\n </div>`;\n};\n\nconst Region = (s: TableState, layout: TableLayout, options: TableOptions, region: RegionSpec, r: number) => {\n const span = region.piles.reduce((n, p) => n + (p.span ?? 1), 0);\n return html`<div class=\"region at-${region.place} n-${span} ${region.placement === 'free' ? 'free-placement' : ''}\" role=\"toolbar\" aria-label=${region.label} data-region=${region.id}>\n ${region.piles.map((pile, index) => Pile(s, layout, options, region, r, pile, index))}\n </div>`;\n};\n\n/** The pile and card depth under an event's target. */\nconst pileAt = (target: EventTarget | null): { readonly pile: string | null; readonly depth: number } => {\n const el = target instanceof Element ? target : null;\n const pile = el?.closest('[data-pile]')?.getAttribute('data-pile') ?? null;\n const depth = Number(el?.closest('[data-depth]')?.getAttribute('data-depth') ?? 0);\n return { pile, depth: Number.isInteger(depth) ? depth : 0 };\n};\n\n/** The pile under a point, ignoring dragged cards (they don't take pointer events). */\nconst pileUnder = (inside: EventTarget | null, x: number, y: number): string | null => {\n const root = inside instanceof Node ? inside.getRootNode() : null;\n if (!(root instanceof ShadowRoot)) return null;\n for (const el of root.elementsFromPoint(x, y)) {\n const pile = el.closest('[data-pile]');\n if (pile !== null) return pile.getAttribute('data-pile');\n }\n return null;\n};\n\n/** Keys the table always handles on a pile; their browser defaults (scrolling) are suppressed. */\nconst TABLE_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End', 'Enter', ' ']);\n\nconst run = (\n s: TableState,\n m: TableMsg,\n layout: TableLayout,\n options: TableOptions,\n): TableState | readonly [TableState, Command<TableMsg>[]] => {\n const result = step(s.ctl, layout, options, m);\n const commands: Command<TableMsg>[] = result.outs.map((out) => emit(out));\n if (result.focus !== null) commands.push(focus(`[data-pile=\"${result.focus}\"]`));\n return commands.length === 0 ? { ctl: result.ctl } : [{ ctl: result.ctl }, commands];\n};\n\nexport const CardTable = define<TableState, TableMsg, TableProps, TableOut>()('jy-card-table', {\n props,\n init: (p) => ({ ctl: initialCtl(p.layout) }),\n renderOnFrame: ['Move'],\n intent: {\n Key: ({ key, event }, { props: { layout, options } }) => {\n if (key === undefined || !(event instanceof KeyboardEvent)) return undefined;\n const onPile = event.target instanceof Element && event.target.hasAttribute('data-pile');\n if (!onPile) return undefined;\n const plain = !event.ctrlKey && !event.metaKey && !event.altKey;\n const lower = key.toLowerCase();\n const single =\n plain &&\n !event.shiftKey &&\n options.singleKeys &&\n ((lower >= '0' && lower <= '9' && lower.length === 1) || layout.keys.includes(lower));\n if ((plain && TABLE_KEYS.has(key)) || single || (plain && key === 'Escape')) event.preventDefault();\n return { _tag: 'Key', key, ctrl: event.ctrlKey, alt: event.altKey, meta: event.metaKey, shift: event.shiftKey };\n },\n Focus: ({ event }) => {\n const pile = pileAt(event.target).pile;\n return pile === null ? undefined : { _tag: 'Focus', pile };\n },\n Down: ({ event, target }) => {\n if (!(event instanceof PointerEvent) || !event.isPrimary || event.button !== 0) return undefined;\n const at = pileAt(event.target);\n // Capture on the event wrapper so a drag that leaves the table still ends here.\n if (at.pile !== null && target instanceof Element && target.isConnected) {\n try {\n target.setPointerCapture(event.pointerId);\n } catch {\n // A synthetic event has no active pointer to capture; the drag still works inside the table.\n }\n }\n return { _tag: 'Down', pile: at.pile, depth: at.depth, x: event.clientX, y: event.clientY };\n },\n Move: ({ event, target }) => {\n if (!(event instanceof PointerEvent) || !event.isPrimary || event.buttons === 0) return undefined;\n return {\n _tag: 'Move',\n x: event.clientX,\n y: event.clientY,\n over: pileUnder(target, event.clientX, event.clientY),\n };\n },\n Up: ({ event, target }) => {\n if (!(event instanceof PointerEvent) || !event.isPrimary) return undefined;\n return { _tag: 'Up', over: pileUnder(target, event.clientX, event.clientY) };\n },\n Cancel: () => ({ _tag: 'Cancel' }),\n },\n update: {\n Key: (s, m, { props: p }) => run(s, m, p.layout, p.options),\n Focus: (s, m, { props: p }) => run(s, m, p.layout, p.options),\n Down: (s, m, { props: p }) => run(s, m, p.layout, p.options),\n Move: (s, m, { props: p }) => run(s, m, p.layout, p.options),\n Up: (s, m, { props: p }) => run(s, m, p.layout, p.options),\n Cancel: (s, m, { props: p }) => run(s, m, p.layout, p.options),\n PropsChanged: (s, { props: p }) => {\n const ctl = sync(s.ctl, p.layout);\n return ctl === s.ctl ? s : { ctl };\n },\n },\n view: (s, _i, { props: p }): ChildValue => {\n const { layout, options } = p;\n const cls = `table cols-${layout.columns} back-${options.back}${options.fourColor ? ' four' : ''}${options.calm ? ' calm' : ''}`;\n return html`${suitDefs()}\n <div class=\"t-events\" data-intent-keydown=${i.Key} data-intent-pointermove=${i.Move}\n data-intent-pointerup=${i.Up} data-intent-pointercancel=${i.Cancel}\n data-intent-focusin=${i.Focus} data-intent-pointerdown=${i.Down}>\n <div class=${cls} role=\"group\" aria-label=${layout.label}>${layout.regions.map((region, r) => Region(s, layout, options, region, r))}</div>\n </div>`;\n },\n styles: tableStyles,\n});\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'jy-card-table': InstanceType<typeof CardTable>;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type ChildValue } from '@gyral/core';
2
+ import { type TileFace } from '@joystyk/kit/tiles';
3
+ export declare const tileFace: (tile: TileFace, numbers?: boolean) => ChildValue;