@dreamboard-games/sdk 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +96 -0
- package/README.md +12 -0
- package/dist/HandView-ncJIVLhN.d.ts +193 -0
- package/dist/ResourceCounter-CTREyF73.d.ts +102 -0
- package/dist/ThemeProvider-fy0_QzgO.d.ts +99 -0
- package/dist/bundle-TIZcw8LB.d.ts +281 -0
- package/dist/cards-Sl3b40Mv.d.ts +13 -0
- package/dist/chunk-7YAHLYBR.js +481 -0
- package/dist/chunk-7YAHLYBR.js.map +1 -0
- package/dist/chunk-FDNZTDD6.js +8085 -0
- package/dist/chunk-FDNZTDD6.js.map +1 -0
- package/dist/chunk-GKKBPPSW.js +598 -0
- package/dist/chunk-GKKBPPSW.js.map +1 -0
- package/dist/chunk-I46YJSOD.js +1 -0
- package/dist/chunk-I46YJSOD.js.map +1 -0
- package/dist/chunk-KAELH4KC.js +104 -0
- package/dist/chunk-KAELH4KC.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-T3ZKNUZ7.js +1 -0
- package/dist/chunk-T3ZKNUZ7.js.map +1 -0
- package/dist/chunk-T52J5RMF.js +1 -0
- package/dist/chunk-T52J5RMF.js.map +1 -0
- package/dist/chunk-TDSWKVZ4.js +5401 -0
- package/dist/chunk-TDSWKVZ4.js.map +1 -0
- package/dist/chunk-U5C6BONG.js +34 -0
- package/dist/chunk-U5C6BONG.js.map +1 -0
- package/dist/chunk-VDXOF4FW.js +69 -0
- package/dist/chunk-VDXOF4FW.js.map +1 -0
- package/dist/chunk-VFTAA4WO.js +115 -0
- package/dist/chunk-VFTAA4WO.js.map +1 -0
- package/dist/chunk-WN74KVNY.js +17 -0
- package/dist/chunk-WN74KVNY.js.map +1 -0
- package/dist/chunk-WYPQ3GG5.js +10990 -0
- package/dist/chunk-WYPQ3GG5.js.map +1 -0
- package/dist/components-D5ZRE2Hl.d.ts +1451 -0
- package/dist/generated/runtime/primitives.d.ts +12 -0
- package/dist/generated/runtime/primitives.js +180 -0
- package/dist/generated/runtime/primitives.js.map +1 -0
- package/dist/generated/runtime-api.d.ts +3 -0
- package/dist/generated/runtime-api.js +2 -0
- package/dist/generated/runtime-api.js.map +1 -0
- package/dist/generated/runtime.d.ts +14 -0
- package/dist/generated/runtime.js +18 -0
- package/dist/generated/runtime.js.map +1 -0
- package/dist/generated/workspace-contract.d.ts +14 -0
- package/dist/generated/workspace-contract.js +14 -0
- package/dist/generated/workspace-contract.js.map +1 -0
- package/dist/hex-board-view-D_07hO6O.d.ts +933 -0
- package/dist/hex-color-MhOyuY-o.d.ts +8 -0
- package/dist/index-BwqPQtBu.d.ts +1433 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/reducer-bundle-abi.d.ts +1083 -0
- package/dist/infrastructure/reducer-bundle-abi.js +14 -0
- package/dist/infrastructure/reducer-bundle-abi.js.map +1 -0
- package/dist/infrastructure/workspace-codegen.d.ts +53 -0
- package/dist/infrastructure/workspace-codegen.js +44 -0
- package/dist/infrastructure/workspace-codegen.js.map +1 -0
- package/dist/manifest-contract-BNHVGFtU.d.ts +9 -0
- package/dist/package-set.d.ts +13 -0
- package/dist/package-set.js +12 -0
- package/dist/package-set.js.map +1 -0
- package/dist/primitive-props-DpKs-GCr.d.ts +11 -0
- package/dist/reducer.d.ts +3786 -0
- package/dist/reducer.js +8131 -0
- package/dist/reducer.js.map +1 -0
- package/dist/runtime/primitives.d.ts +226 -0
- package/dist/runtime/primitives.js +180 -0
- package/dist/runtime/primitives.js.map +1 -0
- package/dist/runtime/types/runtime-api.d.ts +1 -0
- package/dist/runtime/types/runtime-api.js +2 -0
- package/dist/runtime/types/runtime-api.js.map +1 -0
- package/dist/runtime/workspace-contract.d.ts +172 -0
- package/dist/runtime/workspace-contract.js +14 -0
- package/dist/runtime/workspace-contract.js.map +1 -0
- package/dist/runtime-api-3dshj6kK.d.ts +101 -0
- package/dist/runtime-api-DWxvTr-O.d.ts +379 -0
- package/dist/runtime.d.ts +58 -0
- package/dist/runtime.js +13 -0
- package/dist/runtime.js.map +1 -0
- package/dist/slots-1GPGihk8.d.ts +8 -0
- package/dist/testing.d.ts +149 -0
- package/dist/testing.js +513 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +496 -0
- package/dist/types.js +28 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/components.d.ts +16 -0
- package/dist/ui/components.js +192 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/defaults.d.ts +19 -0
- package/dist/ui/defaults.js +104 -0
- package/dist/ui/defaults.js.map +1 -0
- package/dist/ui/plugin-styles.css +250 -0
- package/dist/ui/types/player-state.d.ts +365 -0
- package/dist/ui/types/player-state.js +1 -0
- package/dist/ui/types/player-state.js.map +1 -0
- package/dist/ui-contract-iQfTtUSL.d.ts +1161 -0
- package/dist/ui.d.ts +320 -0
- package/dist/ui.js +253 -0
- package/dist/ui.js.map +1 -0
- package/package.json +199 -0
- package/src/generated/reducer-contract/builders.ts +90 -0
- package/src/generated/reducer-contract/version.ts +9 -0
- package/src/generated/reducer-contract/wire.ts +100 -0
- package/src/generated/reducer-contract/zod.ts +101 -0
- package/src/generated/runtime/primitives.ts +2 -0
- package/src/generated/runtime-api.ts +5 -0
- package/src/generated/runtime.ts +35 -0
- package/src/generated/workspace-contract.ts +2 -0
- package/src/index.ts +7 -0
- package/src/infrastructure/reducer-bundle-abi.ts +8 -0
- package/src/infrastructure/reducer-contract/bundle.ts +37 -0
- package/src/infrastructure/workspace-codegen/hex-geometry.ts +69 -0
- package/src/infrastructure/workspace-codegen/index.ts +64 -0
- package/src/infrastructure/workspace-codegen/manifest-contract.ts +6632 -0
- package/src/infrastructure/workspace-codegen/manifest-validation.ts +795 -0
- package/src/infrastructure/workspace-codegen/ownership.ts +131 -0
- package/src/infrastructure/workspace-codegen/preset-card-sets.ts +169 -0
- package/src/infrastructure/workspace-codegen/seeds.ts +1705 -0
- package/src/infrastructure/workspace-codegen.ts +1 -0
- package/src/package-set.ts +19 -0
- package/src/reducer/authoring/contract.ts +157 -0
- package/src/reducer/authoring/effect.ts +224 -0
- package/src/reducer/authoring/game.ts +23 -0
- package/src/reducer/authoring/interaction.ts +98 -0
- package/src/reducer/authoring/phase.ts +300 -0
- package/src/reducer/authoring/types.ts +70 -0
- package/src/reducer/authoring/validation.ts +382 -0
- package/src/reducer/authoring/view-stage.ts +68 -0
- package/src/reducer/authoring.ts +29 -0
- package/src/reducer/bundle/ingress-bundle.ts +491 -0
- package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +254 -0
- package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +73 -0
- package/src/reducer/bundle/trusted/instruction-runner.ts +414 -0
- package/src/reducer/bundle/trusted/interaction-authorization.ts +137 -0
- package/src/reducer/bundle/trusted/interaction-collectors.ts +859 -0
- package/src/reducer/bundle/trusted/interaction-decision.ts +747 -0
- package/src/reducer/bundle/trusted/interaction-resolver.ts +95 -0
- package/src/reducer/bundle/trusted/interaction-types.ts +171 -0
- package/src/reducer/bundle/trusted/lifecycle-runner.ts +427 -0
- package/src/reducer/bundle/trusted/projection-builder.ts +356 -0
- package/src/reducer/bundle/trusted/projection-context.ts +39 -0
- package/src/reducer/bundle/trusted/rng-sampler.ts +150 -0
- package/src/reducer/bundle/trusted/runtime-registry.ts +120 -0
- package/src/reducer/bundle/trusted/runtime-scope.ts +336 -0
- package/src/reducer/bundle/trusted/simultaneous-player.ts +97 -0
- package/src/reducer/bundle/trusted/stage-resolver.ts +87 -0
- package/src/reducer/bundle/trusted/static-projection.ts +116 -0
- package/src/reducer/bundle/trusted/trusted-runtime-args.ts +97 -0
- package/src/reducer/bundle/trusted/trusted-runtime-result.ts +39 -0
- package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +43 -0
- package/src/reducer/bundle/trusted/trusted-state-codec.ts +48 -0
- package/src/reducer/bundle/trusted-bundle.ts +97 -0
- package/src/reducer/bundle/types.ts +171 -0
- package/src/reducer/bundle.ts +2 -0
- package/src/reducer/client-param-schemas.ts +57 -0
- package/src/reducer/compose.ts +34 -0
- package/src/reducer/core/runtime-input.ts +30 -0
- package/src/reducer/core/runtime-instruction.ts +59 -0
- package/src/reducer/core/types.ts +62 -0
- package/src/reducer/definition-index.ts +277 -0
- package/src/reducer/derived.ts +106 -0
- package/src/reducer/effects.ts +92 -0
- package/src/reducer/engine/runtime-instruction-engine.ts +155 -0
- package/src/reducer/ingress/decode-runtime-input.ts +7 -0
- package/src/reducer/ingress/decode-session-state.ts +9 -0
- package/src/reducer/ingress/encode-session-state.ts +6 -0
- package/src/reducer/ingress/input-codec.ts +18 -0
- package/src/reducer/ingress/phase-schemas.ts +62 -0
- package/src/reducer/ingress/raw-types.ts +107 -0
- package/src/reducer/ingress/runtime-codec.ts +14 -0
- package/src/reducer/ingress/runtime-payload.ts +13 -0
- package/src/reducer/ingress/session-codec.ts +392 -0
- package/src/reducer/ingress/types.ts +6 -0
- package/src/reducer/inputs/boardInput.ts +217 -0
- package/src/reducer/inputs/boardTarget.ts +190 -0
- package/src/reducer/inputs/cardInput.ts +86 -0
- package/src/reducer/inputs/cardTarget.ts +101 -0
- package/src/reducer/inputs/choiceTarget.ts +104 -0
- package/src/reducer/inputs/defineInputs.ts +71 -0
- package/src/reducer/inputs/formInput.ts +809 -0
- package/src/reducer/inputs/many.ts +120 -0
- package/src/reducer/inputs/promptInput.ts +87 -0
- package/src/reducer/inputs/rngInput.ts +58 -0
- package/src/reducer/inputs/targetRule.ts +123 -0
- package/src/reducer/inputs.ts +41 -0
- package/src/reducer/model/definition.ts +1072 -0
- package/src/reducer/model/extract.ts +745 -0
- package/src/reducer/model/manifest.ts +570 -0
- package/src/reducer/model/queries.ts +641 -0
- package/src/reducer/model/runtime.ts +264 -0
- package/src/reducer/model/spec.ts +1386 -0
- package/src/reducer/model/table.ts +260 -0
- package/src/reducer/model.ts +7 -0
- package/src/reducer/ops.ts +1034 -0
- package/src/reducer/parse-utils.ts +28 -0
- package/src/reducer/per-player.ts +422 -0
- package/src/reducer/rng.ts +69 -0
- package/src/reducer/schema-helpers.ts +185 -0
- package/src/reducer/setup-bootstrap-helpers.ts +171 -0
- package/src/reducer/setup-bootstrap.ts +481 -0
- package/src/reducer/table-ops.ts +2671 -0
- package/src/reducer/table-queries.ts +372 -0
- package/src/reducer/transaction.ts +120 -0
- package/src/reducer.ts +314 -0
- package/src/runtime/primitives.ts +1 -0
- package/src/runtime/types/runtime-api.ts +1 -0
- package/src/runtime/workspace-contract.ts +32 -0
- package/src/runtime-internal/components/InteractionForm.tsx +1309 -0
- package/src/runtime-internal/components/PluginRuntime.tsx +103 -0
- package/src/runtime-internal/components/board/target-layer.ts +70 -0
- package/src/runtime-internal/context/ClientParamSchemaContext.tsx +44 -0
- package/src/runtime-internal/context/InteractionDraftContext.tsx +279 -0
- package/src/runtime-internal/context/PluginSessionContext.tsx +47 -0
- package/src/runtime-internal/context/PluginStateContext.tsx +262 -0
- package/src/runtime-internal/context/RuntimeContext.tsx +96 -0
- package/src/runtime-internal/defaults/components.tsx +409 -0
- package/src/runtime-internal/defaults/index.ts +11 -0
- package/src/runtime-internal/errors/ValidationError.ts +29 -0
- package/src/runtime-internal/hooks/useActivePlayers.ts +33 -0
- package/src/runtime-internal/hooks/useBoardInteractions.ts +665 -0
- package/src/runtime-internal/hooks/useGameSelector.ts +105 -0
- package/src/runtime-internal/hooks/useGameView.ts +9 -0
- package/src/runtime-internal/hooks/useInteractionByKey.ts +354 -0
- package/src/runtime-internal/hooks/useInteractionHandle.ts +438 -0
- package/src/runtime-internal/hooks/useIsMyTurn.ts +20 -0
- package/src/runtime-internal/hooks/useLobby.ts +76 -0
- package/src/runtime-internal/hooks/useMe.ts +48 -0
- package/src/runtime-internal/hooks/usePlayerInfo.ts +28 -0
- package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +23 -0
- package/src/runtime-internal/hooks/usePluginRuntime.ts +147 -0
- package/src/runtime-internal/hooks/useSeatInbox.ts +61 -0
- package/src/runtime-internal/hooks/useSimultaneousPhase.ts +10 -0
- package/src/runtime-internal/index.ts +42 -0
- package/src/runtime-internal/internal.ts +43 -0
- package/src/runtime-internal/plugin-styles.css +250 -0
- package/src/runtime-internal/primitives/board.tsx +459 -0
- package/src/runtime-internal/primitives/dialog-lifecycle.ts +58 -0
- package/src/runtime-internal/primitives/dice.tsx +79 -0
- package/src/runtime-internal/primitives/game-ui-provider.tsx +35 -0
- package/src/runtime-internal/primitives/game.tsx +387 -0
- package/src/runtime-internal/primitives/hand-intent-adapter.ts +147 -0
- package/src/runtime-internal/primitives/hand-surface.tsx +594 -0
- package/src/runtime-internal/primitives/index.ts +196 -0
- package/src/runtime-internal/primitives/interaction-form-binding.tsx +56 -0
- package/src/runtime-internal/primitives/interaction-submit.ts +90 -0
- package/src/runtime-internal/primitives/interaction.tsx +987 -0
- package/src/runtime-internal/primitives/phase.tsx +43 -0
- package/src/runtime-internal/primitives/player-roster.tsx +302 -0
- package/src/runtime-internal/primitives/primitive-props.tsx +101 -0
- package/src/runtime-internal/primitives/prompt.tsx +255 -0
- package/src/runtime-internal/primitives/ui.tsx +60 -0
- package/src/runtime-internal/primitives/zone.tsx +791 -0
- package/src/runtime-internal/reducer.ts +30 -0
- package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +605 -0
- package/src/runtime-internal/types/plugin-state.ts +508 -0
- package/src/runtime-internal/types/reducer-state.ts +24 -0
- package/src/runtime-internal/types/runtime-api.ts +114 -0
- package/src/runtime-internal/ui-contract.ts +519 -0
- package/src/runtime-internal/utils/card-intent-adapter.ts +546 -0
- package/src/runtime-internal/utils/interaction-inputs.ts +492 -0
- package/src/runtime-internal/utils/interaction-labels.ts +23 -0
- package/src/runtime-internal/utils/interaction-router.ts +273 -0
- package/src/runtime-internal/utils/interaction-status.ts +74 -0
- package/src/runtime-internal/workspace-contract.ts +1170 -0
- package/src/runtime.ts +34 -0
- package/src/testing/create-expect-api.ts +352 -0
- package/src/testing/create-test-runtime.ts +381 -0
- package/src/testing/definitions.ts +127 -0
- package/src/testing/index.ts +3 -0
- package/src/testing.ts +1 -0
- package/src/type-stubs/manifest-contract.d.ts +42 -0
- package/src/type-stubs/manifest-contract.js +72 -0
- package/src/type-stubs/ui-contract.d.ts +5 -0
- package/src/type-stubs/ui-contract.js +1 -0
- package/src/types/authoring-card-properties.type-test.ts +266 -0
- package/src/types/authoring.ts +1282 -0
- package/src/types/cards.ts +19 -0
- package/src/types/contracts.ts +1550 -0
- package/src/types/generated-helpers.ts +35 -0
- package/src/types/index.ts +147 -0
- package/src/types/slots.ts +11 -0
- package/src/types.ts +1 -0
- package/src/ui/components/ActionButton.tsx +97 -0
- package/src/ui/components/ActionPanel.tsx +315 -0
- package/src/ui/components/Card.tsx +378 -0
- package/src/ui/components/CardDragSurface.tsx +1076 -0
- package/src/ui/components/ChromeSuppressionContext.tsx +70 -0
- package/src/ui/components/CostDisplay.tsx +145 -0
- package/src/ui/components/DiceRoller.tsx +581 -0
- package/src/ui/components/Drawer.tsx +180 -0
- package/src/ui/components/ErrorBoundary.tsx +275 -0
- package/src/ui/components/GameEndDisplay.tsx +398 -0
- package/src/ui/components/GameSkeleton.tsx +260 -0
- package/src/ui/components/Hand.tsx +468 -0
- package/src/ui/components/HandDock.tsx +299 -0
- package/src/ui/components/HandView.tsx +441 -0
- package/src/ui/components/MobileHandTray.tsx +381 -0
- package/src/ui/components/MoreActions.tsx +143 -0
- package/src/ui/components/PhaseIndicator.tsx +341 -0
- package/src/ui/components/PlayArea.tsx +146 -0
- package/src/ui/components/PrimaryActionButton.tsx +336 -0
- package/src/ui/components/PrimaryButton.tsx +45 -0
- package/src/ui/components/ResourceCounter.tsx +270 -0
- package/src/ui/components/StagingZone.tsx +134 -0
- package/src/ui/components/ThemedButton.tsx +113 -0
- package/src/ui/components/Toast.tsx +264 -0
- package/src/ui/components/board/HexGrid.tsx +1294 -0
- package/src/ui/components/board/NetworkGraph.tsx +476 -0
- package/src/ui/components/board/SlotSystem.tsx +388 -0
- package/src/ui/components/board/SquareGrid.tsx +1165 -0
- package/src/ui/components/board/TrackBoard.tsx +496 -0
- package/src/ui/components/board/ZoneMap.tsx +448 -0
- package/src/ui/components/board/hex-board-view.ts +123 -0
- package/src/ui/components/board/index.ts +142 -0
- package/src/ui/components/board/interaction-accessibility.ts +21 -0
- package/src/ui/components/board/target-layer.ts +66 -0
- package/src/ui/components/card-render-content.type-test.ts +27 -0
- package/src/ui/components/hand-layout-math.ts +163 -0
- package/src/ui/components/hand-pointer-engine.ts +413 -0
- package/src/ui/components/index.ts +245 -0
- package/src/ui/components.ts +1 -0
- package/src/ui/defaults/components.tsx +106 -0
- package/src/ui/defaults/index.ts +8 -0
- package/src/ui/defaults.ts +1 -0
- package/src/ui/errors/ValidationError.ts +29 -0
- package/src/ui/helpers/cards.ts +19 -0
- package/src/ui/helpers/track-board.ts +211 -0
- package/src/ui/hooks/useBoardTopology.ts +316 -0
- package/src/ui/hooks/useCards.ts +10 -0
- package/src/ui/hooks/useHandCardPointer.ts +381 -0
- package/src/ui/hooks/useHandLayout.ts +378 -0
- package/src/ui/hooks/useHandPresentation.ts +121 -0
- package/src/ui/hooks/useHexBoard.ts +74 -0
- package/src/ui/hooks/useHexGrid.ts +185 -0
- package/src/ui/hooks/useIsMobile.ts +35 -0
- package/src/ui/hooks/usePanZoom.ts +278 -0
- package/src/ui/hooks/useSquareBoard.ts +124 -0
- package/src/ui/hooks/useSquareGrid.ts +328 -0
- package/src/ui/index.ts +98 -0
- package/src/ui/internal/ui/alert.tsx +51 -0
- package/src/ui/internal/ui/button.tsx +58 -0
- package/src/ui/internal/ui/dialog.tsx +134 -0
- package/src/ui/internal/ui/input.tsx +21 -0
- package/src/ui/internal/ui/label.tsx +21 -0
- package/src/ui/internal/ui/select.tsx +129 -0
- package/src/ui/internal/ui/tooltip.tsx +54 -0
- package/src/ui/internal/ui/utils.ts +5 -0
- package/src/ui/plugin-styles.css +250 -0
- package/src/ui/primitives/dialog-lifecycle.ts +58 -0
- package/src/ui/primitives/dice.tsx +79 -0
- package/src/ui/primitives/primitive-props.tsx +101 -0
- package/src/ui/theme/ThemeProvider.tsx +252 -0
- package/src/ui/theme/board.ts +61 -0
- package/src/ui/theme/css-vars.ts +105 -0
- package/src/ui/theme/derive.ts +240 -0
- package/src/ui/theme/index.ts +61 -0
- package/src/ui/theme/presets/arcade.ts +261 -0
- package/src/ui/theme/presets/studio.ts +261 -0
- package/src/ui/theme/presets/tabletop.ts +266 -0
- package/src/ui/theme/tokens.ts +392 -0
- package/src/ui/types/hex-color.ts +20 -0
- package/src/ui/types/player-state.ts +463 -0
- package/src/ui/types/tiled-board.ts +785 -0
- package/src/ui/types/visual-state.ts +137 -0
- package/src/ui.ts +1 -0
|
@@ -0,0 +1,987 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
type ButtonHTMLAttributes,
|
|
9
|
+
type HTMLAttributes,
|
|
10
|
+
type InputHTMLAttributes,
|
|
11
|
+
type ReactNode,
|
|
12
|
+
} from "react";
|
|
13
|
+
import {
|
|
14
|
+
useInteractionHandle,
|
|
15
|
+
type InteractionHandle,
|
|
16
|
+
type InteractionParamsShape,
|
|
17
|
+
} from "../hooks/useInteractionHandle.js";
|
|
18
|
+
import {
|
|
19
|
+
useInteractionUiStore,
|
|
20
|
+
usePendingInteractionKey,
|
|
21
|
+
usePendingInteractionRevision,
|
|
22
|
+
} from "../context/InteractionDraftContext.js";
|
|
23
|
+
import { usePluginState } from "../context/PluginStateContext.js";
|
|
24
|
+
import type { InteractionInputKey, InteractionKey } from "../ui-contract.js";
|
|
25
|
+
import type {
|
|
26
|
+
InteractionDescriptor,
|
|
27
|
+
InteractionInputDescriptor,
|
|
28
|
+
ZoneHandlesSnapshot,
|
|
29
|
+
} from "../types/plugin-state.js";
|
|
30
|
+
import {
|
|
31
|
+
hasInteractionFieldErrors,
|
|
32
|
+
inputByKey,
|
|
33
|
+
isBoardTargetDomain,
|
|
34
|
+
isResolvedTargetDomain,
|
|
35
|
+
isTargetDomain,
|
|
36
|
+
isManyTargetSelectable,
|
|
37
|
+
} from "../utils/interaction-inputs.js";
|
|
38
|
+
import {
|
|
39
|
+
getInteractionDraftReadiness,
|
|
40
|
+
markInteractionPending,
|
|
41
|
+
routeCardInputIntent,
|
|
42
|
+
shouldRouteInteractionPending,
|
|
43
|
+
} from "../utils/interaction-router.js";
|
|
44
|
+
import {
|
|
45
|
+
interactionUnavailableReason,
|
|
46
|
+
isInteractionAvailable,
|
|
47
|
+
} from "../utils/interaction-status.js";
|
|
48
|
+
import { interactionLabel } from "../utils/interaction-labels.js";
|
|
49
|
+
import {
|
|
50
|
+
composeEventHandlers,
|
|
51
|
+
renderPrimitive,
|
|
52
|
+
type PrimitiveCommonProps,
|
|
53
|
+
} from "./primitive-props.js";
|
|
54
|
+
import {
|
|
55
|
+
BoundInteractionForm,
|
|
56
|
+
castInteractionDraft,
|
|
57
|
+
castInteractionHandle,
|
|
58
|
+
type BoundInteractionFormProps,
|
|
59
|
+
} from "./interaction-form-binding.js";
|
|
60
|
+
import {
|
|
61
|
+
InteractionField as BaseInteractionField,
|
|
62
|
+
type InteractionFieldProps as BaseInteractionFieldProps,
|
|
63
|
+
} from "../components/InteractionForm.js";
|
|
64
|
+
import {
|
|
65
|
+
submitInteractionDraft,
|
|
66
|
+
submitInteractionParams,
|
|
67
|
+
type InteractionSubmitCallbacks,
|
|
68
|
+
} from "./interaction-submit.js";
|
|
69
|
+
import {
|
|
70
|
+
useDialogLifecycle,
|
|
71
|
+
type DialogLifecycleState,
|
|
72
|
+
} from "./dialog-lifecycle.js";
|
|
73
|
+
import { useGameActionError } from "./game.js";
|
|
74
|
+
import { useOptionalZonePrimitiveContext, useZoneCardContext } from "./zone.js";
|
|
75
|
+
|
|
76
|
+
interface InteractionContextValue {
|
|
77
|
+
interaction: string;
|
|
78
|
+
descriptor: InteractionDescriptor | null;
|
|
79
|
+
handle: ReturnType<typeof useInteractionHandle> | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const InteractionContext = createContext<InteractionContextValue | null>(null);
|
|
83
|
+
|
|
84
|
+
function humanizeInteraction(value: string): string {
|
|
85
|
+
const parts = value.split(".");
|
|
86
|
+
const leaf = parts[parts.length - 1] ?? value;
|
|
87
|
+
return leaf
|
|
88
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
89
|
+
.replace(/[-_]+/g, " ")
|
|
90
|
+
.replace(/\s+/g, " ")
|
|
91
|
+
.trim()
|
|
92
|
+
.replace(/^./, (first: string) => first.toUpperCase());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function useInteractionPrimitiveContext(): InteractionContextValue {
|
|
96
|
+
const value = useContext(InteractionContext);
|
|
97
|
+
if (!value) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
"Interaction primitives must be rendered inside <Interaction.Root>.",
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Live draft value for the active interaction's card-target input, resolved
|
|
107
|
+
* from the surrounding `<Interaction.Root>`. Returns the selected card-id array
|
|
108
|
+
* for `selection: "many"` inputs and the single id for `selection: "one"`.
|
|
109
|
+
* Returns `undefined` when there is no interaction context or no card-target
|
|
110
|
+
* input (so it is safe to render outside a root). Reactive: `handle.values`
|
|
111
|
+
* updates as the draft changes. Backs the card surface `slot.card.Value`.
|
|
112
|
+
*/
|
|
113
|
+
export function useResolvedCardTargetValue(): unknown {
|
|
114
|
+
const context = useContext(InteractionContext);
|
|
115
|
+
const descriptor = context?.descriptor;
|
|
116
|
+
const handle = context?.handle;
|
|
117
|
+
if (!descriptor || !handle) return undefined;
|
|
118
|
+
const cardInput = descriptor.inputs.find(
|
|
119
|
+
(input) =>
|
|
120
|
+
isTargetDomain(input.domain) && input.domain.type === "cardTarget",
|
|
121
|
+
);
|
|
122
|
+
if (!cardInput) return undefined;
|
|
123
|
+
return (handle.values as Record<string, unknown>)[cardInput.key];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function useInteractionDescriptor(interaction: string) {
|
|
127
|
+
return usePluginState((state) =>
|
|
128
|
+
state.gameplay.availableInteractions.find(
|
|
129
|
+
(descriptor) =>
|
|
130
|
+
descriptor.interactionKey === interaction ||
|
|
131
|
+
descriptor.interactionId === interaction,
|
|
132
|
+
),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface InteractionRootProps<
|
|
137
|
+
Interaction extends string = InteractionKey,
|
|
138
|
+
> {
|
|
139
|
+
interaction: Interaction;
|
|
140
|
+
children: ReactNode;
|
|
141
|
+
unavailable?: "render" | "hide";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function ResolvedInteractionRoot({
|
|
145
|
+
interaction,
|
|
146
|
+
descriptor,
|
|
147
|
+
children,
|
|
148
|
+
}: {
|
|
149
|
+
interaction: string;
|
|
150
|
+
descriptor: InteractionDescriptor;
|
|
151
|
+
children: ReactNode;
|
|
152
|
+
}) {
|
|
153
|
+
const handle = useInteractionHandle(descriptor);
|
|
154
|
+
const value = useMemo<InteractionContextValue>(
|
|
155
|
+
() => ({ interaction, descriptor, handle }),
|
|
156
|
+
[descriptor, handle, interaction],
|
|
157
|
+
);
|
|
158
|
+
return (
|
|
159
|
+
<InteractionContext.Provider value={value}>
|
|
160
|
+
{children}
|
|
161
|
+
</InteractionContext.Provider>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function InteractionRoot<Interaction extends string = InteractionKey>({
|
|
166
|
+
interaction,
|
|
167
|
+
children,
|
|
168
|
+
unavailable = "render",
|
|
169
|
+
}: InteractionRootProps<Interaction>) {
|
|
170
|
+
const descriptor = useInteractionDescriptor(interaction);
|
|
171
|
+
if (!descriptor) {
|
|
172
|
+
if (unavailable === "hide") return null;
|
|
173
|
+
return (
|
|
174
|
+
<InteractionContext.Provider
|
|
175
|
+
value={{
|
|
176
|
+
interaction,
|
|
177
|
+
descriptor: null,
|
|
178
|
+
handle: null,
|
|
179
|
+
}}
|
|
180
|
+
>
|
|
181
|
+
{children}
|
|
182
|
+
</InteractionContext.Provider>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (!isInteractionAvailable(descriptor) && unavailable === "hide") {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return (
|
|
189
|
+
<ResolvedInteractionRoot interaction={interaction} descriptor={descriptor}>
|
|
190
|
+
{children}
|
|
191
|
+
</ResolvedInteractionRoot>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export type InteractionDialogState = DialogLifecycleState;
|
|
196
|
+
|
|
197
|
+
export interface InteractionDialogRenderState<
|
|
198
|
+
Interaction extends string = InteractionKey,
|
|
199
|
+
> {
|
|
200
|
+
interaction: Interaction;
|
|
201
|
+
state: InteractionDialogState;
|
|
202
|
+
open: boolean;
|
|
203
|
+
minimized: boolean;
|
|
204
|
+
dismissed: boolean;
|
|
205
|
+
setOpen: (open: boolean) => void;
|
|
206
|
+
restore: () => void;
|
|
207
|
+
minimize: () => void;
|
|
208
|
+
dismiss: () => void;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface InteractionDialogProps<
|
|
212
|
+
Interaction extends string = InteractionKey,
|
|
213
|
+
> {
|
|
214
|
+
defaultOpen?: boolean;
|
|
215
|
+
onStateChange?: (state: InteractionDialogState) => void;
|
|
216
|
+
children: (state: InteractionDialogRenderState<Interaction>) => ReactNode;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function InteractionDialog<Interaction extends string = InteractionKey>({
|
|
220
|
+
defaultOpen = false,
|
|
221
|
+
onStateChange,
|
|
222
|
+
children,
|
|
223
|
+
}: InteractionDialogProps<Interaction>) {
|
|
224
|
+
const { interaction } = useInteractionPrimitiveContext();
|
|
225
|
+
const pendingInteractionKey = usePendingInteractionKey();
|
|
226
|
+
const pendingInteractionRevision = usePendingInteractionRevision();
|
|
227
|
+
const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
|
|
228
|
+
const restoredRevisionRef = useRef<number | null>(null);
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
if (
|
|
231
|
+
pendingInteractionKey === interaction &&
|
|
232
|
+
restoredRevisionRef.current !== pendingInteractionRevision
|
|
233
|
+
) {
|
|
234
|
+
restoredRevisionRef.current = pendingInteractionRevision;
|
|
235
|
+
lifecycle.restore();
|
|
236
|
+
}
|
|
237
|
+
}, [
|
|
238
|
+
interaction,
|
|
239
|
+
lifecycle,
|
|
240
|
+
pendingInteractionKey,
|
|
241
|
+
pendingInteractionRevision,
|
|
242
|
+
]);
|
|
243
|
+
const renderState = useMemo<InteractionDialogRenderState<Interaction>>(
|
|
244
|
+
() => ({
|
|
245
|
+
interaction: interaction as Interaction,
|
|
246
|
+
...lifecycle,
|
|
247
|
+
}),
|
|
248
|
+
[interaction, lifecycle],
|
|
249
|
+
);
|
|
250
|
+
return <>{children(renderState)}</>;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface InteractionSwitchRenderState<
|
|
254
|
+
Interaction extends string = InteractionKey,
|
|
255
|
+
> {
|
|
256
|
+
interaction: Interaction;
|
|
257
|
+
descriptor: InteractionDescriptor<Interaction>;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export type InteractionSwitchRouteMap<
|
|
261
|
+
Interaction extends string = InteractionKey,
|
|
262
|
+
> = {
|
|
263
|
+
[Key in Interaction]?: (
|
|
264
|
+
state: InteractionSwitchRenderState<Key>,
|
|
265
|
+
) => ReactNode;
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export interface InteractionRoute {
|
|
269
|
+
readonly collect: Record<string, unknown>;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export type InteractionRoutesMap<Interaction extends string = InteractionKey> =
|
|
273
|
+
{
|
|
274
|
+
[Key in Interaction]: InteractionRoute;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
export interface InteractionSwitchProps<
|
|
278
|
+
Interaction extends string = InteractionKey,
|
|
279
|
+
> {
|
|
280
|
+
interaction?: Interaction;
|
|
281
|
+
routes: InteractionSwitchRouteMap<Interaction>;
|
|
282
|
+
fallback?: ReactNode;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function InteractionSwitch<Interaction extends string = InteractionKey>({
|
|
286
|
+
interaction,
|
|
287
|
+
routes,
|
|
288
|
+
fallback = null,
|
|
289
|
+
}: InteractionSwitchProps<Interaction>) {
|
|
290
|
+
const pendingInteractionKey = usePendingInteractionKey();
|
|
291
|
+
const descriptors = usePluginState(
|
|
292
|
+
(state) => state.gameplay.availableInteractions,
|
|
293
|
+
);
|
|
294
|
+
const routedInteraction = interaction ?? pendingInteractionKey;
|
|
295
|
+
const descriptor = routedInteraction
|
|
296
|
+
? descriptors.find(
|
|
297
|
+
(candidate) => candidate.interactionKey === routedInteraction,
|
|
298
|
+
)
|
|
299
|
+
: undefined;
|
|
300
|
+
if (!descriptor) return <>{fallback}</>;
|
|
301
|
+
const route =
|
|
302
|
+
routes[descriptor.interactionKey as keyof typeof routes] ?? null;
|
|
303
|
+
if (!route) return <>{fallback}</>;
|
|
304
|
+
const typedInteraction = descriptor.interactionKey as Interaction;
|
|
305
|
+
return (
|
|
306
|
+
<InteractionRoot interaction={typedInteraction}>
|
|
307
|
+
{route({
|
|
308
|
+
interaction: typedInteraction,
|
|
309
|
+
descriptor: descriptor as InteractionDescriptor<Interaction>,
|
|
310
|
+
})}
|
|
311
|
+
</InteractionRoot>
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface InteractionRoutesProps<
|
|
316
|
+
Interaction extends string = InteractionKey,
|
|
317
|
+
> {
|
|
318
|
+
routes: InteractionRoutesMap<Interaction>;
|
|
319
|
+
fallback?: ReactNode;
|
|
320
|
+
includeUnavailable?: boolean | null;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const warnedInteractionRouteIssues = new Set<string>();
|
|
324
|
+
|
|
325
|
+
function warnInteractionRouteIssue(message: string) {
|
|
326
|
+
if (warnedInteractionRouteIssues.has(message)) return;
|
|
327
|
+
warnedInteractionRouteIssues.add(message);
|
|
328
|
+
console.warn(message);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function InteractionRoutes<Interaction extends string = InteractionKey>({
|
|
332
|
+
routes,
|
|
333
|
+
fallback = null,
|
|
334
|
+
includeUnavailable = false,
|
|
335
|
+
}: InteractionRoutesProps<Interaction>) {
|
|
336
|
+
const descriptors = usePluginState(
|
|
337
|
+
(state) => state.gameplay.availableInteractions,
|
|
338
|
+
);
|
|
339
|
+
if (descriptors.length === 0) return <>{fallback}</>;
|
|
340
|
+
const routedDescriptors = descriptors
|
|
341
|
+
.filter(
|
|
342
|
+
(descriptor) => includeUnavailable || isInteractionAvailable(descriptor),
|
|
343
|
+
)
|
|
344
|
+
.map((descriptor) => {
|
|
345
|
+
const interaction = descriptor.interactionKey as Interaction;
|
|
346
|
+
const route = routes[interaction as keyof typeof routes];
|
|
347
|
+
if (!route) {
|
|
348
|
+
warnInteractionRouteIssue(
|
|
349
|
+
`[dreamboard] Interaction.Routes is missing a collector route for "${descriptor.interactionKey}". Declare the interaction in routes so input collection stays explicit.`,
|
|
350
|
+
);
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
const missingInputs = descriptor.inputs
|
|
354
|
+
.map((input) => input.key)
|
|
355
|
+
.filter((input) => !(input in route.collect));
|
|
356
|
+
if (missingInputs.length > 0) {
|
|
357
|
+
warnInteractionRouteIssue(
|
|
358
|
+
`[dreamboard] Interaction.Routes route "${descriptor.interactionKey}" is missing collectors for: ${missingInputs.join(
|
|
359
|
+
", ",
|
|
360
|
+
)}.`,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
return descriptor;
|
|
364
|
+
});
|
|
365
|
+
if (routedDescriptors.length === 0) return <>{fallback}</>;
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export type InteractionPartProps = PrimitiveCommonProps &
|
|
370
|
+
HTMLAttributes<HTMLElement>;
|
|
371
|
+
|
|
372
|
+
export function InteractionLabel({ children, ...props }: InteractionPartProps) {
|
|
373
|
+
const { descriptor, interaction } = useInteractionPrimitiveContext();
|
|
374
|
+
return renderPrimitive("span", {
|
|
375
|
+
...props,
|
|
376
|
+
"data-dreamboard-interaction-label": "",
|
|
377
|
+
children:
|
|
378
|
+
children ??
|
|
379
|
+
(descriptor
|
|
380
|
+
? interactionLabel(descriptor)
|
|
381
|
+
: humanizeInteraction(interaction)),
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export function InteractionDescription({
|
|
386
|
+
children,
|
|
387
|
+
...props
|
|
388
|
+
}: InteractionPartProps) {
|
|
389
|
+
const content = children;
|
|
390
|
+
if (!content) return null;
|
|
391
|
+
return renderPrimitive("span", {
|
|
392
|
+
...props,
|
|
393
|
+
"data-dreamboard-interaction-description": "",
|
|
394
|
+
children: content,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export function InteractionUnavailableMessage({
|
|
399
|
+
children,
|
|
400
|
+
...props
|
|
401
|
+
}: InteractionPartProps) {
|
|
402
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
403
|
+
const reason =
|
|
404
|
+
children ??
|
|
405
|
+
handle?.unavailableReason ??
|
|
406
|
+
interactionUnavailableReason(descriptor);
|
|
407
|
+
if (!reason) return null;
|
|
408
|
+
return renderPrimitive("span", {
|
|
409
|
+
...props,
|
|
410
|
+
"data-dreamboard-interaction-unavailable": "",
|
|
411
|
+
children: reason,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
export function InteractionValidationMessage({
|
|
416
|
+
children,
|
|
417
|
+
...props
|
|
418
|
+
}: InteractionPartProps) {
|
|
419
|
+
const { handle } = useInteractionPrimitiveContext();
|
|
420
|
+
const validation = handle?.validateDraft();
|
|
421
|
+
const message =
|
|
422
|
+
children ??
|
|
423
|
+
validation?.formErrors[0] ??
|
|
424
|
+
Object.values(validation?.fieldErrors ?? {})[0]?.[0] ??
|
|
425
|
+
(validation?.missing[0]
|
|
426
|
+
? `${String(validation.missing[0])} is required.`
|
|
427
|
+
: null);
|
|
428
|
+
if (!message) return null;
|
|
429
|
+
return renderPrimitive("span", {
|
|
430
|
+
...props,
|
|
431
|
+
"data-dreamboard-interaction-validation": "",
|
|
432
|
+
children: message,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export type InteractionTriggerProps = PrimitiveCommonProps &
|
|
437
|
+
ButtonHTMLAttributes<HTMLButtonElement>;
|
|
438
|
+
|
|
439
|
+
export function InteractionTrigger({
|
|
440
|
+
disabled,
|
|
441
|
+
onClick,
|
|
442
|
+
...props
|
|
443
|
+
}: InteractionTriggerProps) {
|
|
444
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
445
|
+
const available = isInteractionAvailable(descriptor);
|
|
446
|
+
const isDisabled = disabled === true || !available;
|
|
447
|
+
return renderPrimitive("button", {
|
|
448
|
+
type: "button",
|
|
449
|
+
...props,
|
|
450
|
+
disabled: isDisabled,
|
|
451
|
+
"aria-disabled": isDisabled,
|
|
452
|
+
"data-dreamboard-interaction-trigger": "",
|
|
453
|
+
"data-interaction-id": descriptor?.interactionId,
|
|
454
|
+
"data-interaction-key": descriptor?.interactionKey,
|
|
455
|
+
"data-available": available,
|
|
456
|
+
"data-disabled": isDisabled || undefined,
|
|
457
|
+
"data-state": handle?.isArmed ? "armed" : "idle",
|
|
458
|
+
onClick: composeEventHandlers(onClick, () => {
|
|
459
|
+
handle?.arm();
|
|
460
|
+
}),
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export interface InteractionStateSnapshot<
|
|
465
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
466
|
+
DefaultedKeys extends keyof Params & string = never,
|
|
467
|
+
> {
|
|
468
|
+
interaction: string;
|
|
469
|
+
descriptor: InteractionDescriptor;
|
|
470
|
+
handle: InteractionHandle<Params, DefaultedKeys>;
|
|
471
|
+
draft: InteractionHandle<Params, DefaultedKeys>["draft"];
|
|
472
|
+
values: InteractionHandle<Params, DefaultedKeys>["values"];
|
|
473
|
+
status: InteractionHandle<Params, DefaultedKeys>["status"];
|
|
474
|
+
available: boolean;
|
|
475
|
+
isReady: boolean;
|
|
476
|
+
isArmed: boolean;
|
|
477
|
+
inputKeys: readonly string[];
|
|
478
|
+
missingInputs: readonly string[];
|
|
479
|
+
readyFrontier: readonly string[];
|
|
480
|
+
blockedInputs: readonly string[];
|
|
481
|
+
hasInputs: boolean;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export interface InteractionStateProps<
|
|
485
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
486
|
+
DefaultedKeys extends keyof Params & string = never,
|
|
487
|
+
> {
|
|
488
|
+
unavailable: ReactNode;
|
|
489
|
+
children: (
|
|
490
|
+
state: InteractionStateSnapshot<Params, DefaultedKeys>,
|
|
491
|
+
) => ReactNode;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function InteractionState<
|
|
495
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
496
|
+
DefaultedKeys extends keyof Params & string = never,
|
|
497
|
+
>({ children, unavailable }: InteractionStateProps<Params, DefaultedKeys>) {
|
|
498
|
+
const { interaction, descriptor, handle } = useInteractionPrimitiveContext();
|
|
499
|
+
const store = useInteractionUiStore();
|
|
500
|
+
if (!descriptor || !handle) {
|
|
501
|
+
return <>{unavailable}</>;
|
|
502
|
+
}
|
|
503
|
+
const typedHandle = castInteractionHandle<Params, DefaultedKeys>(handle);
|
|
504
|
+
const liveDraft = castInteractionDraft<Params, DefaultedKeys>(
|
|
505
|
+
store.getDraft(descriptor.interactionKey),
|
|
506
|
+
);
|
|
507
|
+
const inputKeys = descriptor.inputs.map((input) => input.key);
|
|
508
|
+
const readiness = getInteractionDraftReadiness(descriptor, liveDraft);
|
|
509
|
+
return (
|
|
510
|
+
<>
|
|
511
|
+
{children({
|
|
512
|
+
interaction,
|
|
513
|
+
descriptor,
|
|
514
|
+
handle: typedHandle,
|
|
515
|
+
draft: liveDraft,
|
|
516
|
+
values: typedHandle.values,
|
|
517
|
+
status: typedHandle.status,
|
|
518
|
+
available: typedHandle.available,
|
|
519
|
+
isReady: readiness.ready,
|
|
520
|
+
isArmed: typedHandle.isArmed,
|
|
521
|
+
inputKeys,
|
|
522
|
+
missingInputs: readiness.missingInputs,
|
|
523
|
+
readyFrontier: readiness.readyFrontier,
|
|
524
|
+
blockedInputs: readiness.blockedInputs,
|
|
525
|
+
hasInputs: inputKeys.length > 0,
|
|
526
|
+
})}
|
|
527
|
+
</>
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
export type InteractionFormPrimitiveProps<
|
|
532
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
533
|
+
DefaultedKeys extends keyof Params & string = never,
|
|
534
|
+
> = BoundInteractionFormProps<Params, DefaultedKeys>;
|
|
535
|
+
|
|
536
|
+
export function InteractionFormPrimitive<
|
|
537
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
538
|
+
DefaultedKeys extends keyof Params & string = never,
|
|
539
|
+
>(props: InteractionFormPrimitiveProps<Params, DefaultedKeys>) {
|
|
540
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
541
|
+
if (!descriptor || !handle) return null;
|
|
542
|
+
return (
|
|
543
|
+
<BoundInteractionForm<Params, DefaultedKeys>
|
|
544
|
+
descriptor={descriptor}
|
|
545
|
+
handle={handle}
|
|
546
|
+
{...props}
|
|
547
|
+
/>
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export type InteractionFieldPrimitiveProps<
|
|
552
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
553
|
+
Input extends keyof Params & string = keyof Params & string,
|
|
554
|
+
> = Omit<
|
|
555
|
+
BaseInteractionFieldProps<Params, Input>,
|
|
556
|
+
"descriptor" | "handle" | "inputKey"
|
|
557
|
+
> & {
|
|
558
|
+
input: Input;
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
export function InteractionFieldPrimitive<
|
|
562
|
+
Params extends InteractionParamsShape = InteractionParamsShape,
|
|
563
|
+
Input extends keyof Params & string = keyof Params & string,
|
|
564
|
+
>({ input, ...props }: InteractionFieldPrimitiveProps<Params, Input>) {
|
|
565
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
566
|
+
if (!descriptor || !handle) return null;
|
|
567
|
+
return (
|
|
568
|
+
<BaseInteractionField<Params, Input>
|
|
569
|
+
descriptor={descriptor}
|
|
570
|
+
handle={castInteractionHandle<Params>(handle)}
|
|
571
|
+
inputKey={input}
|
|
572
|
+
{...props}
|
|
573
|
+
/>
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export type InteractionSubmitProps = PrimitiveCommonProps &
|
|
578
|
+
ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
579
|
+
params?:
|
|
580
|
+
| InteractionParamsShape
|
|
581
|
+
| (() => InteractionParamsShape | null | undefined);
|
|
582
|
+
onSubmitSuccess?: InteractionSubmitCallbacks["onSubmitSuccess"];
|
|
583
|
+
onSubmitError?: InteractionSubmitCallbacks["onSubmitError"];
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
export function InteractionSubmit({
|
|
587
|
+
disabled,
|
|
588
|
+
onClick,
|
|
589
|
+
params,
|
|
590
|
+
onSubmitSuccess,
|
|
591
|
+
onSubmitError,
|
|
592
|
+
...props
|
|
593
|
+
}: InteractionSubmitProps) {
|
|
594
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
595
|
+
const gameActionError = useGameActionError();
|
|
596
|
+
const isSubmitting = handle?.status === "submitting";
|
|
597
|
+
const hasExplicitParams = params !== undefined;
|
|
598
|
+
const available = isInteractionAvailable(descriptor);
|
|
599
|
+
const isDisabled =
|
|
600
|
+
disabled === true ||
|
|
601
|
+
!available ||
|
|
602
|
+
(!hasExplicitParams && !handle?.isReady) ||
|
|
603
|
+
isSubmitting;
|
|
604
|
+
return renderPrimitive("button", {
|
|
605
|
+
type: "button",
|
|
606
|
+
...props,
|
|
607
|
+
disabled: isDisabled,
|
|
608
|
+
"aria-disabled": isDisabled,
|
|
609
|
+
"data-dreamboard-interaction-submit": "",
|
|
610
|
+
"data-interaction-id": descriptor?.interactionId,
|
|
611
|
+
"data-interaction-key": descriptor?.interactionKey,
|
|
612
|
+
"data-available": available,
|
|
613
|
+
"data-disabled": isDisabled || undefined,
|
|
614
|
+
"data-ready": handle?.isReady ?? false,
|
|
615
|
+
"data-has-inputs": descriptor ? descriptor.inputs.length > 0 : undefined,
|
|
616
|
+
"data-input-count": descriptor?.inputs.length,
|
|
617
|
+
"data-submitting": isSubmitting || undefined,
|
|
618
|
+
"data-state": handle?.status ?? "unavailable",
|
|
619
|
+
onClick: composeEventHandlers(onClick, () => {
|
|
620
|
+
if (isDisabled || !handle) return;
|
|
621
|
+
const resolvedParams = typeof params === "function" ? params() : params;
|
|
622
|
+
if (resolvedParams === null || resolvedParams === undefined) {
|
|
623
|
+
void submitInteractionDraft(handle, {
|
|
624
|
+
onSubmitSuccess,
|
|
625
|
+
onSubmitError: onSubmitError ?? gameActionError ?? undefined,
|
|
626
|
+
});
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
void submitInteractionParams(handle, resolvedParams, {
|
|
630
|
+
onSubmitSuccess,
|
|
631
|
+
onSubmitError: onSubmitError ?? gameActionError ?? undefined,
|
|
632
|
+
});
|
|
633
|
+
}),
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export type InteractionInputProps = PrimitiveCommonProps &
|
|
638
|
+
Omit<InputHTMLAttributes<HTMLInputElement>, "name"> & {
|
|
639
|
+
name: string;
|
|
640
|
+
parse?: (value: string) => unknown;
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
export function InteractionInput({
|
|
644
|
+
name,
|
|
645
|
+
parse,
|
|
646
|
+
onChange,
|
|
647
|
+
disabled,
|
|
648
|
+
...props
|
|
649
|
+
}: InteractionInputProps) {
|
|
650
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
651
|
+
const value = handle?.draft[name];
|
|
652
|
+
const isDisabled = disabled === true || !isInteractionAvailable(descriptor);
|
|
653
|
+
return renderPrimitive("input", {
|
|
654
|
+
...props,
|
|
655
|
+
name,
|
|
656
|
+
disabled: isDisabled,
|
|
657
|
+
"aria-disabled": isDisabled,
|
|
658
|
+
"data-dreamboard-interaction-input": "",
|
|
659
|
+
"data-input-name": name,
|
|
660
|
+
"data-disabled": isDisabled || undefined,
|
|
661
|
+
"data-selected": value !== undefined || undefined,
|
|
662
|
+
onChange: composeEventHandlers(onChange, (event) => {
|
|
663
|
+
const target = event.currentTarget;
|
|
664
|
+
handle?.setInput(name, parse ? parse(target.value) : target.value);
|
|
665
|
+
}),
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
export type InteractionCardInputProps<
|
|
670
|
+
Input extends string = InteractionInputKey,
|
|
671
|
+
> = PrimitiveCommonProps &
|
|
672
|
+
Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> & {
|
|
673
|
+
input: Input;
|
|
674
|
+
unsafeCardId?: string;
|
|
675
|
+
selected?: boolean;
|
|
676
|
+
onSelectedChange?: (selected: boolean) => void;
|
|
677
|
+
children?:
|
|
678
|
+
| ReactNode
|
|
679
|
+
| ((state: InteractionCardInputRenderState) => ReactNode);
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
export interface InteractionCardInputRenderState {
|
|
683
|
+
cardId: string | undefined;
|
|
684
|
+
zone: string | undefined;
|
|
685
|
+
selected: boolean;
|
|
686
|
+
disabled: boolean;
|
|
687
|
+
eligible: boolean;
|
|
688
|
+
targetValid: boolean;
|
|
689
|
+
selectable: boolean;
|
|
690
|
+
cardAvailable: boolean;
|
|
691
|
+
invalid: boolean;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
export function InteractionCardInput<
|
|
695
|
+
Input extends string = InteractionInputKey,
|
|
696
|
+
>({
|
|
697
|
+
input,
|
|
698
|
+
unsafeCardId,
|
|
699
|
+
selected,
|
|
700
|
+
onSelectedChange,
|
|
701
|
+
onClick,
|
|
702
|
+
disabled,
|
|
703
|
+
children,
|
|
704
|
+
...props
|
|
705
|
+
}: InteractionCardInputProps<Input>) {
|
|
706
|
+
const { descriptor, handle } = useInteractionPrimitiveContext();
|
|
707
|
+
const store = useInteractionUiStore();
|
|
708
|
+
const zoneCard = useZoneCardContext();
|
|
709
|
+
const zoneContext = useOptionalZonePrimitiveContext();
|
|
710
|
+
const cardId = zoneCard?.cardId ?? unsafeCardId;
|
|
711
|
+
const validationZone = zoneCard?.zone ?? zoneContext?.zone;
|
|
712
|
+
const zoneSnapshot = usePluginState((state) =>
|
|
713
|
+
validationZone ? state.gameplay.zones[validationZone] : undefined,
|
|
714
|
+
);
|
|
715
|
+
const cardDescriptor = usePluginState((state) => {
|
|
716
|
+
if (!cardId || !validationZone) return undefined;
|
|
717
|
+
return state.gameplay.zones[validationZone]?.playableByCardId[cardId]?.find(
|
|
718
|
+
(candidate) =>
|
|
719
|
+
candidate.interactionKey === descriptor?.interactionKey &&
|
|
720
|
+
candidate.inputs.some((candidateInput) => candidateInput.key === input),
|
|
721
|
+
);
|
|
722
|
+
});
|
|
723
|
+
const inputDescriptor = descriptor
|
|
724
|
+
? inputByKey(descriptor, input)
|
|
725
|
+
: undefined;
|
|
726
|
+
const targetInvalidReason = cardTargetInvalidReason({
|
|
727
|
+
cardDescriptor,
|
|
728
|
+
cardId,
|
|
729
|
+
inputDescriptor,
|
|
730
|
+
unsafeCardId,
|
|
731
|
+
validationZone,
|
|
732
|
+
zoneCard,
|
|
733
|
+
zoneSnapshot,
|
|
734
|
+
});
|
|
735
|
+
const isTargetValid = targetInvalidReason === undefined;
|
|
736
|
+
throwCardInputDevMismatch({
|
|
737
|
+
cardId,
|
|
738
|
+
targetInvalidReason,
|
|
739
|
+
unsafeCardId,
|
|
740
|
+
validationZone,
|
|
741
|
+
zoneCard,
|
|
742
|
+
});
|
|
743
|
+
const liveDraft = descriptor ? store.getDraft(descriptor.interactionKey) : {};
|
|
744
|
+
const currentValue =
|
|
745
|
+
liveDraft[input] ?? handle?.draft[input] ?? handle?.values[input];
|
|
746
|
+
const selection = isTargetDomain(inputDescriptor?.domain)
|
|
747
|
+
? inputDescriptor.domain.selection
|
|
748
|
+
: undefined;
|
|
749
|
+
const selectedByDraft =
|
|
750
|
+
selection?.mode === "many"
|
|
751
|
+
? Array.isArray(currentValue) &&
|
|
752
|
+
currentValue.map((item) => String(item)).includes(String(cardId))
|
|
753
|
+
: currentValue !== undefined &&
|
|
754
|
+
cardId !== undefined &&
|
|
755
|
+
String(currentValue) === String(cardId);
|
|
756
|
+
const isSelected = selected ?? selectedByDraft;
|
|
757
|
+
const descriptorAvailable = isInteractionAvailable(descriptor);
|
|
758
|
+
const cardDescriptorAvailable =
|
|
759
|
+
cardDescriptor === undefined
|
|
760
|
+
? undefined
|
|
761
|
+
: isInteractionAvailable(cardDescriptor);
|
|
762
|
+
const isCardAvailable =
|
|
763
|
+
cardDescriptorAvailable ?? (isTargetValid && descriptorAvailable);
|
|
764
|
+
const cardUnavailableReason =
|
|
765
|
+
interactionUnavailableReason(cardDescriptor) ??
|
|
766
|
+
(!descriptorAvailable
|
|
767
|
+
? (interactionUnavailableReason(descriptor) ?? "interaction-unavailable")
|
|
768
|
+
: undefined);
|
|
769
|
+
const isSelectable =
|
|
770
|
+
cardId !== undefined &&
|
|
771
|
+
inputDescriptor !== undefined &&
|
|
772
|
+
isManyTargetSelectable(inputDescriptor, currentValue, cardId);
|
|
773
|
+
const validation = handle?.validateDraft();
|
|
774
|
+
const fieldErrors = validation?.fieldErrors[input] ?? [];
|
|
775
|
+
const isInvalid = fieldErrors.length > 0;
|
|
776
|
+
const isDisabled =
|
|
777
|
+
disabled === true ||
|
|
778
|
+
!descriptorAvailable ||
|
|
779
|
+
!cardId ||
|
|
780
|
+
!isTargetValid ||
|
|
781
|
+
!isCardAvailable ||
|
|
782
|
+
!isSelectable ||
|
|
783
|
+
!handle;
|
|
784
|
+
|
|
785
|
+
const activateCardInput = useCallback(() => {
|
|
786
|
+
if (isDisabled || !descriptor || !cardId || !handle || !inputDescriptor) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const { params, readiness } = routeCardInputIntent(store, descriptor, {
|
|
790
|
+
cardInputKey: input,
|
|
791
|
+
cardId,
|
|
792
|
+
});
|
|
793
|
+
const hasMissingSurfaceTarget = readiness.readyFrontier.some((key) => {
|
|
794
|
+
const candidate = inputByKey(descriptor, key);
|
|
795
|
+
return (
|
|
796
|
+
candidate !== undefined &&
|
|
797
|
+
isBoardTargetDomain(candidate.domain) &&
|
|
798
|
+
candidate.domain.selection?.mode !== "many"
|
|
799
|
+
);
|
|
800
|
+
});
|
|
801
|
+
const hasMissingFormInput = readiness.readyFrontier.some((key) => {
|
|
802
|
+
const candidate = inputByKey(descriptor, key);
|
|
803
|
+
return (
|
|
804
|
+
candidate !== undefined &&
|
|
805
|
+
(!isTargetDomain(candidate.domain) ||
|
|
806
|
+
candidate.domain.selection?.mode === "many")
|
|
807
|
+
);
|
|
808
|
+
});
|
|
809
|
+
const hasFieldErrors = hasInteractionFieldErrors(readiness.fieldErrors);
|
|
810
|
+
if (shouldRouteInteractionPending(descriptor, readiness)) {
|
|
811
|
+
markInteractionPending(store, descriptor);
|
|
812
|
+
store.setPendingInteraction(
|
|
813
|
+
!hasMissingSurfaceTarget && (hasMissingFormInput || hasFieldErrors)
|
|
814
|
+
? descriptor.interactionKey
|
|
815
|
+
: null,
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
onSelectedChange?.(
|
|
819
|
+
selection?.mode === "many"
|
|
820
|
+
? Array.isArray(params[input]) && params[input].includes(cardId)
|
|
821
|
+
: true,
|
|
822
|
+
);
|
|
823
|
+
}, [
|
|
824
|
+
cardId,
|
|
825
|
+
descriptor,
|
|
826
|
+
handle,
|
|
827
|
+
input,
|
|
828
|
+
inputDescriptor,
|
|
829
|
+
isDisabled,
|
|
830
|
+
onSelectedChange,
|
|
831
|
+
selection,
|
|
832
|
+
store,
|
|
833
|
+
]);
|
|
834
|
+
|
|
835
|
+
const renderState: InteractionCardInputRenderState = {
|
|
836
|
+
cardId,
|
|
837
|
+
zone: validationZone,
|
|
838
|
+
selected: isSelected,
|
|
839
|
+
disabled: isDisabled,
|
|
840
|
+
eligible: isTargetValid && isCardAvailable,
|
|
841
|
+
targetValid: isTargetValid,
|
|
842
|
+
selectable: isSelectable,
|
|
843
|
+
cardAvailable: isCardAvailable,
|
|
844
|
+
invalid: isInvalid,
|
|
845
|
+
};
|
|
846
|
+
const renderedChildren =
|
|
847
|
+
typeof children === "function" ? children(renderState) : children;
|
|
848
|
+
|
|
849
|
+
return renderPrimitive("button", {
|
|
850
|
+
type: "button",
|
|
851
|
+
...props,
|
|
852
|
+
children: renderedChildren,
|
|
853
|
+
disabled: isDisabled,
|
|
854
|
+
"aria-disabled": isDisabled,
|
|
855
|
+
"aria-pressed": isSelected,
|
|
856
|
+
"data-dreamboard-interaction-card-input": "",
|
|
857
|
+
"data-input-name": input,
|
|
858
|
+
"data-card-id": cardId,
|
|
859
|
+
"data-zone": validationZone,
|
|
860
|
+
"data-selected": isSelected || undefined,
|
|
861
|
+
"data-eligible": isTargetValid && isCardAvailable,
|
|
862
|
+
"data-target-valid": isTargetValid,
|
|
863
|
+
"data-target-invalid-reason": targetInvalidReason,
|
|
864
|
+
"data-selectable": isSelectable,
|
|
865
|
+
"data-card-available": isCardAvailable,
|
|
866
|
+
"data-card-unavailable-reason": cardUnavailableReason,
|
|
867
|
+
"data-invalid": isInvalid || undefined,
|
|
868
|
+
"data-disabled": isDisabled || undefined,
|
|
869
|
+
"data-missing-resource": cardId ? undefined : true,
|
|
870
|
+
onClick: composeEventHandlers(onClick, () => {
|
|
871
|
+
activateCardInput();
|
|
872
|
+
}),
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
type CardTargetInvalidReason =
|
|
877
|
+
| "missing-card"
|
|
878
|
+
| "wrong-zone"
|
|
879
|
+
| "not-in-zone"
|
|
880
|
+
| "not-top-card"
|
|
881
|
+
| "not-in-domain";
|
|
882
|
+
|
|
883
|
+
function cardTargetInvalidReason({
|
|
884
|
+
cardDescriptor,
|
|
885
|
+
cardId,
|
|
886
|
+
inputDescriptor,
|
|
887
|
+
unsafeCardId,
|
|
888
|
+
validationZone,
|
|
889
|
+
zoneCard,
|
|
890
|
+
zoneSnapshot,
|
|
891
|
+
}: {
|
|
892
|
+
cardDescriptor: InteractionDescriptor | undefined;
|
|
893
|
+
cardId: string | undefined;
|
|
894
|
+
inputDescriptor: InteractionInputDescriptor | undefined;
|
|
895
|
+
unsafeCardId: string | undefined;
|
|
896
|
+
validationZone: string | undefined;
|
|
897
|
+
zoneCard: ReturnType<typeof useZoneCardContext>;
|
|
898
|
+
zoneSnapshot: ZoneHandlesSnapshot | undefined;
|
|
899
|
+
}): CardTargetInvalidReason | undefined {
|
|
900
|
+
if (!cardId) return "missing-card";
|
|
901
|
+
if (inputDescriptor?.domain.type !== "cardTarget") {
|
|
902
|
+
return "not-in-domain";
|
|
903
|
+
}
|
|
904
|
+
if (zoneCard && unsafeCardId && unsafeCardId !== zoneCard.cardId) {
|
|
905
|
+
return "wrong-zone";
|
|
906
|
+
}
|
|
907
|
+
if (
|
|
908
|
+
validationZone &&
|
|
909
|
+
zoneSnapshot &&
|
|
910
|
+
!zoneSnapshot.cardIds.includes(cardId)
|
|
911
|
+
) {
|
|
912
|
+
return "not-in-zone";
|
|
913
|
+
}
|
|
914
|
+
if (
|
|
915
|
+
validationZone &&
|
|
916
|
+
inputDescriptor.domain.zoneIds &&
|
|
917
|
+
!inputDescriptor.domain.zoneIds.includes(validationZone)
|
|
918
|
+
) {
|
|
919
|
+
return "wrong-zone";
|
|
920
|
+
}
|
|
921
|
+
if (validationZone && !cardDescriptor) {
|
|
922
|
+
return zoneSnapshot?.cardIds[0] !== cardId
|
|
923
|
+
? "not-top-card"
|
|
924
|
+
: "not-in-domain";
|
|
925
|
+
}
|
|
926
|
+
if (
|
|
927
|
+
!zoneCard &&
|
|
928
|
+
isResolvedTargetDomain(inputDescriptor.domain) &&
|
|
929
|
+
!inputDescriptor.domain.eligibleTargets.includes(cardId)
|
|
930
|
+
) {
|
|
931
|
+
return "not-in-domain";
|
|
932
|
+
}
|
|
933
|
+
return undefined;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
function throwCardInputDevMismatch({
|
|
937
|
+
cardId,
|
|
938
|
+
targetInvalidReason,
|
|
939
|
+
unsafeCardId,
|
|
940
|
+
validationZone,
|
|
941
|
+
zoneCard,
|
|
942
|
+
}: {
|
|
943
|
+
cardId: string | undefined;
|
|
944
|
+
targetInvalidReason: CardTargetInvalidReason | undefined;
|
|
945
|
+
unsafeCardId: string | undefined;
|
|
946
|
+
validationZone: string | undefined;
|
|
947
|
+
zoneCard: ReturnType<typeof useZoneCardContext>;
|
|
948
|
+
}) {
|
|
949
|
+
if (!isDevelopmentRuntime() || !validationZone) return;
|
|
950
|
+
if (zoneCard && unsafeCardId && unsafeCardId !== zoneCard.cardId) {
|
|
951
|
+
throw new Error(
|
|
952
|
+
`Interaction.CardInput unsafeCardId '${unsafeCardId}' does not match surrounding Zone.Item card '${zoneCard.cardId}'.`,
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
if (targetInvalidReason === "not-in-zone" && cardId) {
|
|
956
|
+
throw new Error(
|
|
957
|
+
`Interaction.CardInput card '${cardId}' is not present in surrounding zone '${validationZone}'.`,
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
function isDevelopmentRuntime(): boolean {
|
|
963
|
+
const processLike = (
|
|
964
|
+
globalThis as {
|
|
965
|
+
process?: { env?: { NODE_ENV?: string } };
|
|
966
|
+
}
|
|
967
|
+
).process;
|
|
968
|
+
return processLike?.env?.NODE_ENV !== "production";
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
export const Interaction = {
|
|
972
|
+
Root: InteractionRoot,
|
|
973
|
+
State: InteractionState,
|
|
974
|
+
Switch: InteractionSwitch,
|
|
975
|
+
Routes: InteractionRoutes,
|
|
976
|
+
Dialog: InteractionDialog,
|
|
977
|
+
Trigger: InteractionTrigger,
|
|
978
|
+
Label: InteractionLabel,
|
|
979
|
+
Description: InteractionDescription,
|
|
980
|
+
UnavailableMessage: InteractionUnavailableMessage,
|
|
981
|
+
ValidationMessage: InteractionValidationMessage,
|
|
982
|
+
Input: InteractionInput,
|
|
983
|
+
Field: InteractionFieldPrimitive,
|
|
984
|
+
CardInput: InteractionCardInput,
|
|
985
|
+
Form: InteractionFormPrimitive,
|
|
986
|
+
Submit: InteractionSubmit,
|
|
987
|
+
};
|