@dreamboard-games/ui-sdk 0.0.43 → 0.0.46

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 (172) 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 +2 -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
  167. package/type-stubs/manifest-contract.d.ts +42 -0
  168. package/type-stubs/manifest-contract.d.ts.map +1 -0
  169. package/type-stubs/manifest-contract.js +72 -0
  170. package/type-stubs/ui-contract.d.ts +5 -0
  171. package/type-stubs/ui-contract.d.ts.map +1 -0
  172. package/type-stubs/ui-contract.js +1 -0
@@ -0,0 +1,213 @@
1
+ import { createContext, useContext, useMemo, type ReactNode } from "react";
2
+ import type { PlayerId } from "@dreamboard/manifest-contract";
3
+ import { usePluginState } from "../context/PluginStateContext.js";
4
+ import { usePluginSession } from "../context/PluginSessionContext.js";
5
+ import { useActivePlayers } from "../hooks/useActivePlayers.js";
6
+ import { useGameView } from "../hooks/useGameView.js";
7
+ import { usePlayerInfo } from "../hooks/usePlayerInfo.js";
8
+ import { usePlayerTurnOrder } from "../hooks/usePlayerTurnOrder.js";
9
+ import type { Player } from "../types/player-state.js";
10
+
11
+ export type GamePlayer<PlayerIdValue extends string = PlayerId> = Omit<
12
+ Player,
13
+ "playerId"
14
+ > & {
15
+ playerId: PlayerIdValue;
16
+ };
17
+
18
+ export type GamePlayerEntry<PlayerIdValue extends string = PlayerId> =
19
+ GamePlayer<PlayerIdValue> & {
20
+ index: number;
21
+ isActive: boolean;
22
+ isCurrentPlayer: boolean;
23
+ isControllable: boolean;
24
+ };
25
+
26
+ export interface GamePlayersState<PlayerIdValue extends string = PlayerId> {
27
+ byId: ReadonlyMap<PlayerIdValue, GamePlayer<PlayerIdValue>>;
28
+ order: readonly PlayerIdValue[];
29
+ entries: ReadonlyArray<GamePlayerEntry<PlayerIdValue>>;
30
+ active: readonly PlayerIdValue[];
31
+ current: GamePlayer<PlayerIdValue> | null;
32
+ }
33
+
34
+ export interface GameMeState<PlayerIdValue extends string = PlayerId> {
35
+ playerId: PlayerIdValue | null;
36
+ player: GamePlayer<PlayerIdValue> | null;
37
+ controllablePlayerIds: readonly PlayerIdValue[];
38
+ canAct: boolean;
39
+ }
40
+
41
+ export interface GameTurnState<
42
+ PlayerIdValue extends string = PlayerId,
43
+ PhaseValue extends string = string,
44
+ > {
45
+ phase: PhaseValue | null;
46
+ stage: string | null;
47
+ activePlayerIds: readonly PlayerIdValue[];
48
+ currentPlayerId: PlayerIdValue | null;
49
+ order: readonly PlayerIdValue[];
50
+ isMine: boolean;
51
+ }
52
+
53
+ export interface GameRenderState<
54
+ ViewValue = unknown,
55
+ PlayerIdValue extends string = PlayerId,
56
+ PhaseValue extends string = string,
57
+ > {
58
+ view: ViewValue;
59
+ phase: PhaseValue | null;
60
+ stage: string | null;
61
+ session: ReturnType<typeof usePluginSession>;
62
+ me: GameMeState<PlayerIdValue>;
63
+ turn: GameTurnState<PlayerIdValue, PhaseValue>;
64
+ players: GamePlayersState<PlayerIdValue>;
65
+ }
66
+
67
+ export interface GameRootProps<
68
+ ViewValue = unknown,
69
+ PlayerIdValue extends string = PlayerId,
70
+ PhaseValue extends string = string,
71
+ > {
72
+ onActionError?: (error: unknown) => void;
73
+ children: (
74
+ state: GameRenderState<ViewValue, PlayerIdValue, PhaseValue>,
75
+ ) => ReactNode;
76
+ }
77
+
78
+ type GameActionErrorHandler = (error: unknown) => void;
79
+
80
+ const GameActionErrorContext = createContext<GameActionErrorHandler | null>(
81
+ null,
82
+ );
83
+
84
+ export function useGameActionError(): GameActionErrorHandler | null {
85
+ return useContext(GameActionErrorContext);
86
+ }
87
+
88
+ function fallbackPlayer<PlayerIdValue extends string>(
89
+ playerId: PlayerIdValue,
90
+ ): GamePlayer<PlayerIdValue> {
91
+ return {
92
+ playerId,
93
+ name: playerId,
94
+ };
95
+ }
96
+
97
+ export function GameRoot<
98
+ ViewValue = unknown,
99
+ PlayerIdValue extends string = PlayerId,
100
+ PhaseValue extends string = string,
101
+ >({
102
+ children,
103
+ onActionError,
104
+ }: GameRootProps<ViewValue, PlayerIdValue, PhaseValue>) {
105
+ const view = useGameView() as ViewValue;
106
+ const session = usePluginSession();
107
+ const playerInfo = usePlayerInfo();
108
+ const activePlayers = useActivePlayers().map(
109
+ (playerId) => playerId as PlayerIdValue,
110
+ );
111
+ const turnOrder = usePlayerTurnOrder().map(
112
+ (playerId) => playerId as PlayerIdValue,
113
+ );
114
+ const phase = usePluginState(
115
+ (state) => state.gameplay.currentPhase,
116
+ ) as PhaseValue | null;
117
+ const stage = usePluginState((state) => state.gameplay.currentStage);
118
+
119
+ const playersById = useMemo(() => {
120
+ const next = new Map<PlayerIdValue, GamePlayer<PlayerIdValue>>();
121
+ playerInfo.forEach((player, key) => {
122
+ const playerId = key as PlayerIdValue;
123
+ next.set(playerId, {
124
+ ...player,
125
+ playerId,
126
+ });
127
+ });
128
+ return next;
129
+ }, [playerInfo]);
130
+
131
+ const controllingPlayerId =
132
+ session.controllingPlayerId == null
133
+ ? null
134
+ : (session.controllingPlayerId as PlayerIdValue);
135
+ const controllablePlayerIds = session.controllablePlayerIds.map(
136
+ (playerId) => playerId as PlayerIdValue,
137
+ );
138
+ const currentPlayerId = activePlayers[0] ?? turnOrder[0] ?? null;
139
+ const currentPlayer = currentPlayerId
140
+ ? (playersById.get(currentPlayerId) ?? fallbackPlayer(currentPlayerId))
141
+ : null;
142
+ const mePlayer = controllingPlayerId
143
+ ? (playersById.get(controllingPlayerId) ??
144
+ fallbackPlayer(controllingPlayerId))
145
+ : null;
146
+
147
+ const entries = useMemo<ReadonlyArray<GamePlayerEntry<PlayerIdValue>>>(
148
+ () =>
149
+ turnOrder.map((playerId, index) => {
150
+ const player = playersById.get(playerId) ?? fallbackPlayer(playerId);
151
+ return {
152
+ ...player,
153
+ index,
154
+ isActive: activePlayers.includes(playerId),
155
+ isCurrentPlayer: playerId === controllingPlayerId,
156
+ isControllable: controllablePlayerIds.includes(playerId),
157
+ };
158
+ }),
159
+ [
160
+ activePlayers,
161
+ controllablePlayerIds,
162
+ controllingPlayerId,
163
+ playersById,
164
+ turnOrder,
165
+ ],
166
+ );
167
+
168
+ const rendered = (
169
+ <>
170
+ {children({
171
+ view,
172
+ phase,
173
+ stage,
174
+ session,
175
+ me: {
176
+ playerId: controllingPlayerId,
177
+ player: mePlayer,
178
+ controllablePlayerIds,
179
+ canAct:
180
+ controllingPlayerId != null &&
181
+ activePlayers.includes(controllingPlayerId),
182
+ },
183
+ turn: {
184
+ phase,
185
+ stage,
186
+ activePlayerIds: activePlayers,
187
+ currentPlayerId,
188
+ order: turnOrder,
189
+ isMine:
190
+ controllingPlayerId != null &&
191
+ activePlayers.includes(controllingPlayerId),
192
+ },
193
+ players: {
194
+ byId: playersById,
195
+ order: turnOrder,
196
+ entries,
197
+ active: activePlayers,
198
+ current: currentPlayer,
199
+ },
200
+ })}
201
+ </>
202
+ );
203
+ if (!onActionError) return rendered;
204
+ return (
205
+ <GameActionErrorContext.Provider value={onActionError}>
206
+ {rendered}
207
+ </GameActionErrorContext.Provider>
208
+ );
209
+ }
210
+
211
+ export const Game = {
212
+ Root: GameRoot,
213
+ };
@@ -1,29 +1,70 @@
1
+ export { UI, UIRoot, type UIRootProps } from "./ui.js";
1
2
  export {
2
3
  Board,
4
+ BoardEdgeTarget,
5
+ BoardHexGrid,
6
+ BoardHexView,
3
7
  BoardRoot,
8
+ BoardSpaceTarget,
9
+ BoardState,
4
10
  BoardTarget,
11
+ BoardVertexTarget,
5
12
  useBoardPrimitiveContext,
13
+ type BoardEdgeTargetProps,
14
+ type BoardHexGridInteractionFilter,
15
+ type BoardHexGridInteractions,
16
+ type BoardHexGridProps,
17
+ type BoardHexViewProps,
6
18
  type BoardRootProps,
19
+ type BoardSpaceTargetProps,
20
+ type BoardStateProps,
7
21
  type BoardTargetExtraInputs,
8
22
  type BoardTargetProps,
23
+ type BoardVertexTargetProps,
9
24
  } from "./board.js";
25
+ export {
26
+ Game,
27
+ GameRoot,
28
+ useGameActionError,
29
+ type GameMeState,
30
+ type GamePlayer,
31
+ type GamePlayerEntry,
32
+ type GamePlayersState,
33
+ type GameRenderState,
34
+ type GameRootProps,
35
+ type GameTurnState,
36
+ } from "./game.js";
10
37
  export {
11
38
  Interaction,
12
39
  InteractionCardInput,
13
40
  InteractionDescription,
41
+ InteractionDialog,
42
+ InteractionFormPrimitive,
14
43
  InteractionInput,
15
44
  InteractionLabel,
16
45
  InteractionRoot,
46
+ InteractionState,
17
47
  InteractionSubmit,
48
+ InteractionSwitch,
18
49
  InteractionTrigger,
19
50
  InteractionUnavailableMessage,
20
51
  InteractionValidationMessage,
21
52
  useInteractionPrimitiveContext,
22
53
  type InteractionCardInputProps,
54
+ type InteractionDialogProps,
55
+ type InteractionDialogRenderState,
56
+ type InteractionDialogState,
57
+ type InteractionFieldPrimitiveProps,
58
+ type InteractionFormPrimitiveProps,
23
59
  type InteractionInputProps,
24
60
  type InteractionPartProps,
61
+ type InteractionRouteMap,
25
62
  type InteractionRootProps,
63
+ type InteractionStateProps,
64
+ type InteractionStateSnapshot,
26
65
  type InteractionSubmitProps,
66
+ type InteractionSwitchProps,
67
+ type InteractionSwitchRenderState,
27
68
  type InteractionTriggerProps,
28
69
  } from "./interaction.js";
29
70
  export {
@@ -56,12 +97,19 @@ export {
56
97
  PromptInboxEmpty,
57
98
  PromptInboxItems,
58
99
  PromptInboxRoot,
100
+ PromptDialog,
59
101
  PromptMessage,
60
102
  PromptOption,
61
103
  PromptOptions,
62
104
  PromptRoot,
63
105
  PromptTitle,
106
+ type PromptDialogProps,
107
+ type PromptDialogRenderState,
108
+ type PromptDialogState,
109
+ type PromptInboxItemsProps,
110
+ type PromptOptionRenderItem,
64
111
  type PromptOptionProps,
112
+ type PromptOptionsProps,
65
113
  type PromptRootProps,
66
114
  } from "./prompt.js";
67
115
  export {
@@ -70,14 +118,50 @@ export {
70
118
  type PrimitiveCommonProps,
71
119
  type PrimitiveDataAttributes,
72
120
  } from "./primitive-props.js";
121
+ export {
122
+ Dice,
123
+ DiceRoot,
124
+ DiceValues,
125
+ normalizeDiceState,
126
+ useDicePrimitiveContext,
127
+ type DiceComponents,
128
+ type DiceRootProps,
129
+ type DiceState,
130
+ type DiceValue,
131
+ type DiceValuesProps,
132
+ } from "./dice.js";
73
133
  export {
74
134
  Zone,
135
+ ZoneCardAt,
136
+ ZoneCardAction,
75
137
  ZoneItem,
76
138
  ZoneList,
139
+ ZonePileCards,
140
+ ZonePileCount,
141
+ ZonePileDescription,
142
+ ZonePileLabel,
143
+ ZonePileRoot,
144
+ ZonePileTrigger,
77
145
  ZoneRoot,
146
+ ZoneTopCard,
147
+ useOptionalZonePrimitiveContext,
78
148
  useZoneCardContext,
149
+ useZonePileContext,
79
150
  useZonePrimitiveContext,
151
+ type ZoneCardAtProps,
152
+ type ZoneCardActionExtraInputs,
153
+ type ZoneCardActionProps,
154
+ type ZoneCardActionResult,
155
+ type ZoneCardRenderItem,
156
+ type ZonePileCardsProps,
157
+ type ZonePileContextValue,
158
+ type ZonePileCountProps,
159
+ type ZonePileDescriptionProps,
160
+ type ZonePileLabelProps,
161
+ type ZonePileRootProps,
162
+ type ZonePileTriggerProps,
80
163
  type ZoneItemProps,
81
164
  type ZoneListProps,
82
165
  type ZoneRootProps,
166
+ type ZoneTopCardProps,
83
167
  } from "./zone.js";
@@ -0,0 +1,56 @@
1
+ import {
2
+ InteractionForm,
3
+ type InteractionFormProps,
4
+ } from "../components/InteractionForm.js";
5
+ import type {
6
+ InteractionHandle,
7
+ InteractionParamsShape,
8
+ } from "../hooks/useInteractionHandle.js";
9
+ import type { InteractionDescriptor } from "../types/plugin-state.js";
10
+
11
+ export type BoundInteractionFormProps<
12
+ Params extends InteractionParamsShape = InteractionParamsShape,
13
+ DefaultedKeys extends keyof Params & string = never,
14
+ > = Omit<InteractionFormProps<Params, DefaultedKeys>, "descriptor" | "handle">;
15
+
16
+ export function castInteractionHandle<
17
+ Params extends InteractionParamsShape = InteractionParamsShape,
18
+ DefaultedKeys extends keyof Params & string = never,
19
+ >(handle: InteractionHandle): InteractionHandle<Params, DefaultedKeys> {
20
+ return handle as InteractionHandle<Params, DefaultedKeys>;
21
+ }
22
+
23
+ export function castInteractionDraft<
24
+ Params extends InteractionParamsShape = InteractionParamsShape,
25
+ DefaultedKeys extends keyof Params & string = never,
26
+ >(
27
+ draft: Record<string, unknown>,
28
+ ): InteractionHandle<Params, DefaultedKeys>["draft"] {
29
+ return draft as InteractionHandle<Params, DefaultedKeys>["draft"];
30
+ }
31
+
32
+ export function castInteractionFields<
33
+ Params extends InteractionParamsShape = InteractionParamsShape,
34
+ >(fields: readonly string[]): ReadonlyArray<keyof Params & string> {
35
+ return fields as ReadonlyArray<keyof Params & string>;
36
+ }
37
+
38
+ export function BoundInteractionForm<
39
+ Params extends InteractionParamsShape = InteractionParamsShape,
40
+ DefaultedKeys extends keyof Params & string = never,
41
+ >({
42
+ descriptor,
43
+ handle,
44
+ ...props
45
+ }: BoundInteractionFormProps<Params, DefaultedKeys> & {
46
+ descriptor: InteractionDescriptor;
47
+ handle: InteractionHandle;
48
+ }) {
49
+ return (
50
+ <InteractionForm<Params, DefaultedKeys>
51
+ descriptor={descriptor}
52
+ handle={castInteractionHandle<Params, DefaultedKeys>(handle)}
53
+ {...props}
54
+ />
55
+ );
56
+ }
@@ -0,0 +1,90 @@
1
+ import type {
2
+ InteractionHandle,
3
+ InteractionParamsShape,
4
+ } from "../hooks/useInteractionHandle.js";
5
+
6
+ type UnhandledInteractionError = "throw" | "log" | "ignore";
7
+
8
+ interface RunInteractionActionOptions<Result> {
9
+ onSuccess?: (result: Result) => void;
10
+ onError?: (error: unknown) => void;
11
+ unhandledError?: UnhandledInteractionError;
12
+ }
13
+
14
+ export interface InteractionSubmitCallbacks {
15
+ onSubmitSuccess?: () => void;
16
+ onSubmitError?: (error: unknown) => void;
17
+ }
18
+
19
+ export async function runInteractionAction<Result>(
20
+ action: () => Promise<Result>,
21
+ {
22
+ onSuccess,
23
+ onError,
24
+ unhandledError = "throw",
25
+ }: RunInteractionActionOptions<Result> = {},
26
+ ): Promise<void> {
27
+ try {
28
+ const result = await action();
29
+ onSuccess?.(result);
30
+ } catch (error) {
31
+ if (onError) {
32
+ onError(error);
33
+ return;
34
+ }
35
+ if (unhandledError === "log") {
36
+ console.error(error);
37
+ return;
38
+ }
39
+ if (unhandledError === "ignore") {
40
+ return;
41
+ }
42
+ throw error;
43
+ }
44
+ }
45
+
46
+ export function submitInteractionDraft<
47
+ Params extends InteractionParamsShape = InteractionParamsShape,
48
+ DefaultedKeys extends keyof Params & string = never,
49
+ >(
50
+ handle: InteractionHandle<Params, DefaultedKeys>,
51
+ callbacks: InteractionSubmitCallbacks = {},
52
+ options: { unhandledError?: UnhandledInteractionError } = {},
53
+ ): Promise<void> {
54
+ return runInteractionAction(() => handle.submitDraft(), {
55
+ onSuccess: callbacks.onSubmitSuccess,
56
+ onError: callbacks.onSubmitError,
57
+ unhandledError: options.unhandledError,
58
+ });
59
+ }
60
+
61
+ export function submitInteraction<
62
+ Params extends InteractionParamsShape = InteractionParamsShape,
63
+ DefaultedKeys extends keyof Params & string = never,
64
+ >(
65
+ handle: InteractionHandle<Params, DefaultedKeys>,
66
+ callbacks: InteractionSubmitCallbacks = {},
67
+ options: { unhandledError?: UnhandledInteractionError } = {},
68
+ ): Promise<void> {
69
+ return runInteractionAction(() => handle.submit(), {
70
+ onSuccess: callbacks.onSubmitSuccess,
71
+ onError: callbacks.onSubmitError,
72
+ unhandledError: options.unhandledError,
73
+ });
74
+ }
75
+
76
+ export function submitInteractionParams<
77
+ Params extends InteractionParamsShape = InteractionParamsShape,
78
+ DefaultedKeys extends keyof Params & string = never,
79
+ >(
80
+ handle: InteractionHandle<Params, DefaultedKeys>,
81
+ params: Params,
82
+ callbacks: InteractionSubmitCallbacks = {},
83
+ options: { unhandledError?: UnhandledInteractionError } = {},
84
+ ): Promise<void> {
85
+ return runInteractionAction(() => handle.submit(params), {
86
+ onSuccess: callbacks.onSubmitSuccess,
87
+ onError: callbacks.onSubmitError,
88
+ unhandledError: options.unhandledError,
89
+ });
90
+ }