@dreamboard-games/cli 0.1.30-alpha.1 → 0.1.30-alpha.2

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 (114) hide show
  1. package/README.md +179 -22
  2. package/dist/{chunk-C6UAT6EH.js → chunk-N7XPNNUI.js} +9 -12
  3. package/dist/chunk-N7XPNNUI.js.map +1 -0
  4. package/dist/chunk-SEGVTWSK.js +44 -0
  5. package/dist/{chunk-RS7UXJZV.js → chunk-TAQKH67O.js} +21300 -35881
  6. package/dist/chunk-TAQKH67O.js.map +1 -0
  7. package/dist/{global-config-AGFBDFYD.js → global-config-S4ZIPECE.js} +3 -3
  8. package/dist/index.js +415 -37
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal.js +3 -4
  11. package/dist/{agent-verifier/keychain-backend-TNOPQV3Z.mjs → keychain-backend-HDF4TZDL.js} +2 -1
  12. package/dist/{agent-verifier/prompt-3BAINGAQ.mjs → prompt-NDV3AE5L.js} +2 -1
  13. package/package.json +6 -6
  14. package/skills/dreamboard/references/building-your-first-game.md +510 -0
  15. package/skills/dreamboard/references/cli.md +104 -0
  16. package/skills/dreamboard/references/game-interface.md +548 -0
  17. package/skills/dreamboard/references/manifest-authoring.md +597 -0
  18. package/skills/dreamboard/references/quickstart.md +66 -0
  19. package/skills/dreamboard/references/reducer.md +864 -0
  20. package/skills/dreamboard/references/rule-authoring.md +147 -0
  21. package/skills/dreamboard/references/testing.md +249 -0
  22. package/skills/dreamboard/scripts/events-extract.mjs +218 -0
  23. package/dist/agent-verifier/agent-workspace-verifier.mjs +0 -227
  24. package/dist/agent-verifier/chunk-2E5P5NWG.mjs +0 -835
  25. package/dist/agent-verifier/chunk-2GBBP27W.mjs +0 -301
  26. package/dist/agent-verifier/chunk-2QMNAVV4.mjs +0 -14522
  27. package/dist/agent-verifier/chunk-2SZHMP6F.mjs +0 -264
  28. package/dist/agent-verifier/chunk-4WD3YU2E.mjs +0 -166
  29. package/dist/agent-verifier/chunk-54TAYXUD.mjs +0 -12
  30. package/dist/agent-verifier/chunk-6A5HRJMQ.mjs +0 -3174
  31. package/dist/agent-verifier/chunk-6UUJEYDV.mjs +0 -213
  32. package/dist/agent-verifier/chunk-7653FPGJ.mjs +0 -381
  33. package/dist/agent-verifier/chunk-7E65UQLY.mjs +0 -38
  34. package/dist/agent-verifier/chunk-BVVNBJM4.mjs +0 -221
  35. package/dist/agent-verifier/chunk-CEDUHGNH.mjs +0 -74
  36. package/dist/agent-verifier/chunk-CEQ2VJWN.mjs +0 -149
  37. package/dist/agent-verifier/chunk-CFU5EWIC.mjs +0 -69
  38. package/dist/agent-verifier/chunk-CJEEA6NJ.mjs +0 -730
  39. package/dist/agent-verifier/chunk-EIQWDQWJ.mjs +0 -186
  40. package/dist/agent-verifier/chunk-EOQIV6PS.mjs +0 -649
  41. package/dist/agent-verifier/chunk-HBNDKQT5.mjs +0 -8381
  42. package/dist/agent-verifier/chunk-HJFQDSTU.mjs +0 -225
  43. package/dist/agent-verifier/chunk-JH22JNYD.mjs +0 -1681
  44. package/dist/agent-verifier/chunk-LI3ZR3BI.mjs +0 -41
  45. package/dist/agent-verifier/chunk-LM3OZLZG.mjs +0 -48
  46. package/dist/agent-verifier/chunk-MINCYHXN.mjs +0 -106
  47. package/dist/agent-verifier/chunk-MRCUP5SW.mjs +0 -128
  48. package/dist/agent-verifier/chunk-RBDDIIPM.mjs +0 -19
  49. package/dist/agent-verifier/chunk-SHUMAVAP.mjs +0 -59
  50. package/dist/agent-verifier/chunk-SYPLYRGB.mjs +0 -2812
  51. package/dist/agent-verifier/chunk-U6OJN7XS.mjs +0 -8092
  52. package/dist/agent-verifier/chunk-VYJTHSYR.mjs +0 -44
  53. package/dist/agent-verifier/chunk-XYDL7GY6.mjs +0 -10
  54. package/dist/agent-verifier/compile-5QSPIOUT.mjs +0 -313
  55. package/dist/agent-verifier/global-config-WX3ZZIVU.mjs +0 -17
  56. package/dist/agent-verifier/local-files-MTPLP62S.mjs +0 -46
  57. package/dist/agent-verifier/local-typecheck-QFYYAZOK.mjs +0 -9
  58. package/dist/agent-verifier/materialize-workspace-FKALAE2T.mjs +0 -90
  59. package/dist/agent-verifier/project-state-7GR6BQTQ.mjs +0 -32
  60. package/dist/agent-verifier/reducer-bundle-preflight-C73LEXI2.mjs +0 -23
  61. package/dist/agent-verifier/reducer-contract-preflight-22X7DSZW.mjs +0 -10
  62. package/dist/agent-verifier/reducer-native-test-harness-GMWBUISX.mjs +0 -53
  63. package/dist/agent-verifier/static-scaffold-AJMZZQWS.mjs +0 -28
  64. package/dist/agent-verifier/sync-3DUQH32H.mjs +0 -594
  65. package/dist/agent-verifier/test-P4U5INTD.mjs +0 -356
  66. package/dist/agent-verifier/testing-5K2BJYF2.mjs +0 -674
  67. package/dist/agent-verifier/workspace-codegen-JDZJRSDV.mjs +0 -11
  68. package/dist/agent-verifier/workspace-dependencies-HZ6VVS4G.mjs +0 -14
  69. package/dist/chunk-2H7UOFLK.js +0 -11
  70. package/dist/chunk-7FOO4AJI.js +0 -50
  71. package/dist/chunk-7FOO4AJI.js.map +0 -1
  72. package/dist/chunk-C6UAT6EH.js.map +0 -1
  73. package/dist/chunk-RS7UXJZV.js.map +0 -1
  74. package/dist/internal.d.ts +0 -311
  75. package/dist/keychain-backend-JHTXAKWC.js +0 -135
  76. package/dist/prompt-GMZABCJC.js +0 -756
  77. package/dist/runtime-packages/ui-host-runtime/src/actor-principal.ts +0 -71
  78. package/dist/runtime-packages/ui-host-runtime/src/browser-interaction.ts +0 -139
  79. package/dist/runtime-packages/ui-host-runtime/src/components/host-controls.tsx +0 -374
  80. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback-toaster.tsx +0 -266
  81. package/dist/runtime-packages/ui-host-runtime/src/components/host-feedback.tsx +0 -212
  82. package/dist/runtime-packages/ui-host-runtime/src/components/host-primitives.tsx +0 -271
  83. package/dist/runtime-packages/ui-host-runtime/src/components/host-session-metadata.tsx +0 -135
  84. package/dist/runtime-packages/ui-host-runtime/src/components/index.ts +0 -5
  85. package/dist/runtime-packages/ui-host-runtime/src/components/perf-overlay.tsx +0 -194
  86. package/dist/runtime-packages/ui-host-runtime/src/gameplay-authority-transport.ts +0 -626
  87. package/dist/runtime-packages/ui-host-runtime/src/host-controls.tsx +0 -1
  88. package/dist/runtime-packages/ui-host-runtime/src/host-feedback.tsx +0 -1
  89. package/dist/runtime-packages/ui-host-runtime/src/host-session-transport.ts +0 -294
  90. package/dist/runtime-packages/ui-host-runtime/src/index.ts +0 -3
  91. package/dist/runtime-packages/ui-host-runtime/src/logger.ts +0 -11
  92. package/dist/runtime-packages/ui-host-runtime/src/perf.ts +0 -324
  93. package/dist/runtime-packages/ui-host-runtime/src/plugin-bridge.ts +0 -195
  94. package/dist/runtime-packages/ui-host-runtime/src/plugin-health-check.ts +0 -138
  95. package/dist/runtime-packages/ui-host-runtime/src/plugin-messages.ts +0 -159
  96. package/dist/runtime-packages/ui-host-runtime/src/plugin-session-gateway.ts +0 -551
  97. package/dist/runtime-packages/ui-host-runtime/src/runtime/index.ts +0 -13
  98. package/dist/runtime-packages/ui-host-runtime/src/screenshot/projection-to-snapshot.ts +0 -122
  99. package/dist/runtime-packages/ui-host-runtime/src/screenshot/static-store-api.ts +0 -26
  100. package/dist/runtime-packages/ui-host-runtime/src/session-ingress-controller.ts +0 -583
  101. package/dist/runtime-packages/ui-host-runtime/src/session-ingress.ts +0 -219
  102. package/dist/runtime-packages/ui-host-runtime/src/session-live-runtime.ts +0 -117
  103. package/dist/runtime-packages/ui-host-runtime/src/session-model.ts +0 -431
  104. package/dist/runtime-packages/ui-host-runtime/src/session-projection.ts +0 -211
  105. package/dist/runtime-packages/ui-host-runtime/src/session-recovery.ts +0 -80
  106. package/dist/runtime-packages/ui-host-runtime/src/session-state-reducer.ts +0 -1034
  107. package/dist/runtime-packages/ui-host-runtime/src/sse-manager.ts +0 -416
  108. package/dist/runtime-packages/ui-host-runtime/src/unified-session-store.ts +0 -184
  109. package/dist/testing-KLSV6CPJ.js +0 -674
  110. package/dist/testing-KLSV6CPJ.js.map +0 -1
  111. /package/dist/{chunk-2H7UOFLK.js.map → chunk-SEGVTWSK.js.map} +0 -0
  112. /package/dist/{global-config-AGFBDFYD.js.map → global-config-S4ZIPECE.js.map} +0 -0
  113. /package/dist/{keychain-backend-JHTXAKWC.js.map → keychain-backend-HDF4TZDL.js.map} +0 -0
  114. /package/dist/{prompt-GMZABCJC.js.map → prompt-NDV3AE5L.js.map} +0 -0
@@ -1,266 +0,0 @@
1
- import { useEffect } from "react";
2
- import { Toaster, toast } from "sonner";
3
- import { AlertTriangle, Bell, Clock3, X } from "lucide-react";
4
- import {
5
- intentForVariant,
6
- surfaceStyle,
7
- useTheme,
8
- type ButtonVariant,
9
- type Theme,
10
- } from "@dreamboard-games/sdk/ui";
11
- import type { HostFeedback } from "../unified-session-store.js";
12
-
13
- export interface HostFeedbackToasterProps {
14
- feedback?: HostFeedback[];
15
- onDismiss?: (feedbackId: string) => void;
16
- }
17
-
18
- interface FeedbackPresentation {
19
- title: string;
20
- description: string;
21
- duration: number;
22
- variant: Extract<ButtonVariant, "danger" | "warning" | "success" | "info">;
23
- icon: typeof AlertTriangle;
24
- }
25
-
26
- function describeFeedback(item: HostFeedback): FeedbackPresentation {
27
- switch (item.type) {
28
- case "YOUR_TURN": {
29
- const activePlayerCount = item.payload.activePlayers.length;
30
- return {
31
- title: "Your turn",
32
- description:
33
- activePlayerCount > 1
34
- ? "You can act with one of your controlled players."
35
- : "You can act now.",
36
- duration: 3500,
37
- variant: "success",
38
- icon: Bell,
39
- };
40
- }
41
- case "PROMPT_OPENED": {
42
- const { targetPlayer, title } = item.payload;
43
- return {
44
- title: "Response needed",
45
- description: targetPlayer
46
- ? `${title ?? "A prompt is waiting."} (${targetPlayer})`
47
- : (title ?? "A prompt is waiting."),
48
- duration: 5000,
49
- variant: "warning",
50
- icon: Clock3,
51
- };
52
- }
53
- case "ACTION_REJECTED": {
54
- const reason = item.payload.targetPlayer
55
- ? `${item.payload.reason} (${item.payload.targetPlayer})`
56
- : item.payload.reason;
57
- return {
58
- title: "Action rejected",
59
- description: reason,
60
- duration: 5000,
61
- variant: "danger",
62
- icon: AlertTriangle,
63
- };
64
- }
65
- }
66
-
67
- const exhaustive: never = item;
68
- throw new Error(
69
- `Unsupported host feedback item type: ${String((exhaustive as { type?: unknown }).type)}`,
70
- );
71
- }
72
-
73
- interface HostFeedbackToastBodyProps {
74
- presentation: FeedbackPresentation;
75
- theme: Theme;
76
- onDismiss: () => void;
77
- }
78
-
79
- /**
80
- * Inner toast body. Rendered through sonner's `toast.custom` so the
81
- * surface is fully owned by the active {@link Theme} — no implicit
82
- * `richColors` styling, no hardcoded `bg-*` Tailwind classes.
83
- */
84
- function HostFeedbackToastBody({
85
- presentation,
86
- theme,
87
- onDismiss,
88
- }: HostFeedbackToastBodyProps) {
89
- const intent = intentForVariant(theme, presentation.variant);
90
- const Icon = presentation.icon;
91
- return (
92
- <div
93
- role="status"
94
- aria-live="polite"
95
- style={{
96
- ...surfaceStyle(theme, { tone: "card", radius: "lg" }),
97
- background: intent.soft,
98
- color: intent.onSoft,
99
- border: `1px solid ${intent.border}`,
100
- boxShadow: theme.elevation.lifted,
101
- display: "flex",
102
- alignItems: "flex-start",
103
- gap: theme.space[3],
104
- padding: theme.space[3],
105
- // Match sonner's default 356px so the toast lines up with
106
- // sibling toasts that may live inside the same stack.
107
- minWidth: 320,
108
- maxWidth: 420,
109
- fontFamily: theme.typography.fontFamily.body,
110
- }}
111
- >
112
- <Icon
113
- size={20}
114
- strokeWidth={2.5}
115
- aria-hidden="true"
116
- style={{
117
- flexShrink: 0,
118
- marginTop: 2,
119
- color: intent.solid,
120
- }}
121
- />
122
- <div style={{ flex: 1, minWidth: 0 }}>
123
- <div
124
- style={{
125
- fontFamily: theme.typography.fontFamily.display,
126
- fontSize: theme.typography.fontSize.md,
127
- fontWeight: theme.typography.fontWeight.bold,
128
- lineHeight: theme.typography.lineHeight.tight,
129
- color: intent.onSoft,
130
- }}
131
- >
132
- {presentation.title}
133
- </div>
134
- <div
135
- style={{
136
- marginTop: theme.space[1],
137
- fontSize: theme.typography.fontSize.sm,
138
- fontWeight: theme.typography.fontWeight.medium,
139
- lineHeight: theme.typography.lineHeight.normal,
140
- color: intent.onSoft,
141
- opacity: 0.92,
142
- wordBreak: "break-word",
143
- }}
144
- >
145
- {presentation.description}
146
- </div>
147
- </div>
148
- <button
149
- type="button"
150
- aria-label="Dismiss notification"
151
- onClick={onDismiss}
152
- style={{
153
- flexShrink: 0,
154
- width: 28,
155
- height: 28,
156
- display: "inline-flex",
157
- alignItems: "center",
158
- justifyContent: "center",
159
- background: "transparent",
160
- border: "none",
161
- borderRadius: theme.radius.pill,
162
- color: intent.onSoft,
163
- cursor: "pointer",
164
- opacity: 0.7,
165
- transition: `opacity ${theme.motion.duration.fast} ${theme.motion.easing.out}`,
166
- }}
167
- onMouseEnter={(event) => {
168
- event.currentTarget.style.opacity = "1";
169
- }}
170
- onMouseLeave={(event) => {
171
- event.currentTarget.style.opacity = "0.7";
172
- }}
173
- >
174
- <X size={16} aria-hidden="true" />
175
- </button>
176
- </div>
177
- );
178
- }
179
-
180
- /**
181
- * Mounts a {@link Toaster} and dispatches host-feedback events as
182
- * themed sonner toasts.
183
- *
184
- * Implementation notes:
185
- *
186
- * - We use `toast.custom(jsx, { id })` with a stable `id` so sonner
187
- * deduplicates the same feedback id by itself. The previous
188
- * implementation tracked processed ids in a `useRef`, which reset
189
- * across remounts (StrictMode in dev, parent re-renders that swap
190
- * the toaster's key) and caused the "shows / disappears / shows
191
- * again" flicker. With sonner-owned dedup, remounts no longer
192
- * replay the queue.
193
- * - We render a fully themed body so the toast picks up the active
194
- * `useTheme()` palette, font stack, and elevation tokens. Sonner's
195
- * default `richColors` theme is intentionally not used because it
196
- * produces a parallel non-themeable colour scheme.
197
- * - Host feedback is the canonical home for `YOUR_TURN`,
198
- * `PROMPT_OPENED` and `ACTION_REJECTED`. The plugin-side
199
- * `<ToastProvider>` no longer mirrors these; consumers must pass
200
- * the explicit `feedback` array sourced from the unified session
201
- * store.
202
- */
203
- export function HostFeedbackToaster({
204
- feedback = [],
205
- onDismiss,
206
- }: HostFeedbackToasterProps) {
207
- const theme = useTheme();
208
-
209
- useEffect(() => {
210
- for (const item of feedback) {
211
- const presentation = describeFeedback(item);
212
- const dismiss = () => onDismiss?.(item.id);
213
-
214
- // `toast.custom(jsx, { id })` is idempotent — calling it again
215
- // with the same id updates the existing toast in place rather
216
- // than mounting a duplicate, which is exactly what we want for
217
- // host-feedback ids that may flow through several store
218
- // snapshots before being dismissed.
219
- toast.custom(
220
- (toastId) => (
221
- <HostFeedbackToastBody
222
- presentation={presentation}
223
- theme={theme}
224
- onDismiss={() => {
225
- toast.dismiss(toastId);
226
- dismiss();
227
- }}
228
- />
229
- ),
230
- {
231
- id: item.id,
232
- duration: presentation.duration,
233
- unstyled: true,
234
- onAutoClose: () => dismiss(),
235
- onDismiss: () => dismiss(),
236
- },
237
- );
238
- }
239
- }, [feedback, onDismiss, theme]);
240
-
241
- return (
242
- <Toaster
243
- position="top-center"
244
- // Disable `richColors` because we render fully themed bodies
245
- // via `toast.custom` and don't want sonner's default success /
246
- // error palette competing with the active theme.
247
- richColors={false}
248
- // Forward the OS-level theme hint so sonner's container
249
- // (backdrop, default text colour for any non-custom toasts)
250
- // matches the resolved Dreamboard theme mode.
251
- theme={theme.meta.mode === "dark" ? "dark" : "light"}
252
- toastOptions={{
253
- // We use unstyled toasts so the inner `HostFeedbackToastBody`
254
- // has full control. `unstyled: true` removes sonner's
255
- // built-in surface, padding and shadow.
256
- unstyled: true,
257
- // Make the offset match sonner's default but anchor to the
258
- // viewport with safe-area insets so the toast clears phone
259
- // notches.
260
- style: {
261
- marginTop: "env(safe-area-inset-top, 0px)",
262
- },
263
- }}
264
- />
265
- );
266
- }
@@ -1,212 +0,0 @@
1
- /**
2
- * Host-owned inline feedback stack.
3
- *
4
- * Visual styling is driven entirely by the active `@dreamboard-games/sdk/ui`
5
- * `Theme` so the stack re-skins with the rest of the host shell. The
6
- * earlier implementation relied on raw Tailwind colour classes
7
- * (`bg-emerald-500/10`, `text-amber-700`, …) which were untouchable
8
- * by the theme tokens.
9
- */
10
-
11
- import { AlertTriangle, Bell, Clock3, X } from "lucide-react";
12
- import {
13
- intentForVariant,
14
- surfaceStyle,
15
- useTheme,
16
- type ButtonVariant,
17
- type Theme,
18
- } from "@dreamboard-games/sdk/ui";
19
- import type { HostFeedback } from "../unified-session-store.js";
20
-
21
- export interface HostFeedbackStackProps {
22
- feedback: HostFeedback[];
23
- onDismiss?: (feedbackId: string) => void;
24
- className?: string;
25
- }
26
-
27
- interface StackPresentation {
28
- title: string;
29
- description: string;
30
- variant: Extract<ButtonVariant, "danger" | "warning" | "success" | "info">;
31
- icon: typeof AlertTriangle;
32
- }
33
-
34
- function describeFeedback(item: HostFeedback): StackPresentation {
35
- switch (item.type) {
36
- case "YOUR_TURN": {
37
- const description =
38
- item.payload.activePlayers.length > 1
39
- ? "You can act with one of your controlled players."
40
- : "You can act now.";
41
- return {
42
- title: "Your turn",
43
- description,
44
- variant: "success",
45
- icon: Bell,
46
- };
47
- }
48
- case "PROMPT_OPENED": {
49
- const payload = item.payload;
50
- const description = payload.targetPlayer
51
- ? `${payload.title ?? "A prompt is waiting."} (${payload.targetPlayer})`
52
- : (payload.title ?? "A prompt is waiting.");
53
- return {
54
- title: "Response needed",
55
- description,
56
- variant: "warning",
57
- icon: Clock3,
58
- };
59
- }
60
- case "ACTION_REJECTED": {
61
- const payload = item.payload;
62
- const description = payload.targetPlayer
63
- ? `${payload.reason} (${payload.targetPlayer})`
64
- : payload.reason;
65
- return {
66
- title: "Action rejected",
67
- description,
68
- variant: "danger",
69
- icon: AlertTriangle,
70
- };
71
- }
72
- }
73
-
74
- const exhaustive: never = item;
75
- throw new Error(
76
- `Unsupported host feedback item type: ${String((exhaustive as { type?: unknown }).type)}`,
77
- );
78
- }
79
-
80
- interface FeedbackEntryProps {
81
- item: HostFeedback;
82
- presentation: StackPresentation;
83
- theme: Theme;
84
- onDismiss?: (feedbackId: string) => void;
85
- }
86
-
87
- function FeedbackEntry({
88
- item,
89
- presentation,
90
- theme,
91
- onDismiss,
92
- }: FeedbackEntryProps) {
93
- const intent = intentForVariant(theme, presentation.variant);
94
- const Icon = presentation.icon;
95
- return (
96
- <div
97
- role="status"
98
- aria-live="polite"
99
- style={{
100
- ...surfaceStyle(theme, { tone: "card", radius: "lg" }),
101
- background: intent.soft,
102
- color: intent.onSoft,
103
- border: `1px solid ${intent.border}`,
104
- boxShadow: theme.elevation.rest,
105
- display: "flex",
106
- alignItems: "flex-start",
107
- gap: theme.space[3],
108
- padding: theme.space[3],
109
- fontFamily: theme.typography.fontFamily.body,
110
- }}
111
- >
112
- <Icon
113
- size={20}
114
- strokeWidth={2.5}
115
- aria-hidden="true"
116
- style={{
117
- flexShrink: 0,
118
- marginTop: 2,
119
- color: intent.solid,
120
- }}
121
- />
122
- <div style={{ flex: 1, minWidth: 0 }}>
123
- <div
124
- style={{
125
- fontFamily: theme.typography.fontFamily.display,
126
- fontSize: theme.typography.fontSize.md,
127
- fontWeight: theme.typography.fontWeight.bold,
128
- lineHeight: theme.typography.lineHeight.tight,
129
- color: intent.onSoft,
130
- }}
131
- >
132
- {presentation.title}
133
- </div>
134
- <div
135
- style={{
136
- marginTop: theme.space[1],
137
- fontSize: theme.typography.fontSize.sm,
138
- fontWeight: theme.typography.fontWeight.medium,
139
- lineHeight: theme.typography.lineHeight.normal,
140
- color: intent.onSoft,
141
- opacity: 0.92,
142
- wordBreak: "break-word",
143
- }}
144
- >
145
- {presentation.description}
146
- </div>
147
- </div>
148
- {onDismiss ? (
149
- <button
150
- type="button"
151
- aria-label="Dismiss feedback"
152
- onClick={() => onDismiss(item.id)}
153
- style={{
154
- flexShrink: 0,
155
- width: 28,
156
- height: 28,
157
- display: "inline-flex",
158
- alignItems: "center",
159
- justifyContent: "center",
160
- background: "transparent",
161
- border: "none",
162
- borderRadius: theme.radius.pill,
163
- color: intent.onSoft,
164
- cursor: "pointer",
165
- opacity: 0.7,
166
- transition: `opacity ${theme.motion.duration.fast} ${theme.motion.easing.out}`,
167
- }}
168
- onMouseEnter={(event) => {
169
- event.currentTarget.style.opacity = "1";
170
- }}
171
- onMouseLeave={(event) => {
172
- event.currentTarget.style.opacity = "0.7";
173
- }}
174
- >
175
- <X size={16} aria-hidden="true" />
176
- </button>
177
- ) : null}
178
- </div>
179
- );
180
- }
181
-
182
- export function HostFeedbackStack({
183
- feedback,
184
- onDismiss,
185
- className,
186
- }: HostFeedbackStackProps) {
187
- const theme = useTheme();
188
- if (feedback.length === 0) {
189
- return null;
190
- }
191
-
192
- return (
193
- <div
194
- className={className}
195
- style={{
196
- display: "flex",
197
- flexDirection: "column",
198
- gap: theme.space[2],
199
- }}
200
- >
201
- {[...feedback].reverse().map((item) => (
202
- <FeedbackEntry
203
- key={item.id}
204
- item={item}
205
- presentation={describeFeedback(item)}
206
- theme={theme}
207
- onDismiss={onDismiss}
208
- />
209
- ))}
210
- </div>
211
- );
212
- }