@edv4h/usketch-plugin-croupier 0.0.0-stage → 0.1.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.
@@ -0,0 +1,185 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useSyncExternalStore, } from "react";
3
+ import { isSeat, isTable, layoutSeats, makeTableShape, SEAT_SIZE } from "./table-ops.js";
4
+ import { CROUPIER_SEAT_TYPE } from "./types.js";
5
+ export const TABLE_MIN_SIZE = { width: 480, height: 320 };
6
+ function useTableView(api, tableId) {
7
+ const getSnapshot = useCallback(() => api.getView(tableId), [api, tableId]);
8
+ return useSyncExternalStore(api.subscribe, getSnapshot, getSnapshot);
9
+ }
10
+ /**
11
+ * Stops the canvas tools from treating a click on an in-shape control as a drag/select.
12
+ * The table is a container, whose wrapper has `pointer-events: none` (so seats get
13
+ * their clicks): give in-shape controls `pointerEvents: "auto"` as well.
14
+ */
15
+ export const stopCanvas = {
16
+ onPointerDown: (e) => e.stopPropagation(),
17
+ onDoubleClick: (e) => e.stopPropagation(),
18
+ };
19
+ function TableHost({ shape, api, render, }) {
20
+ const view = useTableView(api, shape.id);
21
+ if (!view)
22
+ return null;
23
+ return render({ shape: view.table, view, api });
24
+ }
25
+ function SeatHost({ seat, api, render, }) {
26
+ const view = useTableView(api, seat.parentId);
27
+ if (!view)
28
+ return null;
29
+ const live = view.seats.find((s) => s.id === seat.id) ?? seat;
30
+ return render({
31
+ seat: live,
32
+ view,
33
+ api,
34
+ isCurrent: view.currentPlayers.includes(live.meta.userId),
35
+ isOnline: api.isOnline(live.meta.userId),
36
+ });
37
+ }
38
+ // ── Built-in renderers (plain; hosts are expected to supply their own look) ──
39
+ const panel = {
40
+ width: "100%",
41
+ height: "100%",
42
+ boxSizing: "border-box",
43
+ border: "2px solid #1e1e1e",
44
+ borderRadius: 16,
45
+ background: "#f7f3e8",
46
+ fontFamily: "system-ui, sans-serif",
47
+ color: "#1e1e1e",
48
+ padding: 16,
49
+ display: "flex",
50
+ flexDirection: "column",
51
+ gap: 8,
52
+ overflow: "hidden",
53
+ userSelect: "none",
54
+ };
55
+ const button = {
56
+ pointerEvents: "auto",
57
+ border: "1px solid #1e1e1e",
58
+ borderRadius: 8,
59
+ background: "#ffffff",
60
+ padding: "4px 10px",
61
+ fontSize: 14,
62
+ cursor: "pointer",
63
+ };
64
+ function Button({ children, onClick }) {
65
+ return (_jsx("button", { type: "button", style: button, ...stopCanvas, onClick: (e) => {
66
+ e.stopPropagation();
67
+ onClick();
68
+ }, children: children }));
69
+ }
70
+ const PHASE_LABEL = { lobby: "参加受付中", playing: "プレイ中", finished: "終了" };
71
+ /** Built-in table look: lobby controls, the current turn and the raw view. */
72
+ export const defaultRenderTable = ({ shape, view, api }) => {
73
+ const current = view.seats.find((s) => s.meta.userId === view.currentPlayers[0]);
74
+ return (_jsxs("div", { style: panel, children: [_jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontWeight: 700 }, children: [_jsx("span", { children: view.definition?.label ?? shape.meta.game }), _jsx("span", { children: PHASE_LABEL[view.phase] })] }), _jsxs("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [view.canJoin && _jsx(Button, { onClick: () => api.join(shape.id), children: "\u53C2\u52A0\u3059\u308B" }), view.phase === "lobby" && view.mySeat && (_jsx(Button, { onClick: () => api.leave(shape.id), children: "\u629C\u3051\u308B" })), view.canStart && _jsx(Button, { onClick: () => api.start(shape.id), children: "\u30B9\u30BF\u30FC\u30C8" }), view.isHost && view.phase === "playing" && current && !view.isMyTurn && (_jsx(Button, { onClick: () => void api.takeOver(shape.id), children: "\u4EE3\u308F\u308A\u306B\u9032\u3081\u308B" })), view.isHost && view.phase !== "lobby" && (_jsx(Button, { onClick: () => api.reset(shape.id), children: "\u30ED\u30D3\u30FC\u306B\u623B\u3059" }))] }), view.phase === "playing" && (_jsx("div", { children: view.isMyTurn ? "あなたの番です" : `${current?.meta.name ?? "…"} さんの番` })), view.isMyTurn && (_jsx("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: view.allowedActions.flatMap((action) => {
75
+ const choices = view.definition?.actionChoices
76
+ ? view.definition.actionChoices(action, view.gameView, api.me().userId)
77
+ : [{ label: action }];
78
+ return choices.map((choice) => (_jsx(Button, { onClick: () => api.dispatch(shape.id, action, choice.payload), children: choice.label }, `${action}:${choice.label}`)));
79
+ }) })), view.gameView !== null && (_jsx("pre", { style: {
80
+ flex: 1,
81
+ // Leave the bottom row to the seats (see layoutSeats).
82
+ margin: `0 0 ${SEAT_SIZE.height}px`,
83
+ overflow: "auto",
84
+ fontSize: 11,
85
+ background: "#ffffff",
86
+ pointerEvents: "auto",
87
+ }, children: JSON.stringify(view.phase === "finished" ? view.result : view.gameView, null, 1) }))] }));
88
+ };
89
+ /** Built-in seat look: name, turn marker and connection state. */
90
+ export const defaultRenderSeat = ({ seat, view, isCurrent, isOnline }) => (_jsxs("div", { style: {
91
+ width: "100%",
92
+ height: "100%",
93
+ boxSizing: "border-box",
94
+ border: `2px solid ${isCurrent ? "#e8590c" : "#1e1e1e"}`,
95
+ borderRadius: 10,
96
+ background: "#ffffff",
97
+ fontFamily: "system-ui, sans-serif",
98
+ fontSize: 13,
99
+ padding: "4px 8px",
100
+ opacity: isOnline ? 1 : 0.5,
101
+ overflow: "hidden",
102
+ whiteSpace: "nowrap",
103
+ textOverflow: "ellipsis",
104
+ }, children: [view.table.meta.hostUserId === seat.meta.userId ? "★ " : "", seat.meta.name, isCurrent ? " (手番)" : ""] }));
105
+ // ── Shape definitions ──
106
+ const rectBounds = (data) => ({
107
+ x: data.x,
108
+ y: data.y,
109
+ width: data.width,
110
+ height: data.height,
111
+ });
112
+ const rectHit = (data, p) => p.x >= data.x && p.x <= data.x + data.width && p.y >= data.y && p.y <= data.y + data.height;
113
+ function resizeRect(data, handle, delta) {
114
+ let { x, y, width, height } = data;
115
+ if (handle.includes("e"))
116
+ width += delta.x;
117
+ if (handle.includes("s"))
118
+ height += delta.y;
119
+ if (handle.includes("w")) {
120
+ x += delta.x;
121
+ width -= delta.x;
122
+ }
123
+ if (handle.includes("n")) {
124
+ y += delta.y;
125
+ height -= delta.y;
126
+ }
127
+ const w = Math.max(TABLE_MIN_SIZE.width, width);
128
+ const h = Math.max(TABLE_MIN_SIZE.height, height);
129
+ // Keep the opposite edge fixed when clamping a west / north drag.
130
+ if (handle.includes("w"))
131
+ x += width - w;
132
+ if (handle.includes("n"))
133
+ y += height - h;
134
+ return { ...data, x, y, width: w, height: h };
135
+ }
136
+ export function tableShapeDefinition(opts) {
137
+ const render = opts.renderTable ?? defaultRenderTable;
138
+ return {
139
+ renderTarget: "html",
140
+ render: (data) => isTable(data) ? _jsx(TableHost, { shape: data, api: opts.api, render: render }) : _jsx(_Fragment, {}),
141
+ getBounds: rectBounds,
142
+ hitTest: rectHit,
143
+ resize: resizeRect,
144
+ minSize: TABLE_MIN_SIZE,
145
+ createDefault: ({ id, x, y }) => makeTableShape(new Map(opts.api.games().map((g) => [g.id, g])), {
146
+ id,
147
+ x,
148
+ y,
149
+ game: opts.defaultGame() ?? "",
150
+ host: opts.api.me(),
151
+ size: opts.tableSize,
152
+ }),
153
+ // Seats are children: clicking one selects the table, and they follow it.
154
+ container: {
155
+ selectableChildren: false,
156
+ autoAttach: false,
157
+ // Only seats are laid out; any other child keeps where it is.
158
+ layout: ({ container, children }) => layoutSeats(container, children.filter(isSeat)),
159
+ },
160
+ };
161
+ }
162
+ export function seatShapeDefinition(opts) {
163
+ const render = opts.renderSeat ?? defaultRenderSeat;
164
+ return {
165
+ renderTarget: "html",
166
+ // A malformed seat (no table / meta, e.g. from createDefault) renders nothing.
167
+ render: (data) => isSeat(data) ? _jsx(SeatHost, { seat: data, api: opts.api, render: render }) : _jsx(_Fragment, {}),
168
+ getBounds: rectBounds,
169
+ hitTest: rectHit,
170
+ resize: (data) => data,
171
+ resizable: false,
172
+ // Seats are only created by joining; a bare one (no table, no meta) is removed
173
+ // by `repairTables` and renders nothing meanwhile.
174
+ createDefault: ({ id, x, y }) => ({
175
+ id,
176
+ type: CROUPIER_SEAT_TYPE,
177
+ x,
178
+ y,
179
+ width: 0,
180
+ height: 0,
181
+ style: { fill: "#ffffff", stroke: "#1e1e1e", strokeWidth: 1, opacity: 1 },
182
+ }),
183
+ };
184
+ }
185
+ //# sourceMappingURL=table-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table-shape.js","sourceRoot":"","sources":["../src/table-shape.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import type { ActionLogEntry, BotStrategy, CroupierConfig, CroupierSnapshot, GameResult, GameState, PlayerId } from "@edv4h/croupier-core";
2
+ import type { ShapeData } from "@edv4h/usketch-shared";
3
+ /** Shape type of a game table (holds the game options, the host and the engine snapshot). */
4
+ export declare const CROUPIER_TABLE_TYPE = "croupier-table";
5
+ /** Shape type of a seat (one per joined player, child of a table). */
6
+ export declare const CROUPIER_SEAT_TYPE = "croupier-seat";
7
+ /** Every shape type this plugin owns (e.g. for a host that keeps game writes out of undo). */
8
+ export declare const CROUPIER_SHAPE_TYPES: readonly string[];
9
+ /** `lobby` → (host starts) → `playing` → (engine finishes) → `finished` → (host resets) → `lobby`. */
10
+ export type TablePhase = "lobby" | "playing" | "finished";
11
+ /** Game-specific options chosen in the lobby (e.g. a theme). Must be JSON-serializable. */
12
+ export type GameOptions = Record<string, unknown>;
13
+ /**
14
+ * A game the host app makes available on the board. The plugin never knows the
15
+ * rules: it builds a {@link CroupierConfig} from the table's options and drives it.
16
+ */
17
+ export interface CroupierGameDefinition<S extends GameState = GameState> {
18
+ /** Stable id stored on the table (`meta.game`). */
19
+ id: string;
20
+ /** Display name (HUD / default renderer). */
21
+ label: string;
22
+ /** Build the engine config for a table. Called on start and on every restore, so keep it pure. */
23
+ createConfig(options: GameOptions): CroupierConfig<S>;
24
+ /** Options of a new table. Default `{}`. */
25
+ defaultOptions?: GameOptions;
26
+ /** Players needed to start. Default 2. */
27
+ minPlayers?: number;
28
+ /** Seats available. Default 8. */
29
+ maxPlayers?: number;
30
+ /**
31
+ * Buttons of an action in the built-in look (e.g. one per card in hand for
32
+ * `discardCard`); an empty list hides the action. Without it, each allowed action is
33
+ * one button dispatched without a payload. Custom renderers can ignore it.
34
+ */
35
+ actionChoices?(action: string, gameView: unknown, viewer: PlayerId): ActionChoice[];
36
+ /** Strategy used when the host plays for an absent player. Defaults to `config.bot`. */
37
+ bot?: BotStrategy<S>;
38
+ }
39
+ /** One button of the built-in look: dispatches `action` with `payload`. */
40
+ export interface ActionChoice {
41
+ label: string;
42
+ payload?: unknown;
43
+ }
44
+ /** `croupier-table` meta. Written by the host (lobby / start / reset) and the current player (actions). */
45
+ export type TableMeta = {
46
+ /** Id the table was created with. A copy carries the source id, which is how copies are detected and reset. */
47
+ tableId: string;
48
+ game: string;
49
+ options: GameOptions;
50
+ hostUserId: string;
51
+ phase: TablePhase;
52
+ /** Engine state (`CroupierCore#toSnapshot`). `null` in the lobby. */
53
+ snapshot: CroupierSnapshot | null;
54
+ /** When the current turn started (host clock), for absent-player takeover. */
55
+ turnStartedAt: number | null;
56
+ };
57
+ /** `croupier-seat` meta. Written by the seated player only (except kick / leave by the host). */
58
+ export type SeatMeta = {
59
+ userId: string;
60
+ name: string;
61
+ avatarUrl?: string;
62
+ joinedAt: number;
63
+ /** Free text the player attaches to the result (e.g. why they kept these cards). */
64
+ note?: string;
65
+ };
66
+ export type TableShape = ShapeData & {
67
+ meta: TableMeta;
68
+ };
69
+ export type SeatShape = ShapeData & {
70
+ meta: SeatMeta;
71
+ parentId: string;
72
+ };
73
+ /** The local user. */
74
+ export interface CroupierPlayer {
75
+ userId: string;
76
+ name: string;
77
+ avatarUrl?: string;
78
+ }
79
+ /** Everything a renderer needs about one table, from the viewer's point of view. */
80
+ export interface TableView {
81
+ table: TableShape;
82
+ definition: CroupierGameDefinition | undefined;
83
+ phase: TablePhase;
84
+ /** Seats in turn order (join order). */
85
+ seats: SeatShape[];
86
+ /** The viewer's seat, if joined. */
87
+ mySeat: SeatShape | undefined;
88
+ isHost: boolean;
89
+ canJoin: boolean;
90
+ canStart: boolean;
91
+ /** `getPlayerView(viewer)` of the engine — other players' hidden info is already masked. `null` in the lobby. */
92
+ gameView: unknown;
93
+ /** Players whose turn it is. */
94
+ currentPlayers: PlayerId[];
95
+ isMyTurn: boolean;
96
+ /** Current stage (e.g. `waitingForDraw`). */
97
+ stage: string | undefined;
98
+ /** Actions the viewer may dispatch now. */
99
+ allowedActions: string[];
100
+ result: GameResult | null;
101
+ /** Most recent engine log entries (oldest first). */
102
+ log: ActionLogEntry[];
103
+ revision: number;
104
+ }
105
+ /** Result of a table operation. */
106
+ export type OpResult = {
107
+ ok: true;
108
+ } | {
109
+ ok: false;
110
+ error: string;
111
+ };
112
+ /**
113
+ * Erase a game's state type so games with different states fit in one list
114
+ * (`games: [defineCroupierGame(a), defineCroupierGame(b)]`).
115
+ */
116
+ export declare function defineCroupierGame<S extends GameState>(definition: CroupierGameDefinition<S>): CroupierGameDefinition;
117
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,14 @@
1
+ /** Shape type of a game table (holds the game options, the host and the engine snapshot). */
2
+ export const CROUPIER_TABLE_TYPE = "croupier-table";
3
+ /** Shape type of a seat (one per joined player, child of a table). */
4
+ export const CROUPIER_SEAT_TYPE = "croupier-seat";
5
+ /** Every shape type this plugin owns (e.g. for a host that keeps game writes out of undo). */
6
+ export const CROUPIER_SHAPE_TYPES = [CROUPIER_TABLE_TYPE, CROUPIER_SEAT_TYPE];
7
+ /**
8
+ * Erase a game's state type so games with different states fit in one list
9
+ * (`games: [defineCroupierGame(a), defineCroupierGame(b)]`).
10
+ */
11
+ export function defineCroupierGame(definition) {
12
+ return definition;
13
+ }
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAWA,6FAA6F;AAC7F,MAAM,CAAC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AACpD,sEAAsE;AACtE,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAClD,8FAA8F;AAC9F,MAAM,CAAC,MAAM,oBAAoB,GAAsB,CAAC,mBAAmB,EAAE,kBAAkB,CAAC,CAAC;AAyGjG;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CACjC,UAAqC;IAErC,OAAO,UAA+C,CAAC;AACxD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
1
  {
2
2
  "name": "@edv4h/usketch-plugin-croupier",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.ts",
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@edv4h/croupier-core": "0.1.0",
16
+ "@edv4h/usketch-shared": "4.19.0",
17
+ "@edv4h/usketch-store": "3.11.1"
18
+ },
19
+ "peerDependencies": {
20
+ "react": ">=19"
21
+ },
22
+ "devDependencies": {
23
+ "@edv4h/croupier-plugin-values-card": "0.1.0",
24
+ "@edv4h/usketch-core": "2.4.9",
25
+ "@types/react": "19.3.0",
26
+ "typescript": "7.0.2",
27
+ "vitest": "5.0.5"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "README.md"
35
+ ],
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/EdV4H/usketch.git",
40
+ "directory": "plugins/usketch-plugin-croupier"
41
+ },
42
+ "homepage": "https://github.com/EdV4H/usketch#readme",
43
+ "bugs": {
44
+ "url": "https://github.com/EdV4H/usketch/issues"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.json",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest run --passWithNoTests",
50
+ "clean": "rm -rf dist"
51
+ }
6
52
  }