@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.
- package/dist/components/ActionButton.d.ts.map +1 -1
- package/dist/components/ActionButton.js +2 -1
- package/dist/components/Card.d.ts +1 -1
- package/dist/components/Card.d.ts.map +1 -1
- package/dist/components/DiceRoller.d.ts +3 -2
- package/dist/components/DiceRoller.d.ts.map +1 -1
- package/dist/components/DiceRoller.js +4 -13
- package/dist/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/ErrorBoundary.js +94 -2
- package/dist/components/InteractionForm.d.ts +1 -1
- package/dist/components/InteractionForm.d.ts.map +1 -1
- package/dist/components/InteractionForm.js +29 -15
- package/dist/components/PrimaryActionButton.d.ts.map +1 -1
- package/dist/components/PrimaryActionButton.js +7 -6
- package/dist/components/ResourceCounter.d.ts +59 -25
- package/dist/components/ResourceCounter.d.ts.map +1 -1
- package/dist/components/ResourceCounter.js +106 -115
- package/dist/components/Toast.d.ts +13 -6
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +10 -5
- package/dist/components/board/HexGrid.js +6 -6
- package/dist/components/board/target-layer.d.ts +18 -2
- package/dist/components/board/target-layer.d.ts.map +1 -1
- package/dist/components/board/target-layer.js +20 -3
- package/dist/components/index.d.ts +3 -4
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +3 -4
- package/dist/components/surfaces/InboxSurface.d.ts.map +1 -1
- package/dist/components/surfaces/InboxSurface.js +2 -6
- package/dist/components/surfaces/PlayerCardsSurface.js +2 -2
- package/dist/components/surfaces/internal/CardZoneRoutedForm.d.ts +7 -0
- package/dist/components/surfaces/internal/CardZoneRoutedForm.d.ts.map +1 -0
- package/dist/components/surfaces/internal/CardZoneRoutedForm.js +9 -0
- package/dist/components/surfaces/internal/DefaultInteractionButton.d.ts.map +1 -1
- package/dist/components/surfaces/internal/DefaultInteractionButton.js +5 -8
- package/dist/components/surfaces/internal/useCardZoneInteractions.d.ts +2 -2
- package/dist/components/surfaces/internal/useCardZoneInteractions.d.ts.map +1 -1
- package/dist/components/surfaces/internal/useCardZoneInteractions.js +19 -43
- package/dist/context/InteractionDraftContext.d.ts +11 -2
- package/dist/context/InteractionDraftContext.d.ts.map +1 -1
- package/dist/context/InteractionDraftContext.js +41 -4
- package/dist/defaults/components.d.ts +0 -5
- package/dist/defaults/components.d.ts.map +1 -1
- package/dist/defaults/components.js +7 -11
- package/dist/hooks/useBoardInteractions.d.ts +35 -12
- package/dist/hooks/useBoardInteractions.d.ts.map +1 -1
- package/dist/hooks/useBoardInteractions.js +186 -82
- package/dist/hooks/useInteractionHandle.d.ts +1 -1
- package/dist/hooks/useInteractionHandle.d.ts.map +1 -1
- package/dist/hooks/useInteractionHandle.js +12 -27
- package/dist/index.d.ts +11 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -14
- package/dist/primitives/board.d.ts +53 -3
- package/dist/primitives/board.d.ts.map +1 -1
- package/dist/primitives/board.js +65 -41
- package/dist/primitives/dialog-lifecycle.d.ts +17 -0
- package/dist/primitives/dialog-lifecycle.d.ts.map +1 -0
- package/dist/primitives/dialog-lifecycle.js +24 -0
- package/dist/primitives/dice.d.ts +31 -0
- package/dist/primitives/dice.d.ts.map +1 -0
- package/dist/primitives/dice.js +33 -0
- package/dist/primitives/game.d.ts +55 -0
- package/dist/primitives/game.d.ts.map +1 -0
- package/dist/primitives/game.js +101 -0
- package/dist/primitives/index.d.ts +7 -4
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +7 -4
- package/dist/primitives/interaction-form-binding.d.ts +12 -0
- package/dist/primitives/interaction-form-binding.d.ts.map +1 -0
- package/dist/primitives/interaction-form-binding.js +14 -0
- package/dist/primitives/interaction-submit.d.ts +23 -0
- package/dist/primitives/interaction-submit.d.ts.map +1 -0
- package/dist/primitives/interaction-submit.js +41 -0
- package/dist/primitives/interaction.d.ts +76 -6
- package/dist/primitives/interaction.d.ts.map +1 -1
- package/dist/primitives/interaction.js +210 -26
- package/dist/primitives/player-roster.d.ts +2 -1
- package/dist/primitives/player-roster.d.ts.map +1 -1
- package/dist/primitives/prompt.d.ts +36 -11
- package/dist/primitives/prompt.d.ts.map +1 -1
- package/dist/primitives/prompt.js +29 -17
- package/dist/primitives/ui.d.ts +9 -0
- package/dist/primitives/ui.d.ts.map +1 -0
- package/dist/primitives/ui.js +7 -0
- package/dist/primitives/zone.d.ts +111 -5
- package/dist/primitives/zone.d.ts.map +1 -1
- package/dist/primitives/zone.js +349 -9
- package/dist/reducer.d.ts +2 -14
- package/dist/reducer.d.ts.map +1 -1
- package/dist/reducer.js +1 -14
- package/dist/runtime/createPluginRuntimeAPI.js +1 -1
- package/dist/types/hex-color.d.ts +7 -0
- package/dist/types/hex-color.d.ts.map +1 -0
- package/dist/types/hex-color.js +13 -0
- package/dist/types/player-state.d.ts +28 -14
- package/dist/types/player-state.d.ts.map +1 -1
- package/dist/types/plugin-state.d.ts +9 -3
- package/dist/types/plugin-state.d.ts.map +1 -1
- package/dist/ui-contract.d.ts +119 -14
- package/dist/ui-contract.d.ts.map +1 -1
- package/dist/ui-contract.js +4 -3
- package/dist/ui-sdk.d.ts +1637 -1245
- package/dist/utils/interaction-inputs.d.ts +8 -5
- package/dist/utils/interaction-inputs.d.ts.map +1 -1
- package/dist/utils/interaction-inputs.js +82 -14
- package/dist/utils/interaction-router.d.ts +31 -0
- package/dist/utils/interaction-router.d.ts.map +1 -0
- package/dist/utils/interaction-router.js +114 -0
- package/package.json +1 -1
- package/src/components/ActionButton.tsx +2 -1
- package/src/components/Card.tsx +1 -1
- package/src/components/DiceRoller.tsx +13 -22
- package/src/components/ErrorBoundary.test.tsx +19 -0
- package/src/components/ErrorBoundary.tsx +113 -24
- package/src/components/InteractionForm.test.tsx +24 -0
- package/src/components/InteractionForm.tsx +48 -23
- package/src/components/PrimaryActionButton.tsx +19 -5
- package/src/components/ResourceCounter.test.tsx +13 -13
- package/src/components/ResourceCounter.tsx +238 -244
- package/src/components/Toast.tsx +23 -10
- package/src/components/__fixtures__/ResourceCounter.fixture.tsx +70 -169
- package/src/components/board/HexGrid.tsx +6 -6
- package/src/components/board/target-layer.ts +44 -5
- package/src/components/index.ts +17 -10
- package/src/components/surfaces/InboxSurface.tsx +7 -5
- package/src/components/surfaces/PlayerCardsSurface.tsx +6 -6
- package/src/components/surfaces/internal/CardZoneRoutedForm.tsx +35 -0
- package/src/components/surfaces/internal/DefaultInteractionButton.tsx +17 -7
- package/src/components/surfaces/internal/useCardZoneInteractions.ts +25 -67
- package/src/context/InteractionDraftContext.tsx +51 -5
- package/src/defaults/components.tsx +12 -50
- package/src/defaults/defaults.test.tsx +1 -50
- package/src/hooks/useBoardInteractions.test.tsx +240 -17
- package/src/hooks/useBoardInteractions.ts +330 -105
- package/src/hooks/useInteractionHandle.ts +23 -28
- package/src/index.test.ts +60 -40
- package/src/index.ts +30 -36
- package/src/primitives/board.test.tsx +73 -0
- package/src/primitives/board.tsx +191 -40
- package/src/primitives/dialog-lifecycle.ts +58 -0
- package/src/primitives/dice.test.tsx +47 -0
- package/src/primitives/dice.tsx +79 -0
- package/src/primitives/game.test.tsx +98 -0
- package/src/primitives/game.tsx +213 -0
- package/src/primitives/index.ts +84 -0
- package/src/primitives/interaction-form-binding.tsx +56 -0
- package/src/primitives/interaction-submit.ts +90 -0
- package/src/primitives/interaction.test.tsx +396 -0
- package/src/primitives/interaction.tsx +451 -31
- package/src/primitives/player-roster.tsx +2 -1
- package/src/primitives/prompt.test.tsx +94 -3
- package/src/primitives/prompt.tsx +87 -48
- package/src/primitives/ui.test.tsx +131 -0
- package/src/primitives/ui.tsx +13 -0
- package/src/primitives/zone.test.tsx +305 -0
- package/src/primitives/zone.tsx +660 -12
- package/src/reducer.ts +7 -20
- package/src/runtime/createPluginRuntimeAPI.ts +1 -1
- package/src/types/hex-color.ts +20 -0
- package/src/types/player-state.ts +36 -18
- package/src/types/plugin-state.ts +10 -3
- package/src/ui-contract.ts +253 -21
- package/src/utils/interaction-inputs.test.ts +400 -0
- package/src/utils/interaction-inputs.ts +113 -11
- package/src/utils/interaction-router.ts +200 -0
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ResourceCounter component fixtures
|
|
3
|
-
* Demonstrates resource display in various configurations
|
|
4
|
-
*/
|
|
5
1
|
import React, { useState } from "react";
|
|
6
2
|
import {
|
|
7
3
|
Coins,
|
|
8
|
-
TreePine,
|
|
9
|
-
Gem,
|
|
10
|
-
Zap,
|
|
11
|
-
Droplet,
|
|
12
|
-
Mountain,
|
|
13
4
|
Cpu,
|
|
5
|
+
Droplet,
|
|
6
|
+
Gem,
|
|
14
7
|
Leaf,
|
|
8
|
+
Mountain,
|
|
9
|
+
TreePine,
|
|
10
|
+
Zap,
|
|
15
11
|
} from "lucide-react";
|
|
16
12
|
import {
|
|
17
13
|
ResourceCounter,
|
|
@@ -20,77 +16,71 @@ import {
|
|
|
20
16
|
|
|
21
17
|
function Container({ children }: { children: React.ReactNode }) {
|
|
22
18
|
return (
|
|
23
|
-
<div className="min-h-screen bg-
|
|
24
|
-
<div className="max-w-2xl
|
|
19
|
+
<div className="min-h-screen bg-slate-950 p-8 text-white">
|
|
20
|
+
<div className="mx-auto max-w-2xl space-y-6">{children}</div>
|
|
25
21
|
</div>
|
|
26
22
|
);
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
// Fantasy game resources
|
|
30
25
|
const fantasyResources: ResourceDisplayConfig[] = [
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
icon: Coins,
|
|
35
|
-
iconColor: "text-yellow-400",
|
|
36
|
-
bgColor: "bg-yellow-900/30",
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
type: "wood",
|
|
40
|
-
label: "Wood",
|
|
41
|
-
icon: TreePine,
|
|
42
|
-
iconColor: "text-amber-600",
|
|
43
|
-
bgColor: "bg-amber-900/30",
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
type: "gems",
|
|
47
|
-
label: "Gems",
|
|
48
|
-
icon: Gem,
|
|
49
|
-
iconColor: "text-purple-400",
|
|
50
|
-
bgColor: "bg-purple-900/30",
|
|
51
|
-
},
|
|
26
|
+
{ type: "gold", label: "Gold", icon: Coins },
|
|
27
|
+
{ type: "wood", label: "Wood", icon: TreePine },
|
|
28
|
+
{ type: "gems", label: "Gems", icon: Gem },
|
|
52
29
|
];
|
|
53
30
|
|
|
54
|
-
// Sci-fi game resources (Catan-style)
|
|
55
31
|
const scifiResources: ResourceDisplayConfig[] = [
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
bgColor: "bg-amber-900/30",
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
type: "energy",
|
|
65
|
-
label: "Energy",
|
|
66
|
-
icon: Zap,
|
|
67
|
-
iconColor: "text-blue-400",
|
|
68
|
-
bgColor: "bg-blue-900/30",
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
type: "water",
|
|
72
|
-
label: "Water",
|
|
73
|
-
icon: Droplet,
|
|
74
|
-
iconColor: "text-cyan-400",
|
|
75
|
-
bgColor: "bg-cyan-900/30",
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
type: "tech",
|
|
79
|
-
label: "Tech Parts",
|
|
80
|
-
icon: Cpu,
|
|
81
|
-
iconColor: "text-purple-400",
|
|
82
|
-
bgColor: "bg-purple-900/30",
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
type: "bio",
|
|
86
|
-
label: "Bio-matter",
|
|
87
|
-
icon: Leaf,
|
|
88
|
-
iconColor: "text-green-400",
|
|
89
|
-
bgColor: "bg-green-900/30",
|
|
90
|
-
},
|
|
32
|
+
{ type: "minerals", label: "Minerals", icon: Mountain },
|
|
33
|
+
{ type: "energy", label: "Energy", icon: Zap },
|
|
34
|
+
{ type: "water", label: "Water", icon: Droplet },
|
|
35
|
+
{ type: "tech", label: "Tech Parts", icon: Cpu },
|
|
36
|
+
{ type: "bio", label: "Bio-matter", icon: Leaf },
|
|
91
37
|
];
|
|
92
38
|
|
|
93
|
-
|
|
39
|
+
const iconClassByResource: Record<string, string> = {
|
|
40
|
+
gold: "text-yellow-300",
|
|
41
|
+
wood: "text-amber-500",
|
|
42
|
+
gems: "text-fuchsia-300",
|
|
43
|
+
minerals: "text-stone-300",
|
|
44
|
+
energy: "text-sky-300",
|
|
45
|
+
water: "text-cyan-300",
|
|
46
|
+
tech: "text-violet-300",
|
|
47
|
+
bio: "text-emerald-300",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function DemoResourceCounter({
|
|
51
|
+
resources,
|
|
52
|
+
counts,
|
|
53
|
+
showZero = true,
|
|
54
|
+
onResourceClick,
|
|
55
|
+
}: {
|
|
56
|
+
resources: ResourceDisplayConfig[];
|
|
57
|
+
counts: Record<string, number>;
|
|
58
|
+
showZero?: boolean;
|
|
59
|
+
onResourceClick?: (type: string) => void;
|
|
60
|
+
}) {
|
|
61
|
+
return (
|
|
62
|
+
<ResourceCounter.Root
|
|
63
|
+
resources={resources}
|
|
64
|
+
counts={counts}
|
|
65
|
+
zero={showZero ? "show" : "hide"}
|
|
66
|
+
onResourceClick={onResourceClick}
|
|
67
|
+
className="flex flex-wrap gap-3"
|
|
68
|
+
>
|
|
69
|
+
<ResourceCounter.Item className="inline-flex items-center gap-2 rounded-md border border-slate-700 bg-slate-900 px-3 py-2 font-bold transition data-[interactive=true]:cursor-pointer data-[interactive=true]:border-slate-600 data-[interactive=true]:shadow-sm data-[interactive=true]:hover:border-slate-300 data-[resource-zero=true]:opacity-50">
|
|
70
|
+
{(resource) => (
|
|
71
|
+
<>
|
|
72
|
+
<ResourceCounter.Icon
|
|
73
|
+
className={`h-5 w-5 ${iconClassByResource[resource.type] ?? ""}`}
|
|
74
|
+
/>
|
|
75
|
+
<ResourceCounter.Count className="tabular-nums" />
|
|
76
|
+
<ResourceCounter.Label className="text-xs font-medium text-slate-400" />
|
|
77
|
+
</>
|
|
78
|
+
)}
|
|
79
|
+
</ResourceCounter.Item>
|
|
80
|
+
</ResourceCounter.Root>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
94
84
|
function InteractiveDemo() {
|
|
95
85
|
const [counts, setCounts] = useState<Record<string, number>>({
|
|
96
86
|
gold: 5,
|
|
@@ -98,27 +88,16 @@ function InteractiveDemo() {
|
|
|
98
88
|
gems: 1,
|
|
99
89
|
});
|
|
100
90
|
|
|
101
|
-
const handleClick = (type: string) => {
|
|
102
|
-
setCounts((prev) => ({
|
|
103
|
-
...prev,
|
|
104
|
-
[type]: (prev[type] ?? 0) + 1,
|
|
105
|
-
}));
|
|
106
|
-
};
|
|
107
|
-
|
|
108
91
|
return (
|
|
109
92
|
<Container>
|
|
110
|
-
<h2 className="text-xl font-bold
|
|
111
|
-
|
|
112
|
-
</h2>
|
|
113
|
-
<ResourceCounter
|
|
93
|
+
<h2 className="text-xl font-bold">Interactive Author Markup</h2>
|
|
94
|
+
<DemoResourceCounter
|
|
114
95
|
resources={fantasyResources}
|
|
115
96
|
counts={counts}
|
|
116
|
-
onResourceClick={
|
|
117
|
-
|
|
97
|
+
onResourceClick={(type) =>
|
|
98
|
+
setCounts((prev) => ({ ...prev, [type]: (prev[type] ?? 0) + 1 }))
|
|
99
|
+
}
|
|
118
100
|
/>
|
|
119
|
-
<p className="text-slate-400 text-sm mt-4">
|
|
120
|
-
Click any resource to add +1
|
|
121
|
-
</p>
|
|
122
101
|
</Container>
|
|
123
102
|
);
|
|
124
103
|
}
|
|
@@ -126,81 +105,18 @@ function InteractiveDemo() {
|
|
|
126
105
|
export default {
|
|
127
106
|
default: (
|
|
128
107
|
<Container>
|
|
129
|
-
<h2 className="text-xl font-bold
|
|
130
|
-
|
|
131
|
-
</h2>
|
|
132
|
-
<ResourceCounter
|
|
108
|
+
<h2 className="text-xl font-bold">Author Styled Resources</h2>
|
|
109
|
+
<DemoResourceCounter
|
|
133
110
|
resources={fantasyResources}
|
|
134
111
|
counts={{ gold: 5, wood: 3, gems: 1 }}
|
|
135
112
|
/>
|
|
136
113
|
</Container>
|
|
137
114
|
),
|
|
138
115
|
|
|
139
|
-
|
|
116
|
+
hiddenZeros: (
|
|
140
117
|
<Container>
|
|
141
|
-
<h2 className="text-xl font-bold
|
|
142
|
-
|
|
143
|
-
</h2>
|
|
144
|
-
<ResourceCounter
|
|
145
|
-
resources={scifiResources}
|
|
146
|
-
counts={{ minerals: 4, energy: 2, water: 3, tech: 1, bio: 5 }}
|
|
147
|
-
layout="grid"
|
|
148
|
-
columns={5}
|
|
149
|
-
/>
|
|
150
|
-
</Container>
|
|
151
|
-
),
|
|
152
|
-
|
|
153
|
-
compactLayout: (
|
|
154
|
-
<Container>
|
|
155
|
-
<h2 className="text-xl font-bold text-white mb-4">Compact Layout</h2>
|
|
156
|
-
<ResourceCounter
|
|
157
|
-
resources={fantasyResources}
|
|
158
|
-
counts={{ gold: 10, wood: 5, gems: 2 }}
|
|
159
|
-
layout="compact"
|
|
160
|
-
size="sm"
|
|
161
|
-
/>
|
|
162
|
-
</Container>
|
|
163
|
-
),
|
|
164
|
-
|
|
165
|
-
sizes: (
|
|
166
|
-
<Container>
|
|
167
|
-
<h2 className="text-xl font-bold text-white mb-4">Size Variants</h2>
|
|
168
|
-
<div className="space-y-6">
|
|
169
|
-
<div>
|
|
170
|
-
<p className="text-slate-400 text-sm mb-2">Small</p>
|
|
171
|
-
<ResourceCounter
|
|
172
|
-
resources={fantasyResources}
|
|
173
|
-
counts={{ gold: 5, wood: 3, gems: 1 }}
|
|
174
|
-
size="sm"
|
|
175
|
-
/>
|
|
176
|
-
</div>
|
|
177
|
-
<div>
|
|
178
|
-
<p className="text-slate-400 text-sm mb-2">Medium (Default)</p>
|
|
179
|
-
<ResourceCounter
|
|
180
|
-
resources={fantasyResources}
|
|
181
|
-
counts={{ gold: 5, wood: 3, gems: 1 }}
|
|
182
|
-
size="md"
|
|
183
|
-
/>
|
|
184
|
-
</div>
|
|
185
|
-
<div>
|
|
186
|
-
<p className="text-slate-400 text-sm mb-2">Large</p>
|
|
187
|
-
<ResourceCounter
|
|
188
|
-
resources={fantasyResources}
|
|
189
|
-
counts={{ gold: 5, wood: 3, gems: 1 }}
|
|
190
|
-
size="lg"
|
|
191
|
-
/>
|
|
192
|
-
</div>
|
|
193
|
-
</div>
|
|
194
|
-
</Container>
|
|
195
|
-
),
|
|
196
|
-
|
|
197
|
-
hideZeroValues: (
|
|
198
|
-
<Container>
|
|
199
|
-
<h2 className="text-xl font-bold text-white mb-4">Hide Zero Values</h2>
|
|
200
|
-
<p className="text-slate-400 text-sm mb-4">
|
|
201
|
-
Only showing resources with count {">"} 0
|
|
202
|
-
</p>
|
|
203
|
-
<ResourceCounter
|
|
118
|
+
<h2 className="text-xl font-bold">Filtered Resources</h2>
|
|
119
|
+
<DemoResourceCounter
|
|
204
120
|
resources={scifiResources}
|
|
205
121
|
counts={{ minerals: 4, energy: 0, water: 3, tech: 0, bio: 5 }}
|
|
206
122
|
showZero={false}
|
|
@@ -209,19 +125,4 @@ export default {
|
|
|
209
125
|
),
|
|
210
126
|
|
|
211
127
|
interactive: <InteractiveDemo />,
|
|
212
|
-
|
|
213
|
-
sciFiTheme: (
|
|
214
|
-
<Container>
|
|
215
|
-
<h2 className="text-xl font-bold text-white mb-4">
|
|
216
|
-
Sci-Fi Resources (Catan Style)
|
|
217
|
-
</h2>
|
|
218
|
-
<ResourceCounter
|
|
219
|
-
resources={scifiResources}
|
|
220
|
-
counts={{ minerals: 3, energy: 2, water: 1, tech: 4, bio: 2 }}
|
|
221
|
-
layout="grid"
|
|
222
|
-
columns={5}
|
|
223
|
-
size="md"
|
|
224
|
-
/>
|
|
225
|
-
</Container>
|
|
226
|
-
),
|
|
227
128
|
};
|
|
@@ -1053,7 +1053,7 @@ function HexGridImpl(
|
|
|
1053
1053
|
onClick={
|
|
1054
1054
|
isSelectable
|
|
1055
1055
|
? () => {
|
|
1056
|
-
void
|
|
1056
|
+
void state.select?.();
|
|
1057
1057
|
}
|
|
1058
1058
|
: undefined
|
|
1059
1059
|
}
|
|
@@ -1062,7 +1062,7 @@ function HexGridImpl(
|
|
|
1062
1062
|
event,
|
|
1063
1063
|
isSelectable
|
|
1064
1064
|
? () => {
|
|
1065
|
-
void
|
|
1065
|
+
void state.select?.();
|
|
1066
1066
|
}
|
|
1067
1067
|
: undefined,
|
|
1068
1068
|
)
|
|
@@ -1151,7 +1151,7 @@ function HexGridImpl(
|
|
|
1151
1151
|
onClick={
|
|
1152
1152
|
isSelectable
|
|
1153
1153
|
? () => {
|
|
1154
|
-
void
|
|
1154
|
+
void state.select?.();
|
|
1155
1155
|
}
|
|
1156
1156
|
: undefined
|
|
1157
1157
|
}
|
|
@@ -1160,7 +1160,7 @@ function HexGridImpl(
|
|
|
1160
1160
|
event,
|
|
1161
1161
|
isSelectable
|
|
1162
1162
|
? () => {
|
|
1163
|
-
void
|
|
1163
|
+
void state.select?.();
|
|
1164
1164
|
}
|
|
1165
1165
|
: undefined,
|
|
1166
1166
|
)
|
|
@@ -1226,7 +1226,7 @@ function HexGridImpl(
|
|
|
1226
1226
|
onClick={
|
|
1227
1227
|
isSelectable
|
|
1228
1228
|
? () => {
|
|
1229
|
-
void
|
|
1229
|
+
void state.select?.();
|
|
1230
1230
|
}
|
|
1231
1231
|
: undefined
|
|
1232
1232
|
}
|
|
@@ -1235,7 +1235,7 @@ function HexGridImpl(
|
|
|
1235
1235
|
event,
|
|
1236
1236
|
isSelectable
|
|
1237
1237
|
? () => {
|
|
1238
|
-
void
|
|
1238
|
+
void state.select?.();
|
|
1239
1239
|
}
|
|
1240
1240
|
: undefined,
|
|
1241
1241
|
)
|
|
@@ -1,10 +1,28 @@
|
|
|
1
|
+
import type { BoardTargetKind } from "../../utils/interaction-inputs.js";
|
|
2
|
+
|
|
3
|
+
export interface InteractiveTargetState {
|
|
4
|
+
kind?: BoardTargetKind;
|
|
5
|
+
id: string;
|
|
6
|
+
eligible: boolean;
|
|
7
|
+
selectable: boolean;
|
|
8
|
+
hovered: boolean;
|
|
9
|
+
interactionKey?: string;
|
|
10
|
+
interactionId?: string;
|
|
11
|
+
inputKey?: string;
|
|
12
|
+
pending: boolean;
|
|
13
|
+
conflict: boolean;
|
|
14
|
+
unavailableReason?: string;
|
|
15
|
+
select?: () => unknown | Promise<unknown>;
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
export interface InteractiveTargetLayer {
|
|
2
19
|
enabled?: boolean;
|
|
3
20
|
eligible?: ReadonlySet<string>;
|
|
4
|
-
selectTargetId?: (targetId: string) =>
|
|
21
|
+
selectTargetId?: (targetId: string) => unknown | Promise<unknown>;
|
|
22
|
+
targetState?: (targetId: string) => Partial<InteractiveTargetState>;
|
|
5
23
|
}
|
|
6
24
|
|
|
7
|
-
export interface InteractiveTargetRenderState {
|
|
25
|
+
export interface InteractiveTargetRenderState extends InteractiveTargetState {
|
|
8
26
|
isEnabled: boolean;
|
|
9
27
|
isEligible: boolean;
|
|
10
28
|
isHovered: boolean;
|
|
@@ -15,9 +33,26 @@ export function interactiveTargetRenderState(
|
|
|
15
33
|
targetId: string,
|
|
16
34
|
isHovered: boolean,
|
|
17
35
|
): InteractiveTargetRenderState {
|
|
36
|
+
const enabled = layer.enabled !== false;
|
|
37
|
+
const eligible = layer.eligible?.has(targetId) ?? true;
|
|
38
|
+
const extra = layer.targetState?.(targetId) ?? {};
|
|
39
|
+
const selectable =
|
|
40
|
+
extra.selectable ?? (enabled && eligible && !!layer.selectTargetId);
|
|
18
41
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
42
|
+
id: targetId,
|
|
43
|
+
...extra,
|
|
44
|
+
eligible: extra.eligible ?? eligible,
|
|
45
|
+
selectable,
|
|
46
|
+
hovered: isHovered,
|
|
47
|
+
pending: extra.pending ?? false,
|
|
48
|
+
conflict: extra.conflict ?? false,
|
|
49
|
+
select:
|
|
50
|
+
extra.select ??
|
|
51
|
+
(layer.selectTargetId
|
|
52
|
+
? () => layer.selectTargetId?.(targetId)
|
|
53
|
+
: undefined),
|
|
54
|
+
isEnabled: enabled,
|
|
55
|
+
isEligible: extra.eligible ?? eligible,
|
|
21
56
|
isHovered,
|
|
22
57
|
};
|
|
23
58
|
}
|
|
@@ -26,5 +61,9 @@ export function isInteractiveTargetSelectable(
|
|
|
26
61
|
layer: InteractiveTargetLayer,
|
|
27
62
|
state: InteractiveTargetRenderState,
|
|
28
63
|
): boolean {
|
|
29
|
-
return
|
|
64
|
+
return (
|
|
65
|
+
state.isEnabled &&
|
|
66
|
+
state.selectable &&
|
|
67
|
+
!!(state.select ?? layer.selectTargetId)
|
|
68
|
+
);
|
|
30
69
|
}
|
package/src/components/index.ts
CHANGED
|
@@ -16,9 +16,12 @@ export { PlayArea, type PlayAreaProps } from "./PlayArea.js";
|
|
|
16
16
|
// Other UI components
|
|
17
17
|
export { GameSkeleton, type GameSkeletonProps } from "./GameSkeleton.js";
|
|
18
18
|
export {
|
|
19
|
+
Toast,
|
|
20
|
+
ToastActions,
|
|
19
21
|
ToastProvider,
|
|
20
|
-
|
|
21
|
-
type
|
|
22
|
+
type ToastActionsProps,
|
|
23
|
+
type ToastActionsValue,
|
|
24
|
+
type ToastNotification,
|
|
22
25
|
type ToastType,
|
|
23
26
|
} from "./Toast.js";
|
|
24
27
|
export { ErrorBoundary, type ErrorBoundaryProps } from "./ErrorBoundary.js";
|
|
@@ -51,8 +54,20 @@ export {
|
|
|
51
54
|
// Game UI primitives (SDK v0.1.0+)
|
|
52
55
|
export {
|
|
53
56
|
ResourceCounter,
|
|
57
|
+
ResourceCounterCount,
|
|
58
|
+
ResourceCounterIcon,
|
|
59
|
+
ResourceCounterItem,
|
|
60
|
+
ResourceCounterLabel,
|
|
61
|
+
ResourceCounterRoot,
|
|
62
|
+
createResourceCounter,
|
|
63
|
+
type BoundResourceCounterRootProps,
|
|
64
|
+
type ResourceCounterComponents,
|
|
65
|
+
type ResourceCounterItemState,
|
|
66
|
+
type ResourceCounterPartProps,
|
|
54
67
|
type ResourceCounterProps,
|
|
68
|
+
type ResourceCounterRootProps,
|
|
55
69
|
type ResourceDisplayConfig,
|
|
70
|
+
type ResourceIconProps,
|
|
56
71
|
} from "./ResourceCounter.js";
|
|
57
72
|
export {
|
|
58
73
|
CostDisplay,
|
|
@@ -69,12 +84,8 @@ export {
|
|
|
69
84
|
} from "./PrimaryActionButton.js";
|
|
70
85
|
export {
|
|
71
86
|
InteractionForm,
|
|
72
|
-
InteractionField,
|
|
73
87
|
defaultFormInputs,
|
|
74
88
|
hasDefaultInteractionFormFields,
|
|
75
|
-
type InteractionFieldProps,
|
|
76
|
-
type InteractionFieldRenderMap,
|
|
77
|
-
type InteractionFieldRenderProps,
|
|
78
89
|
type InteractionFormProps,
|
|
79
90
|
} from "./InteractionForm.js";
|
|
80
91
|
export {
|
|
@@ -91,10 +102,6 @@ export {
|
|
|
91
102
|
type GameEndDisplayProps,
|
|
92
103
|
type PlayerScore,
|
|
93
104
|
} from "./GameEndDisplay.js";
|
|
94
|
-
export {
|
|
95
|
-
PromptDialogHost,
|
|
96
|
-
type PromptDialogHostProps,
|
|
97
|
-
} from "./PromptDialogHost.js";
|
|
98
105
|
|
|
99
106
|
// Board primitives (SDK v0.2.0+)
|
|
100
107
|
export {
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
} from "../../types/plugin-state.js";
|
|
13
13
|
import { interactionInputKeys } from "../../utils/interaction-inputs.js";
|
|
14
14
|
import { interactionLabel } from "../../utils/interaction-labels.js";
|
|
15
|
+
import { submitInteractionParams } from "../../primitives/interaction-submit.js";
|
|
15
16
|
import { DefaultInteractionButton } from "./internal/DefaultInteractionButton.js";
|
|
16
17
|
import { ThemedButton } from "../ThemedButton.js";
|
|
17
18
|
import type {
|
|
@@ -225,11 +226,12 @@ function PromptOptionsCard<
|
|
|
225
226
|
if (disabled || !inputKey) return;
|
|
226
227
|
setPendingOptionId(option.id);
|
|
227
228
|
try {
|
|
228
|
-
await
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
229
|
+
await submitInteractionParams(
|
|
230
|
+
handle,
|
|
231
|
+
{ [inputKey]: option.id } as Params,
|
|
232
|
+
{},
|
|
233
|
+
{ unhandledError: "ignore" },
|
|
234
|
+
);
|
|
233
235
|
} finally {
|
|
234
236
|
setPendingOptionId(null);
|
|
235
237
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
useCardZoneInteractions,
|
|
11
11
|
type CardZoneInteractionContext,
|
|
12
12
|
} from "./internal/useCardZoneInteractions.js";
|
|
13
|
-
import {
|
|
13
|
+
import { CardZoneRoutedForm } from "./internal/CardZoneRoutedForm.js";
|
|
14
14
|
import type { InteractionParamsByKeyShape } from "./types.js";
|
|
15
15
|
|
|
16
16
|
export type PlayerCardsLayout<ZoneKey extends string = string> =
|
|
@@ -511,12 +511,12 @@ function PlayerCardsFan<
|
|
|
511
511
|
);
|
|
512
512
|
}}
|
|
513
513
|
/>
|
|
514
|
-
{zone.
|
|
514
|
+
{zone.routedInteraction ? (
|
|
515
515
|
<Fragment>
|
|
516
|
-
<
|
|
517
|
-
key={zone.
|
|
518
|
-
descriptor={zone.
|
|
519
|
-
onDone={() => zone.
|
|
516
|
+
<CardZoneRoutedForm<I, ParamsByKey>
|
|
517
|
+
key={zone.routedInteraction.interactionKey}
|
|
518
|
+
descriptor={zone.routedInteraction}
|
|
519
|
+
onDone={() => zone.setRoutedInteraction(null)}
|
|
520
520
|
/>
|
|
521
521
|
</Fragment>
|
|
522
522
|
) : null}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { InteractionForm } from "../../InteractionForm.js";
|
|
2
|
+
import { useInteractionHandle } from "../../../hooks/useInteractionHandle.js";
|
|
3
|
+
import type { InteractionDescriptor } from "../../../types/plugin-state.js";
|
|
4
|
+
import type {
|
|
5
|
+
InteractionDefaultedKeysOf,
|
|
6
|
+
InteractionParamsByKeyShape,
|
|
7
|
+
InteractionParamsOf,
|
|
8
|
+
} from "../types.js";
|
|
9
|
+
|
|
10
|
+
export function CardZoneRoutedForm<
|
|
11
|
+
I extends string,
|
|
12
|
+
ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
|
|
13
|
+
>({
|
|
14
|
+
descriptor,
|
|
15
|
+
onDone,
|
|
16
|
+
}: {
|
|
17
|
+
descriptor: InteractionDescriptor<I>;
|
|
18
|
+
onDone: () => void;
|
|
19
|
+
}) {
|
|
20
|
+
const handle = useInteractionHandle<
|
|
21
|
+
InteractionParamsOf<ParamsByKey, I>,
|
|
22
|
+
InteractionDefaultedKeysOf<ParamsByKey, I>
|
|
23
|
+
>(descriptor);
|
|
24
|
+
return (
|
|
25
|
+
<InteractionForm
|
|
26
|
+
descriptor={descriptor}
|
|
27
|
+
handle={handle}
|
|
28
|
+
hiddenFields={[
|
|
29
|
+
"cardId" as keyof InteractionParamsOf<ParamsByKey, I> & string,
|
|
30
|
+
]}
|
|
31
|
+
onCancel={onDone}
|
|
32
|
+
onSubmitSuccess={onDone}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
InteractionForm,
|
|
11
11
|
hasDefaultInteractionFormFields,
|
|
12
12
|
} from "../../InteractionForm.js";
|
|
13
|
+
import {
|
|
14
|
+
submitInteractionDraft,
|
|
15
|
+
submitInteractionParams,
|
|
16
|
+
} from "../../../primitives/interaction-submit.js";
|
|
13
17
|
import { interactionLabel } from "../../../utils/interaction-labels.js";
|
|
14
18
|
import { ThemedButton } from "../../ThemedButton.js";
|
|
15
19
|
|
|
@@ -160,15 +164,21 @@ export function DefaultInteractionButton<
|
|
|
160
164
|
setPending(true);
|
|
161
165
|
try {
|
|
162
166
|
if (params !== undefined) {
|
|
163
|
-
await
|
|
167
|
+
await submitInteractionParams(
|
|
168
|
+
handle,
|
|
169
|
+
params as Params,
|
|
170
|
+
{},
|
|
171
|
+
{
|
|
172
|
+
unhandledError: "ignore",
|
|
173
|
+
},
|
|
174
|
+
);
|
|
164
175
|
} else {
|
|
165
|
-
await
|
|
176
|
+
await submitInteractionDraft(
|
|
177
|
+
handle,
|
|
178
|
+
{},
|
|
179
|
+
{ unhandledError: "ignore" },
|
|
180
|
+
);
|
|
166
181
|
}
|
|
167
|
-
} catch {
|
|
168
|
-
// Descriptor-level availability is authoritative; submission
|
|
169
|
-
// errors flow through the runtime's error channel. We swallow
|
|
170
|
-
// here so consumers without an error boundary don't see an
|
|
171
|
-
// unhandled rejection warning.
|
|
172
182
|
} finally {
|
|
173
183
|
setPending(false);
|
|
174
184
|
}
|