@joystyk/cards-ui 0.0.0 → 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/CHANGELOG.md +22 -0
- package/README.md +30 -2
- package/dist/controller.d.ts +110 -0
- package/dist/controller.js +449 -0
- package/dist/controller.js.map +1 -0
- package/dist/face-styles.d.ts +1 -0
- package/dist/face-styles.js +106 -0
- package/dist/face-styles.js.map +1 -0
- package/dist/faces.d.ts +11 -0
- package/dist/faces.js +403 -0
- package/dist/faces.js.map +1 -0
- package/dist/hand-styles.d.ts +1 -0
- package/dist/hand-styles.js +121 -0
- package/dist/hand-styles.js.map +1 -0
- package/dist/hand.d.ts +100 -0
- package/dist/hand.js +480 -0
- package/dist/hand.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +9 -0
- package/dist/layout.d.ts +122 -0
- package/dist/layout.js +35 -0
- package/dist/layout.js.map +1 -0
- package/dist/solitaire.d.ts +155 -0
- package/dist/solitaire.js +1508 -0
- package/dist/solitaire.js.map +1 -0
- package/dist/styles.d.ts +1 -0
- package/dist/styles.js +452 -0
- package/dist/styles.js.map +1 -0
- package/dist/table.d.ts +28 -0
- package/dist/table.js +629 -0
- package/dist/table.js.map +1 -0
- package/dist/tiles.d.ts +3 -0
- package/dist/tiles.js +157 -0
- package/dist/tiles.js.map +1 -0
- package/dist/worker-setup.d.ts +7 -0
- package/dist/worker-setup.js +45 -0
- package/dist/worker-setup.js.map +1 -0
- package/package.json +61 -11
package/dist/layout.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Rank, Suit } from '@joystyk/kit/cards';
|
|
2
|
+
/** A face-up card: its stable id (an animation key) and its face. */
|
|
3
|
+
export type FaceCard = {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly rank: Rank;
|
|
6
|
+
readonly suit: Suit;
|
|
7
|
+
};
|
|
8
|
+
/** A face-down card. It carries no id, so nothing about it reaches the page. */
|
|
9
|
+
export type DownCard = {
|
|
10
|
+
readonly hidden: true;
|
|
11
|
+
};
|
|
12
|
+
export type PileCard = FaceCard | DownCard;
|
|
13
|
+
/**
|
|
14
|
+
* How a pile shows its cards:
|
|
15
|
+
* - `down`: a column, each card lower than the last, so every face-up card shows its strip;
|
|
16
|
+
* - `right`: fanned to the right (a draw-3 waste, completed runs), showing the last `show`;
|
|
17
|
+
* - `stack`: squared up, only the top card visible (stock, foundations, free cells).
|
|
18
|
+
*/
|
|
19
|
+
export type Fan = 'down' | 'right' | 'stack';
|
|
20
|
+
export type PileSpec = {
|
|
21
|
+
/** Unique within the table: `t3`, `waste`, `f0`. Moves name piles by it. */
|
|
22
|
+
readonly id: string;
|
|
23
|
+
/** The accessible name, already in words: "Column 3: 2 face-down cards, then 9 of spades." */
|
|
24
|
+
readonly label: string;
|
|
25
|
+
/** Bottom to top. */
|
|
26
|
+
readonly cards: readonly PileCard[];
|
|
27
|
+
readonly fan: Fan;
|
|
28
|
+
/** For `right` and `stack`: how many cards from the top are drawn. Default 1 for a stack, 3 fanned. */
|
|
29
|
+
readonly show?: number;
|
|
30
|
+
/** How many cards from the top may be picked up together; 0 for none. */
|
|
31
|
+
readonly pickable: number;
|
|
32
|
+
/** Said when the player asks for more cards than `pickable` (Spider: "different suits"). */
|
|
33
|
+
readonly limit?: string;
|
|
34
|
+
/** Legal destinations by pick-up size: `targets[k - 1]` lists the piles `k` cards may go to. */
|
|
35
|
+
readonly targets?: readonly (readonly string[])[];
|
|
36
|
+
/** Clicking the pile, or Enter on it, runs its action instead of picking up (the stock). */
|
|
37
|
+
readonly action?: boolean;
|
|
38
|
+
/** What an empty pile shows: "A" on a foundation, "K" on a column, "↺" on a stock that can redeal. */
|
|
39
|
+
readonly mark?: string;
|
|
40
|
+
/** A styling hook for the game's theme: `stock`, `waste`, `foundation`, `column`, `cell`, `runs`. */
|
|
41
|
+
readonly kind: string;
|
|
42
|
+
/** The number key that jumps to this pile: "1" … "9", "0". */
|
|
43
|
+
readonly key?: string;
|
|
44
|
+
/** How many grid columns the pile spans. Default 1. */
|
|
45
|
+
readonly span?: number;
|
|
46
|
+
/** Said after "Picked up …" from this pile: "Up to 5 can move." */
|
|
47
|
+
readonly note?: string;
|
|
48
|
+
/** Half-card horizontal steps and half-card rows in a freely placed region. */
|
|
49
|
+
readonly position?: {
|
|
50
|
+
readonly row: number;
|
|
51
|
+
readonly column: number;
|
|
52
|
+
};
|
|
53
|
+
/** A visible, non-color cue, such as a Pyramid partner's value. */
|
|
54
|
+
readonly badge?: string;
|
|
55
|
+
/** Up/Down reads individual cards without changing the one-card action. */
|
|
56
|
+
readonly inspect?: boolean;
|
|
57
|
+
};
|
|
58
|
+
/** Where a region sits on the table grid. Tab order follows the region list, not the place. */
|
|
59
|
+
export type Place = 'top-start' | 'top-end' | 'main' | 'bottom-start' | 'bottom-end';
|
|
60
|
+
export type RegionSpec = {
|
|
61
|
+
readonly id: string;
|
|
62
|
+
/** "Stock and waste", "Foundations", "Tableau". */
|
|
63
|
+
readonly label: string;
|
|
64
|
+
readonly place: Place;
|
|
65
|
+
readonly piles: readonly PileSpec[];
|
|
66
|
+
readonly placement?: 'free';
|
|
67
|
+
};
|
|
68
|
+
/** A suggested move, outlined on the table. */
|
|
69
|
+
export type HintSpec = {
|
|
70
|
+
readonly from: string;
|
|
71
|
+
readonly to: string;
|
|
72
|
+
readonly count: number;
|
|
73
|
+
};
|
|
74
|
+
export type TableLayout = {
|
|
75
|
+
/** The table's name: "Klondike table". */
|
|
76
|
+
readonly label: string;
|
|
77
|
+
/** Grid columns the cards are sized for: 7 for Klondike, 8 for FreeCell, 10 for Spider. */
|
|
78
|
+
readonly columns: number;
|
|
79
|
+
readonly regions: readonly RegionSpec[];
|
|
80
|
+
readonly hint: HintSpec | null;
|
|
81
|
+
/**
|
|
82
|
+
* Single-key shortcuts that act on the focused pile (Klondike's `F`, FreeCell's `C`). The
|
|
83
|
+
* table reports them as `Key` outputs with the pile and count; other keys bubble to the game.
|
|
84
|
+
*/
|
|
85
|
+
readonly keys: readonly string[];
|
|
86
|
+
/** Number shortcuts activate the named pile (rather than just focusing it). */
|
|
87
|
+
readonly activateNumbers?: boolean;
|
|
88
|
+
/** Changes whenever the cards do (the session revision). A change drops any pick-up. */
|
|
89
|
+
readonly version: number;
|
|
90
|
+
};
|
|
91
|
+
/** Card backs: Klondike's lattice, Spider's fine-line web, FreeCell's cells. All original. */
|
|
92
|
+
export type Back = 'lattice' | 'web' | 'cells' | 'terraces' | 'contours' | 'dunes';
|
|
93
|
+
export type TableOptions = {
|
|
94
|
+
/** WCAG 2.1.4: false turns off number keys and the layout's single-key shortcuts. */
|
|
95
|
+
readonly singleKeys: boolean;
|
|
96
|
+
/** Reduced motion: cards move instantly. */
|
|
97
|
+
readonly calm: boolean;
|
|
98
|
+
/** Blue diamonds and green clubs, for players who struggle with red and black. */
|
|
99
|
+
readonly fourColor: boolean;
|
|
100
|
+
readonly back: Back;
|
|
101
|
+
};
|
|
102
|
+
export declare const DEFAULT_OPTIONS: TableOptions;
|
|
103
|
+
export declare const EMPTY_LAYOUT: TableLayout;
|
|
104
|
+
export declare const isFaceCard: (card: PileCard | undefined) => card is FaceCard;
|
|
105
|
+
/** A light shape check for the `layout` property (development builds validate properties). */
|
|
106
|
+
export declare const isTableLayout: (value: unknown) => value is TableLayout;
|
|
107
|
+
export declare const isTableOptions: (value: unknown) => value is TableOptions;
|
|
108
|
+
/** Every pile with its region index and position, in Tab order. */
|
|
109
|
+
export declare const allPiles: (layout: TableLayout) => readonly {
|
|
110
|
+
readonly region: number;
|
|
111
|
+
readonly index: number;
|
|
112
|
+
readonly pile: PileSpec;
|
|
113
|
+
}[];
|
|
114
|
+
export declare const findPile: (layout: TableLayout, id: string) => {
|
|
115
|
+
readonly region: number;
|
|
116
|
+
readonly index: number;
|
|
117
|
+
readonly pile: PileSpec;
|
|
118
|
+
} | null;
|
|
119
|
+
/** The face-up cards at the top of a pile, `count` of them, bottom first. */
|
|
120
|
+
export declare const topCards: (pile: PileSpec, count: number) => FaceCard[];
|
|
121
|
+
/** True when `count` cards from `from` may go to `to`. */
|
|
122
|
+
export declare const isTarget: (pile: PileSpec, count: number, to: string) => boolean;
|
package/dist/layout.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/layout.ts
|
|
2
|
+
var DEFAULT_OPTIONS = {
|
|
3
|
+
singleKeys: true,
|
|
4
|
+
calm: false,
|
|
5
|
+
fourColor: false,
|
|
6
|
+
back: "lattice"
|
|
7
|
+
};
|
|
8
|
+
var EMPTY_LAYOUT = {
|
|
9
|
+
label: "Card table",
|
|
10
|
+
columns: 7,
|
|
11
|
+
regions: [],
|
|
12
|
+
hint: null,
|
|
13
|
+
keys: [],
|
|
14
|
+
version: 0
|
|
15
|
+
};
|
|
16
|
+
var isFaceCard = (card) => card !== void 0 && !("hidden" in card);
|
|
17
|
+
var isRecord = (value) => typeof value === "object" && value !== null;
|
|
18
|
+
/** A light shape check for the `layout` property (development builds validate properties). */
|
|
19
|
+
var isTableLayout = (value) => isRecord(value) && typeof value["label"] === "string" && typeof value["columns"] === "number" && Array.isArray(value["regions"]) && typeof value["version"] === "number";
|
|
20
|
+
var isTableOptions = (value) => isRecord(value) && typeof value["singleKeys"] === "boolean" && typeof value["calm"] === "boolean" && typeof value["fourColor"] === "boolean" && typeof value["back"] === "string";
|
|
21
|
+
/** Every pile with its region index and position, in Tab order. */
|
|
22
|
+
var allPiles = (layout) => layout.regions.flatMap((region, r) => region.piles.map((pile, index) => ({
|
|
23
|
+
region: r,
|
|
24
|
+
index,
|
|
25
|
+
pile
|
|
26
|
+
})));
|
|
27
|
+
var findPile = (layout, id) => allPiles(layout).find((entry) => entry.pile.id === id) ?? null;
|
|
28
|
+
/** The face-up cards at the top of a pile, `count` of them, bottom first. */
|
|
29
|
+
var topCards = (pile, count) => pile.cards.slice(Math.max(0, pile.cards.length - count)).filter(isFaceCard);
|
|
30
|
+
/** True when `count` cards from `from` may go to `to`. */
|
|
31
|
+
var isTarget = (pile, count, to) => pile.targets?.[count - 1]?.includes(to) === true;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { DEFAULT_OPTIONS, EMPTY_LAYOUT, allPiles, findPile, isFaceCard, isTableLayout, isTableOptions, isTarget, topCards };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","names":[],"sources":["../src/layout.ts"],"sourcesContent":["// The table a card game hands to <jy-card-table>: regions of piles, each pile's cards bottom\n// to top, and what the player may do with them. It is plain JSON built from the game's view\n// on every snapshot, so the table never needs the rules: the game says how many cards a pile\n// lets go of and where each pick-up may land, and the table turns pointer and keyboard input\n// into moves (klondike.md, \"Interaction and accessibility\").\nimport type { Rank, Suit } from '@joystyk/kit/cards';\n\n/** A face-up card: its stable id (an animation key) and its face. */\nexport type FaceCard = { readonly id: string; readonly rank: Rank; readonly suit: Suit };\n\n/** A face-down card. It carries no id, so nothing about it reaches the page. */\nexport type DownCard = { readonly hidden: true };\n\nexport type PileCard = FaceCard | DownCard;\n\n/**\n * How a pile shows its cards:\n * - `down`: a column, each card lower than the last, so every face-up card shows its strip;\n * - `right`: fanned to the right (a draw-3 waste, completed runs), showing the last `show`;\n * - `stack`: squared up, only the top card visible (stock, foundations, free cells).\n */\nexport type Fan = 'down' | 'right' | 'stack';\n\nexport type PileSpec = {\n /** Unique within the table: `t3`, `waste`, `f0`. Moves name piles by it. */\n readonly id: string;\n /** The accessible name, already in words: \"Column 3: 2 face-down cards, then 9 of spades.\" */\n readonly label: string;\n /** Bottom to top. */\n readonly cards: readonly PileCard[];\n readonly fan: Fan;\n /** For `right` and `stack`: how many cards from the top are drawn. Default 1 for a stack, 3 fanned. */\n readonly show?: number;\n /** How many cards from the top may be picked up together; 0 for none. */\n readonly pickable: number;\n /** Said when the player asks for more cards than `pickable` (Spider: \"different suits\"). */\n readonly limit?: string;\n /** Legal destinations by pick-up size: `targets[k - 1]` lists the piles `k` cards may go to. */\n readonly targets?: readonly (readonly string[])[];\n /** Clicking the pile, or Enter on it, runs its action instead of picking up (the stock). */\n readonly action?: boolean;\n /** What an empty pile shows: \"A\" on a foundation, \"K\" on a column, \"↺\" on a stock that can redeal. */\n readonly mark?: string;\n /** A styling hook for the game's theme: `stock`, `waste`, `foundation`, `column`, `cell`, `runs`. */\n readonly kind: string;\n /** The number key that jumps to this pile: \"1\" … \"9\", \"0\". */\n readonly key?: string;\n /** How many grid columns the pile spans. Default 1. */\n readonly span?: number;\n /** Said after \"Picked up …\" from this pile: \"Up to 5 can move.\" */\n readonly note?: string;\n /** Half-card horizontal steps and half-card rows in a freely placed region. */\n readonly position?: { readonly row: number; readonly column: number };\n /** A visible, non-color cue, such as a Pyramid partner's value. */\n readonly badge?: string;\n /** Up/Down reads individual cards without changing the one-card action. */\n readonly inspect?: boolean;\n};\n\n/** Where a region sits on the table grid. Tab order follows the region list, not the place. */\nexport type Place = 'top-start' | 'top-end' | 'main' | 'bottom-start' | 'bottom-end';\n\nexport type RegionSpec = {\n readonly id: string;\n /** \"Stock and waste\", \"Foundations\", \"Tableau\". */\n readonly label: string;\n readonly place: Place;\n readonly piles: readonly PileSpec[];\n readonly placement?: 'free';\n};\n\n/** A suggested move, outlined on the table. */\nexport type HintSpec = { readonly from: string; readonly to: string; readonly count: number };\n\nexport type TableLayout = {\n /** The table's name: \"Klondike table\". */\n readonly label: string;\n /** Grid columns the cards are sized for: 7 for Klondike, 8 for FreeCell, 10 for Spider. */\n readonly columns: number;\n readonly regions: readonly RegionSpec[];\n readonly hint: HintSpec | null;\n /**\n * Single-key shortcuts that act on the focused pile (Klondike's `F`, FreeCell's `C`). The\n * table reports them as `Key` outputs with the pile and count; other keys bubble to the game.\n */\n readonly keys: readonly string[];\n /** Number shortcuts activate the named pile (rather than just focusing it). */\n readonly activateNumbers?: boolean;\n /** Changes whenever the cards do (the session revision). A change drops any pick-up. */\n readonly version: number;\n};\n\n/** Card backs: Klondike's lattice, Spider's fine-line web, FreeCell's cells. All original. */\nexport type Back = 'lattice' | 'web' | 'cells' | 'terraces' | 'contours' | 'dunes';\n\nexport type TableOptions = {\n /** WCAG 2.1.4: false turns off number keys and the layout's single-key shortcuts. */\n readonly singleKeys: boolean;\n /** Reduced motion: cards move instantly. */\n readonly calm: boolean;\n /** Blue diamonds and green clubs, for players who struggle with red and black. */\n readonly fourColor: boolean;\n readonly back: Back;\n};\n\nexport const DEFAULT_OPTIONS: TableOptions = { singleKeys: true, calm: false, fourColor: false, back: 'lattice' };\n\nexport const EMPTY_LAYOUT: TableLayout = {\n label: 'Card table',\n columns: 7,\n regions: [],\n hint: null,\n keys: [],\n version: 0,\n};\n\nexport const isFaceCard = (card: PileCard | undefined): card is FaceCard => card !== undefined && !('hidden' in card);\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null;\n\n/** A light shape check for the `layout` property (development builds validate properties). */\nexport const isTableLayout = (value: unknown): value is TableLayout =>\n isRecord(value) &&\n typeof value['label'] === 'string' &&\n typeof value['columns'] === 'number' &&\n Array.isArray(value['regions']) &&\n typeof value['version'] === 'number';\n\nexport const isTableOptions = (value: unknown): value is TableOptions =>\n isRecord(value) &&\n typeof value['singleKeys'] === 'boolean' &&\n typeof value['calm'] === 'boolean' &&\n typeof value['fourColor'] === 'boolean' &&\n typeof value['back'] === 'string';\n\n/** Every pile with its region index and position, in Tab order. */\nexport const allPiles = (\n layout: TableLayout,\n): readonly { readonly region: number; readonly index: number; readonly pile: PileSpec }[] =>\n layout.regions.flatMap((region, r) => region.piles.map((pile, index) => ({ region: r, index, pile })));\n\nexport const findPile = (\n layout: TableLayout,\n id: string,\n): { readonly region: number; readonly index: number; readonly pile: PileSpec } | null =>\n allPiles(layout).find((entry) => entry.pile.id === id) ?? null;\n\n/** The face-up cards at the top of a pile, `count` of them, bottom first. */\nexport const topCards = (pile: PileSpec, count: number): FaceCard[] =>\n pile.cards.slice(Math.max(0, pile.cards.length - count)).filter(isFaceCard);\n\n/** True when `count` cards from `from` may go to `to`. */\nexport const isTarget = (pile: PileSpec, count: number, to: string): boolean =>\n pile.targets?.[count - 1]?.includes(to) === true;\n"],"mappings":";AAyGA,IAAa,kBAAgC;CAAE,YAAY;CAAM,MAAM;CAAO,WAAW;CAAO,MAAM;AAAU;AAEhH,IAAa,eAA4B;CACvC,OAAO;CACP,SAAS;CACT,SAAS,CAAC;CACV,MAAM;CACN,MAAM,CAAC;CACP,SAAS;AACX;AAEA,IAAa,cAAc,SAAiD,SAAS,KAAA,KAAa,EAAE,YAAY;AAEhH,IAAM,YAAY,UAAqD,OAAO,UAAU,YAAY,UAAU;;AAG9G,IAAa,iBAAiB,UAC5B,SAAS,KAAK,KACd,OAAO,MAAM,aAAa,YAC1B,OAAO,MAAM,eAAe,YAC5B,MAAM,QAAQ,MAAM,UAAU,KAC9B,OAAO,MAAM,eAAe;AAE9B,IAAa,kBAAkB,UAC7B,SAAS,KAAK,KACd,OAAO,MAAM,kBAAkB,aAC/B,OAAO,MAAM,YAAY,aACzB,OAAO,MAAM,iBAAiB,aAC9B,OAAO,MAAM,YAAY;;AAG3B,IAAa,YACX,WAEA,OAAO,QAAQ,SAAS,QAAQ,MAAM,OAAO,MAAM,KAAK,MAAM,WAAW;CAAE,QAAQ;CAAG;CAAO;AAAK,EAAE,CAAC;AAEvG,IAAa,YACX,QACA,OAEA,SAAS,MAAM,CAAC,CAAC,MAAM,UAAU,MAAM,KAAK,OAAO,EAAE,KAAK;;AAG5D,IAAa,YAAY,MAAgB,UACvC,KAAK,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,SAAS,KAAK,CAAC,CAAC,CAAC,OAAO,UAAU;;AAG5E,IAAa,YAAY,MAAgB,OAAe,OACtD,KAAK,UAAU,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { type AnyGameSession, type Json, type Mounted, type PlatformApi, type Preferences, type Validator } from '@joystyk/contracts';
|
|
2
|
+
import { type Back, type TableLayout, type TableOptions } from './layout.js';
|
|
3
|
+
import type { TableOut } from './controller.js';
|
|
4
|
+
export type SetupField = {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly label: string;
|
|
7
|
+
readonly value: string;
|
|
8
|
+
readonly choices?: readonly {
|
|
9
|
+
readonly value: string;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
}[];
|
|
12
|
+
};
|
|
13
|
+
export type SolitaireData = {
|
|
14
|
+
readonly title: string;
|
|
15
|
+
readonly theme: 'noon' | 'dawn' | 'dusk';
|
|
16
|
+
readonly back: Back;
|
|
17
|
+
readonly layout: TableLayout;
|
|
18
|
+
readonly status: string;
|
|
19
|
+
readonly line: string;
|
|
20
|
+
readonly meters: readonly {
|
|
21
|
+
readonly label: string;
|
|
22
|
+
readonly value: string;
|
|
23
|
+
}[];
|
|
24
|
+
readonly fields: readonly SetupField[];
|
|
25
|
+
readonly setupAllowed: boolean;
|
|
26
|
+
readonly actions: readonly {
|
|
27
|
+
readonly label: string;
|
|
28
|
+
readonly command: Json;
|
|
29
|
+
readonly disabled: boolean;
|
|
30
|
+
}[];
|
|
31
|
+
readonly scorecard?: readonly {
|
|
32
|
+
readonly hole: number;
|
|
33
|
+
readonly strokes: number | null;
|
|
34
|
+
readonly total: number | null;
|
|
35
|
+
readonly par: number;
|
|
36
|
+
readonly cleared: boolean;
|
|
37
|
+
}[];
|
|
38
|
+
readonly recordGroup: string;
|
|
39
|
+
readonly moves: number;
|
|
40
|
+
readonly score: number;
|
|
41
|
+
readonly bestRun: number;
|
|
42
|
+
readonly cleared: number;
|
|
43
|
+
readonly keys: string;
|
|
44
|
+
readonly history?: readonly string[];
|
|
45
|
+
readonly round?: {
|
|
46
|
+
readonly strokes: number;
|
|
47
|
+
readonly bestHole: number;
|
|
48
|
+
readonly par: number;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export type SolitaireAdapter<V, E> = {
|
|
52
|
+
readonly view: Validator<V>;
|
|
53
|
+
readonly event: Validator<E>;
|
|
54
|
+
readonly describe: (view: V, events: readonly E[], revision: number) => SolitaireData;
|
|
55
|
+
readonly table: (view: V, out: TableOut) => Json | null;
|
|
56
|
+
readonly shortcut: (view: V, key: string) => Json | null;
|
|
57
|
+
readonly setup: (view: V, values: Readonly<Record<string, string>>) => Json | null;
|
|
58
|
+
/** Optional worker validation/certification before a setup command is sent. */
|
|
59
|
+
readonly prepareSetup?: (command: Json) => Promise<Json>;
|
|
60
|
+
readonly dispose?: () => void;
|
|
61
|
+
};
|
|
62
|
+
type Snapshot = {
|
|
63
|
+
readonly data: SolitaireData;
|
|
64
|
+
readonly revision: number;
|
|
65
|
+
readonly canUndo: boolean;
|
|
66
|
+
readonly result: string | null;
|
|
67
|
+
readonly summary: string;
|
|
68
|
+
readonly notice: string;
|
|
69
|
+
readonly elapsedMs: number;
|
|
70
|
+
readonly undosUsed: number;
|
|
71
|
+
readonly assisted: boolean;
|
|
72
|
+
readonly paused: boolean;
|
|
73
|
+
};
|
|
74
|
+
export type RecordRow = {
|
|
75
|
+
readonly played: number;
|
|
76
|
+
readonly won: number;
|
|
77
|
+
readonly bestScore: number | null;
|
|
78
|
+
readonly fewestMoves: number | null;
|
|
79
|
+
readonly bestMs: number | null;
|
|
80
|
+
readonly bestRun: number;
|
|
81
|
+
readonly cleared: number;
|
|
82
|
+
readonly cleanWins: number;
|
|
83
|
+
readonly streak: number;
|
|
84
|
+
readonly longestStreak: number;
|
|
85
|
+
readonly completed: number;
|
|
86
|
+
readonly totalStrokes: number;
|
|
87
|
+
readonly bestRound: number | null;
|
|
88
|
+
readonly bestHole: number | null;
|
|
89
|
+
readonly underPar: number;
|
|
90
|
+
};
|
|
91
|
+
type Records = Readonly<Record<string, RecordRow>>;
|
|
92
|
+
export declare const decode: <T>(schema: Validator<T>, raw: unknown) => T | null;
|
|
93
|
+
type Action = {
|
|
94
|
+
readonly kind: 'command';
|
|
95
|
+
readonly command: Json;
|
|
96
|
+
} | {
|
|
97
|
+
readonly kind: 'undo' | 'resign';
|
|
98
|
+
} | {
|
|
99
|
+
readonly kind: 'table';
|
|
100
|
+
readonly out: TableOut;
|
|
101
|
+
} | {
|
|
102
|
+
readonly kind: 'key';
|
|
103
|
+
readonly key: string;
|
|
104
|
+
} | {
|
|
105
|
+
readonly kind: 'setup';
|
|
106
|
+
readonly values: Readonly<Record<string, string>>;
|
|
107
|
+
};
|
|
108
|
+
type State = {
|
|
109
|
+
readonly snapshot: Snapshot | null;
|
|
110
|
+
readonly options: TableOptions;
|
|
111
|
+
readonly dark: boolean;
|
|
112
|
+
readonly message: string;
|
|
113
|
+
readonly dialog: 'none' | 'keys' | 'confirm';
|
|
114
|
+
readonly elapsedMs: number;
|
|
115
|
+
readonly records: Records;
|
|
116
|
+
readonly sound: boolean;
|
|
117
|
+
};
|
|
118
|
+
type Msg = {
|
|
119
|
+
readonly _tag: 'Snapshot';
|
|
120
|
+
readonly snapshot: Snapshot;
|
|
121
|
+
} | {
|
|
122
|
+
readonly _tag: 'Preferences';
|
|
123
|
+
readonly p: Preferences;
|
|
124
|
+
} | {
|
|
125
|
+
readonly _tag: 'Records';
|
|
126
|
+
readonly records: Records;
|
|
127
|
+
} | {
|
|
128
|
+
readonly _tag: 'Tick';
|
|
129
|
+
readonly ms: number;
|
|
130
|
+
} | {
|
|
131
|
+
readonly _tag: 'Action';
|
|
132
|
+
readonly action: Action;
|
|
133
|
+
} | {
|
|
134
|
+
readonly _tag: 'Table';
|
|
135
|
+
readonly out: TableOut;
|
|
136
|
+
} | {
|
|
137
|
+
readonly _tag: 'Key';
|
|
138
|
+
readonly key: string;
|
|
139
|
+
readonly ctrl: boolean;
|
|
140
|
+
} | {
|
|
141
|
+
readonly _tag: 'Dialog';
|
|
142
|
+
readonly dialog: State['dialog'];
|
|
143
|
+
} | {
|
|
144
|
+
readonly _tag: 'Color';
|
|
145
|
+
readonly on: boolean;
|
|
146
|
+
} | {
|
|
147
|
+
readonly _tag: 'Sound';
|
|
148
|
+
readonly on: boolean;
|
|
149
|
+
} | {
|
|
150
|
+
readonly _tag: 'Message';
|
|
151
|
+
readonly message: string;
|
|
152
|
+
};
|
|
153
|
+
export declare const SolitaireBoard: import("@gyral/core").GyralElementClass<State, Msg, object, never, "Key" | "Cancel" | "Action" | "Table" | "Color" | "Sound" | "Undo" | "Hint" | "New" | "Keys" | "Confirm" | "Setup">;
|
|
154
|
+
export declare const mountSolitaire: <V, E>(slot: HTMLElement, session: AnyGameSession, platform: PlatformApi, adapter: SolitaireAdapter<V, E>) => Mounted;
|
|
155
|
+
export { workerSetup } from './worker-setup.js';
|