@dreamboard-games/ui-sdk 0.0.43 → 0.0.45

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.
Files changed (166) hide show
  1. package/dist/components/ActionButton.d.ts.map +1 -1
  2. package/dist/components/ActionButton.js +2 -1
  3. package/dist/components/Card.d.ts +1 -1
  4. package/dist/components/Card.d.ts.map +1 -1
  5. package/dist/components/DiceRoller.d.ts +3 -2
  6. package/dist/components/DiceRoller.d.ts.map +1 -1
  7. package/dist/components/DiceRoller.js +4 -13
  8. package/dist/components/ErrorBoundary.d.ts.map +1 -1
  9. package/dist/components/ErrorBoundary.js +94 -2
  10. package/dist/components/InteractionForm.d.ts +1 -1
  11. package/dist/components/InteractionForm.d.ts.map +1 -1
  12. package/dist/components/InteractionForm.js +29 -15
  13. package/dist/components/PrimaryActionButton.d.ts.map +1 -1
  14. package/dist/components/PrimaryActionButton.js +7 -6
  15. package/dist/components/ResourceCounter.d.ts +59 -25
  16. package/dist/components/ResourceCounter.d.ts.map +1 -1
  17. package/dist/components/ResourceCounter.js +106 -115
  18. package/dist/components/Toast.d.ts +13 -6
  19. package/dist/components/Toast.d.ts.map +1 -1
  20. package/dist/components/Toast.js +10 -5
  21. package/dist/components/board/HexGrid.js +6 -6
  22. package/dist/components/board/target-layer.d.ts +18 -2
  23. package/dist/components/board/target-layer.d.ts.map +1 -1
  24. package/dist/components/board/target-layer.js +20 -3
  25. package/dist/components/index.d.ts +3 -4
  26. package/dist/components/index.d.ts.map +1 -1
  27. package/dist/components/index.js +3 -4
  28. package/dist/components/surfaces/InboxSurface.d.ts.map +1 -1
  29. package/dist/components/surfaces/InboxSurface.js +2 -6
  30. package/dist/components/surfaces/PlayerCardsSurface.js +2 -2
  31. package/dist/components/surfaces/internal/CardZoneRoutedForm.d.ts +7 -0
  32. package/dist/components/surfaces/internal/CardZoneRoutedForm.d.ts.map +1 -0
  33. package/dist/components/surfaces/internal/CardZoneRoutedForm.js +9 -0
  34. package/dist/components/surfaces/internal/DefaultInteractionButton.d.ts.map +1 -1
  35. package/dist/components/surfaces/internal/DefaultInteractionButton.js +5 -8
  36. package/dist/components/surfaces/internal/useCardZoneInteractions.d.ts +2 -2
  37. package/dist/components/surfaces/internal/useCardZoneInteractions.d.ts.map +1 -1
  38. package/dist/components/surfaces/internal/useCardZoneInteractions.js +19 -43
  39. package/dist/context/InteractionDraftContext.d.ts +11 -2
  40. package/dist/context/InteractionDraftContext.d.ts.map +1 -1
  41. package/dist/context/InteractionDraftContext.js +41 -4
  42. package/dist/defaults/components.d.ts +0 -5
  43. package/dist/defaults/components.d.ts.map +1 -1
  44. package/dist/defaults/components.js +7 -11
  45. package/dist/hooks/useBoardInteractions.d.ts +35 -12
  46. package/dist/hooks/useBoardInteractions.d.ts.map +1 -1
  47. package/dist/hooks/useBoardInteractions.js +186 -82
  48. package/dist/hooks/useInteractionHandle.d.ts +1 -1
  49. package/dist/hooks/useInteractionHandle.d.ts.map +1 -1
  50. package/dist/hooks/useInteractionHandle.js +12 -27
  51. package/dist/index.d.ts +11 -17
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +5 -14
  54. package/dist/primitives/board.d.ts +53 -3
  55. package/dist/primitives/board.d.ts.map +1 -1
  56. package/dist/primitives/board.js +65 -41
  57. package/dist/primitives/dialog-lifecycle.d.ts +17 -0
  58. package/dist/primitives/dialog-lifecycle.d.ts.map +1 -0
  59. package/dist/primitives/dialog-lifecycle.js +24 -0
  60. package/dist/primitives/dice.d.ts +31 -0
  61. package/dist/primitives/dice.d.ts.map +1 -0
  62. package/dist/primitives/dice.js +33 -0
  63. package/dist/primitives/game.d.ts +55 -0
  64. package/dist/primitives/game.d.ts.map +1 -0
  65. package/dist/primitives/game.js +101 -0
  66. package/dist/primitives/index.d.ts +7 -4
  67. package/dist/primitives/index.d.ts.map +1 -1
  68. package/dist/primitives/index.js +7 -4
  69. package/dist/primitives/interaction-form-binding.d.ts +12 -0
  70. package/dist/primitives/interaction-form-binding.d.ts.map +1 -0
  71. package/dist/primitives/interaction-form-binding.js +14 -0
  72. package/dist/primitives/interaction-submit.d.ts +23 -0
  73. package/dist/primitives/interaction-submit.d.ts.map +1 -0
  74. package/dist/primitives/interaction-submit.js +41 -0
  75. package/dist/primitives/interaction.d.ts +76 -6
  76. package/dist/primitives/interaction.d.ts.map +1 -1
  77. package/dist/primitives/interaction.js +210 -26
  78. package/dist/primitives/player-roster.d.ts +2 -1
  79. package/dist/primitives/player-roster.d.ts.map +1 -1
  80. package/dist/primitives/prompt.d.ts +36 -11
  81. package/dist/primitives/prompt.d.ts.map +1 -1
  82. package/dist/primitives/prompt.js +29 -17
  83. package/dist/primitives/ui.d.ts +9 -0
  84. package/dist/primitives/ui.d.ts.map +1 -0
  85. package/dist/primitives/ui.js +7 -0
  86. package/dist/primitives/zone.d.ts +111 -5
  87. package/dist/primitives/zone.d.ts.map +1 -1
  88. package/dist/primitives/zone.js +349 -9
  89. package/dist/reducer.d.ts +2 -14
  90. package/dist/reducer.d.ts.map +1 -1
  91. package/dist/reducer.js +1 -14
  92. package/dist/runtime/createPluginRuntimeAPI.js +1 -1
  93. package/dist/types/hex-color.d.ts +7 -0
  94. package/dist/types/hex-color.d.ts.map +1 -0
  95. package/dist/types/hex-color.js +13 -0
  96. package/dist/types/player-state.d.ts +28 -14
  97. package/dist/types/player-state.d.ts.map +1 -1
  98. package/dist/types/plugin-state.d.ts +9 -3
  99. package/dist/types/plugin-state.d.ts.map +1 -1
  100. package/dist/ui-contract.d.ts +119 -14
  101. package/dist/ui-contract.d.ts.map +1 -1
  102. package/dist/ui-contract.js +4 -3
  103. package/dist/ui-sdk.d.ts +1637 -1245
  104. package/dist/utils/interaction-inputs.d.ts +8 -5
  105. package/dist/utils/interaction-inputs.d.ts.map +1 -1
  106. package/dist/utils/interaction-inputs.js +82 -14
  107. package/dist/utils/interaction-router.d.ts +31 -0
  108. package/dist/utils/interaction-router.d.ts.map +1 -0
  109. package/dist/utils/interaction-router.js +114 -0
  110. package/package.json +1 -1
  111. package/src/components/ActionButton.tsx +2 -1
  112. package/src/components/Card.tsx +1 -1
  113. package/src/components/DiceRoller.tsx +13 -22
  114. package/src/components/ErrorBoundary.test.tsx +19 -0
  115. package/src/components/ErrorBoundary.tsx +113 -24
  116. package/src/components/InteractionForm.test.tsx +24 -0
  117. package/src/components/InteractionForm.tsx +48 -23
  118. package/src/components/PrimaryActionButton.tsx +19 -5
  119. package/src/components/ResourceCounter.test.tsx +13 -13
  120. package/src/components/ResourceCounter.tsx +238 -244
  121. package/src/components/Toast.tsx +23 -10
  122. package/src/components/__fixtures__/ResourceCounter.fixture.tsx +70 -169
  123. package/src/components/board/HexGrid.tsx +6 -6
  124. package/src/components/board/target-layer.ts +44 -5
  125. package/src/components/index.ts +17 -10
  126. package/src/components/surfaces/InboxSurface.tsx +7 -5
  127. package/src/components/surfaces/PlayerCardsSurface.tsx +6 -6
  128. package/src/components/surfaces/internal/CardZoneRoutedForm.tsx +35 -0
  129. package/src/components/surfaces/internal/DefaultInteractionButton.tsx +17 -7
  130. package/src/components/surfaces/internal/useCardZoneInteractions.ts +25 -67
  131. package/src/context/InteractionDraftContext.tsx +51 -5
  132. package/src/defaults/components.tsx +12 -50
  133. package/src/defaults/defaults.test.tsx +1 -50
  134. package/src/hooks/useBoardInteractions.test.tsx +240 -17
  135. package/src/hooks/useBoardInteractions.ts +330 -105
  136. package/src/hooks/useInteractionHandle.ts +23 -28
  137. package/src/index.test.ts +60 -40
  138. package/src/index.ts +30 -36
  139. package/src/primitives/board.test.tsx +73 -0
  140. package/src/primitives/board.tsx +191 -40
  141. package/src/primitives/dialog-lifecycle.ts +58 -0
  142. package/src/primitives/dice.test.tsx +47 -0
  143. package/src/primitives/dice.tsx +79 -0
  144. package/src/primitives/game.test.tsx +98 -0
  145. package/src/primitives/game.tsx +213 -0
  146. package/src/primitives/index.ts +84 -0
  147. package/src/primitives/interaction-form-binding.tsx +56 -0
  148. package/src/primitives/interaction-submit.ts +90 -0
  149. package/src/primitives/interaction.test.tsx +396 -0
  150. package/src/primitives/interaction.tsx +451 -31
  151. package/src/primitives/player-roster.tsx +2 -1
  152. package/src/primitives/prompt.test.tsx +94 -3
  153. package/src/primitives/prompt.tsx +87 -48
  154. package/src/primitives/ui.test.tsx +131 -0
  155. package/src/primitives/ui.tsx +13 -0
  156. package/src/primitives/zone.test.tsx +305 -0
  157. package/src/primitives/zone.tsx +660 -12
  158. package/src/reducer.ts +7 -20
  159. package/src/runtime/createPluginRuntimeAPI.ts +1 -1
  160. package/src/types/hex-color.ts +20 -0
  161. package/src/types/player-state.ts +36 -18
  162. package/src/types/plugin-state.ts +10 -3
  163. package/src/ui-contract.ts +253 -21
  164. package/src/utils/interaction-inputs.test.ts +400 -0
  165. package/src/utils/interaction-inputs.ts +113 -11
  166. package/src/utils/interaction-router.ts +200 -0
package/src/reducer.ts CHANGED
@@ -1,23 +1,3 @@
1
- export { useActivePlayers } from "./hooks/useActivePlayers.js";
2
- export { useSimultaneousPhase } from "./hooks/useSimultaneousPhase.js";
3
- export { usePlayerTurnOrder } from "./hooks/usePlayerTurnOrder.js";
4
- export { useGameSelector } from "./hooks/useGameSelector.js";
5
- export { useIsMyTurn } from "./hooks/useIsMyTurn.js";
6
- export { useCards } from "./hooks/useCards.js";
7
- export { useGameView } from "./hooks/useGameView.js";
8
- export { useLobby } from "./hooks/useLobby.js";
9
- export { useMe } from "./hooks/useMe.js";
10
- export { usePlayerInfo } from "./hooks/usePlayerInfo.js";
11
- export { useSeatInbox, type SeatInbox } from "./hooks/useSeatInbox.js";
12
- export {
13
- useInteractionHandle,
14
- type InteractionHandle,
15
- type InteractionHandleStatus,
16
- type DraftValidation,
17
- type InteractionParamsShape,
18
- } from "./hooks/useInteractionHandle.js";
19
- export { useInteractionByKey } from "./hooks/useInteractionByKey.js";
20
- export { usePluginSession } from "./context/PluginSessionContext.js";
21
1
  export {
22
2
  type ClientParamSchema,
23
3
  type ClientParamSchemaMap,
@@ -35,6 +15,13 @@ export type {
35
15
  } from "./types/plugin-state.js";
36
16
  export type { LobbyState } from "./hooks/useLobby.js";
37
17
  export type { Player } from "./hooks/useMe.js";
18
+ export type { SeatInbox } from "./hooks/useSeatInbox.js";
19
+ export type {
20
+ DraftValidation,
21
+ InteractionHandle,
22
+ InteractionHandleStatus,
23
+ InteractionParamsShape,
24
+ } from "./hooks/useInteractionHandle.js";
38
25
  export type {
39
26
  CardCollection,
40
27
  ViewCard,
@@ -387,7 +387,7 @@ export function createPluginRuntimeAPI(): PluginRuntimeAPI {
387
387
 
388
388
  // Tier-0 perf: after notifyStateListeners has kicked React's
389
389
  // render, schedule a post-commit microtask + rAF chain so the
390
- // follow-up `state-rendered` message lands close to when the
390
+ // paired `state-rendered` message lands close to when the
391
391
  // plugin's DOM would have been painted. `queueMicrotask` is
392
392
  // used first because most React listeners finish synchronously;
393
393
  // `requestAnimationFrame` then bounces to the next paint tick.
@@ -0,0 +1,20 @@
1
+ export type HexColor = string & { readonly __brand: "HexColor" };
2
+
3
+ const HEX_COLOR_PATTERN = /^#[0-9A-Fa-f]{6}$/;
4
+
5
+ export function isHexColor(value: unknown): value is HexColor {
6
+ return typeof value === "string" && HEX_COLOR_PATTERN.test(value);
7
+ }
8
+
9
+ export function parseHexColor(value: unknown): HexColor | undefined {
10
+ return isHexColor(value) ? value : undefined;
11
+ }
12
+
13
+ export function hexColor(value: string): HexColor {
14
+ if (!isHexColor(value)) {
15
+ throw new Error(
16
+ `Expected a 6-digit hex color such as #E53935, received '${value}'.`,
17
+ );
18
+ }
19
+ return value;
20
+ }
@@ -8,18 +8,36 @@ import type {
8
8
  VertexTypeId,
9
9
  BoardBaseId,
10
10
  BoardId,
11
- BoardRef,
12
- PerPlayer,
13
- PerPlayerBoardRef,
14
11
  PieceId,
15
12
  PieceTypeId,
16
- SharedBoardRef,
17
13
  SpaceId,
18
14
  SpaceTypeId,
19
15
  DieId,
20
16
  } from "@dreamboard/manifest-contract";
17
+ import type { HexColor } from "./hex-color.js";
21
18
 
22
- export type { BoardRef, PerPlayer, PerPlayerBoardRef, SharedBoardRef };
19
+ export interface PerPlayer<Value> {
20
+ readonly __perPlayer: true;
21
+ readonly entries: ReadonlyArray<readonly [PlayerId, Value]>;
22
+ }
23
+
24
+ export interface SharedBoardRef<BaseId extends string = BoardBaseId> {
25
+ readonly baseId: BaseId;
26
+ readonly seat?: undefined;
27
+ }
28
+
29
+ export interface PerPlayerBoardRef<
30
+ BaseId extends string = BoardBaseId,
31
+ Id extends string = PlayerId,
32
+ > {
33
+ readonly baseId: BaseId;
34
+ readonly seat: Id;
35
+ }
36
+
37
+ export type BoardRef<
38
+ BaseId extends string = BoardBaseId,
39
+ Id extends string = PlayerId,
40
+ > = SharedBoardRef<BaseId> | PerPlayerBoardRef<BaseId, Id>;
23
41
 
24
42
  /**
25
43
  * Hands are keyed by the authored hand id and split per seat. The per-seat
@@ -40,12 +58,12 @@ export interface Player {
40
58
  /** Whether this player is the host */
41
59
  isHost?: boolean;
42
60
  /** Player's assigned color */
43
- color?: string;
61
+ color?: HexColor;
44
62
  }
45
63
 
46
64
  export interface HexTileState<
47
65
  B extends string = BoardId,
48
- SpaceIdValue extends SpaceId = SpaceId,
66
+ SpaceIdValue extends string = SpaceId,
49
67
  Properties = B extends keyof TilePropertiesByBoardId
50
68
  ? TilePropertiesByBoardId[B]
51
69
  : undefined,
@@ -67,8 +85,8 @@ export interface HexTileState<
67
85
  properties?: Properties;
68
86
  /**
69
87
  * Optional view-projection overlay merged onto the static topology by
70
- * `createHexBoardView` / `useHexBoardView`. Authored boards can also
71
- * supply this directly when building tiles by hand.
88
+ * component-first board helpers such as `Board.HexView`. Authored boards can
89
+ * also supply this directly when building tiles by hand.
72
90
  */
73
91
  view?: View;
74
92
  }
@@ -76,7 +94,7 @@ export interface HexTileState<
76
94
  /** State of an edge on a reducer-projected hex board. */
77
95
  export interface HexEdgeState<
78
96
  B extends string = BoardId,
79
- SpaceIdValue extends SpaceId = SpaceId,
97
+ SpaceIdValue extends string = SpaceId,
80
98
  EdgeIdValue extends string = string,
81
99
  Properties = B extends keyof EdgePropertiesByBoardId
82
100
  ? EdgePropertiesByBoardId[B]
@@ -101,7 +119,7 @@ export interface HexEdgeState<
101
119
  /** State of a vertex on a reducer-projected hex board. */
102
120
  export interface HexVertexState<
103
121
  B extends string = BoardId,
104
- SpaceIdValue extends SpaceId = SpaceId,
122
+ SpaceIdValue extends string = SpaceId,
105
123
  VertexIdValue extends string = string,
106
124
  Properties = B extends keyof VertexPropertiesByBoardId
107
125
  ? VertexPropertiesByBoardId[B]
@@ -124,7 +142,7 @@ export interface HexVertexState<
124
142
  /** Complete state of a reducer-projected hex board. */
125
143
  export interface HexBoardState<
126
144
  B extends string = BoardId,
127
- SpaceIdValue extends SpaceId = SpaceId,
145
+ SpaceIdValue extends string = SpaceId,
128
146
  EdgeIdValue extends string = string,
129
147
  VertexIdValue extends string = string,
130
148
  TileProperties = B extends keyof TilePropertiesByBoardId
@@ -215,7 +233,7 @@ export interface NetworkBoardState {
215
233
 
216
234
  /** State of a cell on a reducer-projected square grid board. */
217
235
  export interface SquareCellState<
218
- SpaceIdValue extends SpaceId = SpaceId,
236
+ SpaceIdValue extends string = SpaceId,
219
237
  Properties = Record<string, unknown>,
220
238
  > {
221
239
  /** Unique cell identifier */
@@ -236,7 +254,7 @@ export interface SquareCellState<
236
254
 
237
255
  /** State of an edge on a reducer-projected square grid board. */
238
256
  export interface SquareEdgeState<
239
- SpaceIdValue extends SpaceId = SpaceId,
257
+ SpaceIdValue extends string = SpaceId,
240
258
  EdgeIdValue extends string = string,
241
259
  Properties = Record<string, unknown>,
242
260
  > {
@@ -256,7 +274,7 @@ export interface SquareEdgeState<
256
274
 
257
275
  /** State of a vertex on a reducer-projected square grid board. */
258
276
  export interface SquareVertexState<
259
- SpaceIdValue extends SpaceId = SpaceId,
277
+ SpaceIdValue extends string = SpaceId,
260
278
  VertexIdValue extends string = string,
261
279
  Properties = Record<string, unknown>,
262
280
  > {
@@ -276,7 +294,7 @@ export interface SquareVertexState<
276
294
 
277
295
  /** State of a piece placed on a reducer-projected square grid cell. */
278
296
  export interface SquarePieceState<
279
- PieceIdValue extends PieceId = PieceId,
297
+ PieceIdValue extends string = PieceId,
280
298
  Properties = Record<string, unknown>,
281
299
  > {
282
300
  /** Unique piece identifier */
@@ -296,10 +314,10 @@ export interface SquarePieceState<
296
314
  /** Complete state of a reducer-projected square grid board. */
297
315
  export interface SquareBoardState<
298
316
  B extends string = BoardId,
299
- SpaceIdValue extends SpaceId = SpaceId,
317
+ SpaceIdValue extends string = SpaceId,
300
318
  EdgeIdValue extends string = string,
301
319
  VertexIdValue extends string = string,
302
- PieceIdValue extends PieceId = PieceId,
320
+ PieceIdValue extends string = PieceId,
303
321
  CellProperties = Record<string, unknown>,
304
322
  EdgeProperties = Record<string, unknown>,
305
323
  VertexProperties = Record<string, unknown>,
@@ -1,4 +1,5 @@
1
1
  import type { PlayerId } from "@dreamboard/manifest-contract";
2
+ import type { HexColor } from "./hex-color.js";
2
3
 
3
4
  /**
4
5
  * Plugin State Types
@@ -14,7 +15,7 @@ export interface SeatAssignment {
14
15
  playerId: PlayerId;
15
16
  controllerUserId?: string;
16
17
  displayName: string;
17
- playerColor?: string;
18
+ playerColor?: HexColor;
18
19
  isHost?: boolean;
19
20
  }
20
21
 
@@ -218,7 +219,6 @@ export interface GameplayPromptOption {
218
219
  export interface InteractionContextOption {
219
220
  id: string;
220
221
  label?: string;
221
- data?: unknown;
222
222
  }
223
223
 
224
224
  /** Structured context attached to a prompt-kind InteractionDescriptor. */
@@ -268,10 +268,17 @@ export interface InputDomain {
268
268
  step?: number;
269
269
  choices?: readonly InteractionChoiceOption[];
270
270
  selection?: InputSelection;
271
+ dependsOn?: readonly string[];
272
+ dependentCases?: readonly InputDomainDependencyCase[];
273
+ }
274
+
275
+ export interface InputDomainDependencyCase {
276
+ when: Readonly<Record<string, string>>;
277
+ domain: InputDomain;
271
278
  }
272
279
 
273
280
  export interface InteractionChoiceOption {
274
- value: string;
281
+ value: string | null;
275
282
  label: string;
276
283
  icon?: string;
277
284
  badge?: string;
@@ -1,25 +1,56 @@
1
- import type { ReactElement } from "react";
2
- import {
3
- PromptDialogHost as PromptDialogHostComponent,
4
- type PromptDialogHostProps,
5
- } from "./components/PromptDialogHost.js";
1
+ import type { ReactElement, ReactNode } from "react";
6
2
  import {
7
3
  Board as BoardPrimitive,
4
+ Dice as DicePrimitive,
5
+ Game as GamePrimitive,
8
6
  Interaction as InteractionPrimitive,
9
7
  Phase as PhasePrimitive,
10
8
  PlayerRoster as PlayerRosterPrimitive,
11
9
  Prompt as PromptPrimitive,
12
10
  PromptInbox as PromptInboxPrimitive,
11
+ UI as UIPrimitive,
13
12
  Zone as ZonePrimitive,
13
+ type BoardHexGridProps,
14
+ type BoardHexGridInteractionFilter,
14
15
  type BoardTargetProps,
16
+ type BoardSpaceTargetProps,
17
+ type BoardEdgeTargetProps,
18
+ type BoardVertexTargetProps,
19
+ type DiceComponents,
20
+ type GameRootProps,
15
21
  type InteractionCardInputProps,
22
+ type InteractionDialogProps,
23
+ type InteractionFieldPrimitiveProps,
24
+ type InteractionFormPrimitiveProps,
25
+ type InteractionRouteMap,
16
26
  type InteractionRootProps,
27
+ type InteractionSwitchProps,
17
28
  type PhaseSwitchProps,
18
29
  type PlayerRosterComponents,
30
+ type PlayerRosterBadge,
31
+ type PlayerRosterEntry,
32
+ type PlayerRosterListProps,
33
+ type PlayerRosterPartProps,
34
+ type PlayerRosterRootProps,
35
+ type PlayerRosterSwitchButtonProps,
36
+ type PromptDialogProps,
37
+ type PromptInboxItemsProps,
38
+ type PromptOptionRenderItem,
19
39
  type PromptOptionProps,
40
+ type PromptOptionsProps,
20
41
  type PromptRootProps,
42
+ type UIRootProps,
43
+ type ZoneItemProps,
44
+ type ZoneCardAtProps,
45
+ type ZoneCardActionProps,
46
+ type ZoneCardRenderItem,
47
+ type ZoneListProps,
48
+ type ZonePileCardsProps,
49
+ type ZonePileRootProps,
21
50
  type ZoneRootProps,
22
51
  } from "./primitives/index.js";
52
+ import type { InteractionDescriptor } from "./types/plugin-state.js";
53
+ import type { AnyHexBoardInput, BoardSpaceIdOf } from "./types/tiled-board.js";
23
54
 
24
55
  /**
25
56
  * Workspace-aware UI typing extension point.
@@ -37,6 +68,7 @@ export interface UIContract {
37
68
  inputs?: UIContractBucket;
38
69
  prompts?: UIContractBucket;
39
70
  promptOptions?: UIContractBucket;
71
+ players?: UIContractBucket;
40
72
  zones?: UIContractBucket;
41
73
  cards?: UIContractBucket;
42
74
  phases?: UIContractBucket;
@@ -54,10 +86,18 @@ type BucketOf<Contract extends UIContract, Key extends keyof UIContract> =
54
86
  ? NonNullable<Contract[Key]>
55
87
  : UIContractBucket;
56
88
 
57
- type StringKeysOrFallback<Bucket extends UIContractBucket> =
58
- string extends Extract<keyof Bucket, string>
89
+ type StringKeyOf<Bucket extends UIContractBucket> = Extract<
90
+ keyof Bucket,
91
+ string
92
+ >;
93
+
94
+ type StringKeysOrFallback<Bucket extends UIContractBucket> = [
95
+ StringKeyOf<Bucket>,
96
+ ] extends [never]
97
+ ? string
98
+ : string extends StringKeyOf<Bucket>
59
99
  ? string
60
- : Extract<keyof Bucket, string>;
100
+ : StringKeyOf<Bucket>;
61
101
 
62
102
  export type RegisteredUI = RegisteredUIContract;
63
103
 
@@ -73,6 +113,9 @@ export type PromptKey<Contract extends UIContract = RegisteredUI> =
73
113
  export type PromptOptionKey<Contract extends UIContract = RegisteredUI> =
74
114
  StringKeysOrFallback<BucketOf<Contract, "promptOptions">>;
75
115
 
116
+ export type PlayerKey<Contract extends UIContract = RegisteredUI> =
117
+ StringKeysOrFallback<BucketOf<Contract, "players">>;
118
+
76
119
  export type ZoneKey<Contract extends UIContract = RegisteredUI> =
77
120
  StringKeysOrFallback<BucketOf<Contract, "zones">>;
78
121
 
@@ -85,21 +128,46 @@ export type PhaseKey<Contract extends UIContract = RegisteredUI> =
85
128
  export type BoardTargetKey<Contract extends UIContract = RegisteredUI> =
86
129
  StringKeysOrFallback<BucketOf<Contract, "boardTargets">>;
87
130
 
131
+ type TypedZoneCardRenderItem<Contract extends UIContract> =
132
+ ZoneCardRenderItem<CardKey<Contract> & string> extends infer Item
133
+ ? Item extends { id: string; zone: string }
134
+ ? Omit<Item, "id" | "zone"> & {
135
+ id: CardKey<Contract>;
136
+ zone: ZoneKey<Contract>;
137
+ }
138
+ : never
139
+ : never;
140
+
88
141
  export type TypedInteraction<Contract extends UIContract> = Omit<
89
142
  typeof InteractionPrimitive,
90
- "Root" | "CardInput"
143
+ "Root" | "CardInput" | "Dialog" | "Field" | "Form" | "Switch"
91
144
  > & {
92
145
  Root<Interaction extends InteractionKey<Contract>>(
93
146
  props: InteractionRootProps<Interaction>,
94
147
  ): ReactElement | null;
148
+ Switch(
149
+ props: Omit<InteractionSwitchProps<InteractionKey<Contract>>, "routes"> & {
150
+ routes: InteractionRouteMap<InteractionKey<Contract>>;
151
+ },
152
+ ): ReactElement;
95
153
  CardInput<Input extends InteractionInputKey<Contract>>(
96
- props: Omit<InteractionCardInputProps, "input"> & { input: Input },
154
+ props: Omit<InteractionCardInputProps, "input" | "unsafeCardId"> & {
155
+ input: Input;
156
+ unsafeCardId?: CardKey<Contract>;
157
+ },
158
+ ): ReactElement;
159
+ Dialog<Interaction extends InteractionKey<Contract>>(
160
+ props: InteractionDialogProps<Interaction>,
97
161
  ): ReactElement;
162
+ Field<Input extends InteractionInputKey<Contract>>(
163
+ props: Omit<InteractionFieldPrimitiveProps, "input"> & { input: Input },
164
+ ): ReactElement | null;
165
+ Form(props: InteractionFormPrimitiveProps): ReactElement | null;
98
166
  };
99
167
 
100
168
  export type TypedPrompt<Contract extends UIContract> = Omit<
101
169
  typeof PromptPrimitive,
102
- "Root" | "Option"
170
+ "Root" | "Option" | "Options" | "Dialog"
103
171
  > & {
104
172
  Root<Prompt extends PromptKey<Contract>>(
105
173
  props: PromptRootProps<Prompt>,
@@ -107,10 +175,94 @@ export type TypedPrompt<Contract extends UIContract> = Omit<
107
175
  Option<Option extends PromptOptionKey<Contract>>(
108
176
  props: Omit<PromptOptionProps, "value"> & { value: Option },
109
177
  ): ReactElement;
178
+ Options(
179
+ props: Omit<PromptOptionsProps, "children"> & {
180
+ children: (
181
+ option: Omit<PromptOptionRenderItem, "id"> & {
182
+ id: PromptOptionKey<Contract>;
183
+ },
184
+ ) => ReactNode;
185
+ },
186
+ ): ReactElement;
187
+ Dialog<Prompt extends PromptKey<Contract>>(
188
+ props: PromptDialogProps<Prompt>,
189
+ ): ReactElement;
190
+ };
191
+
192
+ export type TypedPromptInbox<Contract extends UIContract> = Omit<
193
+ typeof PromptInboxPrimitive,
194
+ "Items"
195
+ > & {
196
+ Items(
197
+ props: Omit<PromptInboxItemsProps, "children"> & {
198
+ children: (
199
+ prompt: Omit<InteractionDescriptor, "interactionKey"> & {
200
+ interactionKey: PromptKey<Contract>;
201
+ },
202
+ ) => ReactNode;
203
+ },
204
+ ): ReactElement;
205
+ };
206
+
207
+ type TypedPlayerRosterEntry<Player extends string> = Omit<
208
+ PlayerRosterEntry,
209
+ "playerId"
210
+ > & {
211
+ playerId: Player;
212
+ };
213
+
214
+ type TypedPlayerRosterRootProps<Player extends string> = Omit<
215
+ PlayerRosterRootProps,
216
+ "score" | "scoreLabel" | "badges" | "metadata"
217
+ > & {
218
+ score?: (playerId: Player) => number | undefined;
219
+ scoreLabel?: string | ((playerId: Player) => string | undefined);
220
+ badges?: (
221
+ playerId: Player,
222
+ ) => ReadonlyArray<PlayerRosterBadge | null | false | undefined>;
223
+ metadata?: (playerId: Player) => Record<string, unknown> | undefined;
224
+ };
225
+
226
+ type TypedPlayerRosterListProps<Player extends string> = Omit<
227
+ PlayerRosterListProps,
228
+ "children"
229
+ > & {
230
+ children?: (player: TypedPlayerRosterEntry<Player>) => ReactNode;
110
231
  };
111
232
 
112
- export type TypedPromptInbox = typeof PromptInboxPrimitive;
113
- export type TypedPlayerRoster = PlayerRosterComponents;
233
+ type TypedPlayerRosterPartProps<Player extends string> = Omit<
234
+ PlayerRosterPartProps,
235
+ "player"
236
+ > & {
237
+ player: TypedPlayerRosterEntry<Player>;
238
+ };
239
+
240
+ type TypedPlayerRosterSwitchButtonProps<Player extends string> = Omit<
241
+ PlayerRosterSwitchButtonProps,
242
+ "player"
243
+ > & {
244
+ player: TypedPlayerRosterEntry<Player>;
245
+ };
246
+
247
+ export type TypedPlayerRoster<Contract extends UIContract> = Omit<
248
+ PlayerRosterComponents,
249
+ "Root" | "List" | "SwitchButton" | "Name" | "Score" | "Badges"
250
+ > & {
251
+ Root(
252
+ props: TypedPlayerRosterRootProps<PlayerKey<Contract>>,
253
+ ): ReactElement | null;
254
+ List(props: TypedPlayerRosterListProps<PlayerKey<Contract>>): ReactElement;
255
+ SwitchButton(
256
+ props: TypedPlayerRosterSwitchButtonProps<PlayerKey<Contract>>,
257
+ ): ReactElement;
258
+ Name(props: TypedPlayerRosterPartProps<PlayerKey<Contract>>): ReactElement;
259
+ Score(
260
+ props: TypedPlayerRosterPartProps<PlayerKey<Contract>>,
261
+ ): ReactElement | null;
262
+ Badges(
263
+ props: TypedPlayerRosterPartProps<PlayerKey<Contract>>,
264
+ ): ReactElement | null;
265
+ };
114
266
 
115
267
  export type TypedPhase<Contract extends UIContract> = Omit<
116
268
  typeof PhasePrimitive,
@@ -121,31 +273,109 @@ export type TypedPhase<Contract extends UIContract> = Omit<
121
273
 
122
274
  export type TypedZone<Contract extends UIContract> = Omit<
123
275
  typeof ZonePrimitive,
124
- "Root"
276
+ | "Root"
277
+ | "Item"
278
+ | "CardAt"
279
+ | "TopCard"
280
+ | "CardAction"
281
+ | "List"
282
+ | "PileRoot"
283
+ | "PileCards"
125
284
  > & {
126
285
  Root<Zone extends ZoneKey<Contract>>(
127
286
  props: Omit<ZoneRootProps, "zone"> & { zone: Zone },
128
287
  ): ReactElement;
288
+ Item<Card extends CardKey<Contract>>(
289
+ props: Omit<ZoneItemProps, "card"> & { card: Card },
290
+ ): ReactElement;
291
+ CardAction<Card extends CardKey<Contract>>(
292
+ props: Omit<ZoneCardActionProps, "card"> & { card?: Card },
293
+ ): ReactElement;
294
+ CardAt<Zone extends ZoneKey<Contract>>(
295
+ props: Omit<ZoneCardAtProps<Zone>, "zone" | "children"> & {
296
+ zone?: Zone;
297
+ children?:
298
+ | ReactNode
299
+ | ((card: TypedZoneCardRenderItem<Contract>) => ReactNode);
300
+ },
301
+ ): ReactElement | null;
302
+ TopCard<Zone extends ZoneKey<Contract>>(
303
+ props: Omit<ZoneCardAtProps<Zone>, "zone" | "index" | "children"> & {
304
+ zone?: Zone;
305
+ children?:
306
+ | ReactNode
307
+ | ((card: TypedZoneCardRenderItem<Contract>) => ReactNode);
308
+ },
309
+ ): ReactElement | null;
310
+ List(
311
+ props: Omit<ZoneListProps, "children"> & {
312
+ children?:
313
+ | ReactNode
314
+ | ((card: TypedZoneCardRenderItem<Contract>) => ReactNode);
315
+ },
316
+ ): ReactElement;
317
+ PileRoot<Zone extends ZoneKey<Contract>>(
318
+ props: Omit<ZonePileRootProps<Zone>, "zone"> & {
319
+ zone: Zone;
320
+ },
321
+ ): ReactElement;
322
+ PileCards(
323
+ props: Omit<ZonePileCardsProps, "renderCard"> & {
324
+ renderCard: (card: TypedZoneCardRenderItem<Contract>) => ReactNode;
325
+ },
326
+ ): ReactElement | null;
129
327
  };
130
328
 
131
329
  export type TypedBoard<Contract extends UIContract> = Omit<
132
330
  typeof BoardPrimitive,
133
- "Target"
331
+ "Target" | "SpaceTarget" | "EdgeTarget" | "VertexTarget" | "HexGrid"
134
332
  > & {
135
333
  Target<Target extends BoardTargetKey<Contract>>(
136
334
  props: Omit<BoardTargetProps, "value"> & { value: Target },
137
335
  ): ReactElement;
336
+ SpaceTarget<Target extends BoardTargetKey<Contract>>(
337
+ props: Omit<BoardSpaceTargetProps, "value"> & { value: Target },
338
+ ): ReactElement;
339
+ EdgeTarget<Target extends BoardTargetKey<Contract>>(
340
+ props: Omit<BoardEdgeTargetProps, "value"> & { value: Target },
341
+ ): ReactElement;
342
+ VertexTarget<Target extends BoardTargetKey<Contract>>(
343
+ props: Omit<BoardVertexTargetProps, "value"> & { value: Target },
344
+ ): ReactElement;
345
+ HexGrid<
346
+ TBoard extends AnyHexBoardInput,
347
+ TSpaceView extends { id: BoardSpaceIdOf<TBoard> },
348
+ >(
349
+ props: Omit<BoardHexGridProps<TBoard, TSpaceView>, "interactions"> & {
350
+ interactions?:
351
+ | Exclude<BoardHexGridInteractionFilter, object>
352
+ | {
353
+ edge?: ReadonlyArray<InteractionKey<Contract>>;
354
+ vertex?: ReadonlyArray<InteractionKey<Contract>>;
355
+ space?: ReadonlyArray<InteractionKey<Contract>>;
356
+ };
357
+ },
358
+ ): ReactElement;
359
+ };
360
+
361
+ export type TypedGame<
362
+ _Contract extends UIContract,
363
+ View = unknown,
364
+ Player extends string = PlayerKey<_Contract>,
365
+ Phase extends string = PhaseKey<_Contract>,
366
+ > = Omit<typeof GamePrimitive, "Root"> & {
367
+ Root(props: GameRootProps<View, Player, Phase>): ReactElement;
138
368
  };
139
369
 
140
370
  export interface DreamboardUI<Contract extends UIContract = RegisteredUI> {
141
371
  readonly contract: Contract;
372
+ Root(props: UIRootProps): ReactElement;
373
+ readonly Game: TypedGame<Contract>;
142
374
  readonly Interaction: TypedInteraction<Contract>;
143
375
  readonly Prompt: TypedPrompt<Contract>;
144
- readonly PromptInbox: TypedPromptInbox;
145
- readonly PlayerRoster: TypedPlayerRoster;
146
- readonly PromptDialogHost: (
147
- props: PromptDialogHostProps,
148
- ) => ReactElement | null;
376
+ readonly PromptInbox: TypedPromptInbox<Contract>;
377
+ readonly PlayerRoster: TypedPlayerRoster<Contract>;
378
+ readonly Dice: DiceComponents;
149
379
  readonly Phase: TypedPhase<Contract>;
150
380
  readonly Zone: TypedZone<Contract>;
151
381
  readonly Board: TypedBoard<Contract>;
@@ -156,11 +386,13 @@ export function createDreamboardUI<const Contract extends UIContract>(
156
386
  ): DreamboardUI<Contract> {
157
387
  return {
158
388
  contract,
389
+ Root: UIPrimitive.Root,
390
+ Game: GamePrimitive,
159
391
  Interaction: InteractionPrimitive,
160
392
  Prompt: PromptPrimitive,
161
393
  PromptInbox: PromptInboxPrimitive,
162
394
  PlayerRoster: PlayerRosterPrimitive,
163
- PromptDialogHost: PromptDialogHostComponent,
395
+ Dice: DicePrimitive,
164
396
  Phase: PhasePrimitive,
165
397
  Zone: ZonePrimitive,
166
398
  Board: BoardPrimitive,