@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,459 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useMemo,
|
|
5
|
+
type ButtonHTMLAttributes,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { useStore } from "zustand";
|
|
9
|
+
import {
|
|
10
|
+
createHexBoardView,
|
|
11
|
+
HexGrid,
|
|
12
|
+
type AnyHexBoardInput,
|
|
13
|
+
type BoardSpaceIdOf,
|
|
14
|
+
type HexBoardView,
|
|
15
|
+
type HexGridBoardProps,
|
|
16
|
+
} from "../../ui.js";
|
|
17
|
+
import {
|
|
18
|
+
useBoardInteractions,
|
|
19
|
+
type BoardInteractionsContext,
|
|
20
|
+
type BoardSelectionResult,
|
|
21
|
+
type BoardTargetLayerOptions,
|
|
22
|
+
} from "../hooks/useBoardInteractions.js";
|
|
23
|
+
import { usePluginState } from "../context/PluginStateContext.js";
|
|
24
|
+
import type { InteractionDescriptor } from "../types/plugin-state.js";
|
|
25
|
+
import type { BoardTargetKey } from "../ui-contract.js";
|
|
26
|
+
import {
|
|
27
|
+
eligibleTargetsForInput,
|
|
28
|
+
inputByKey,
|
|
29
|
+
inputKeyForTarget,
|
|
30
|
+
isResolvedTargetDomain,
|
|
31
|
+
resolveInputDomain,
|
|
32
|
+
type BoardTargetKind,
|
|
33
|
+
} from "../utils/interaction-inputs.js";
|
|
34
|
+
import {
|
|
35
|
+
composeEventHandlers,
|
|
36
|
+
renderPrimitive,
|
|
37
|
+
type PrimitiveCommonProps,
|
|
38
|
+
} from "./primitive-props.js";
|
|
39
|
+
import { runInteractionAction } from "./interaction-submit.js";
|
|
40
|
+
import { useGameActionError } from "./game.js";
|
|
41
|
+
import { isInteractionAvailable } from "../utils/interaction-status.js";
|
|
42
|
+
import { useInteractionUiStore } from "../context/InteractionDraftContext.js";
|
|
43
|
+
|
|
44
|
+
type BoardContextValue = BoardInteractionsContext;
|
|
45
|
+
|
|
46
|
+
const BoardContext = createContext<BoardContextValue | null>(null);
|
|
47
|
+
const warnedAmbiguousBoardTargets = new Set<string>();
|
|
48
|
+
|
|
49
|
+
function warnAmbiguousBoardTarget({
|
|
50
|
+
kind,
|
|
51
|
+
value,
|
|
52
|
+
interactionKeys,
|
|
53
|
+
}: {
|
|
54
|
+
kind: BoardTargetKind;
|
|
55
|
+
value: string;
|
|
56
|
+
interactionKeys: readonly string[];
|
|
57
|
+
}): void {
|
|
58
|
+
const key = `${kind}:${value}:${interactionKeys.join("|")}`;
|
|
59
|
+
if (warnedAmbiguousBoardTargets.has(key)) return;
|
|
60
|
+
warnedAmbiguousBoardTargets.add(key);
|
|
61
|
+
console.error(
|
|
62
|
+
`[dreamboard] Ambiguous Board.${kind} target "${value}" matched multiple available interactions: ${interactionKeys.join(
|
|
63
|
+
", ",
|
|
64
|
+
)}. Declare the real initiating collector in Interaction.Routes (for example, a card or form input), arm one interaction before collecting this board target, or render an explicit Board.Target interaction prop.`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function useBoardPrimitiveContext(): BoardContextValue {
|
|
69
|
+
const value = useContext(BoardContext);
|
|
70
|
+
if (!value) {
|
|
71
|
+
throw new Error("Board primitives must be rendered inside <Board.Root>.");
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface BoardRootProps extends PrimitiveCommonProps {
|
|
77
|
+
children: ReactNode;
|
|
78
|
+
targetKinds?: readonly BoardTargetKind[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function BoardRoot({ children, targetKinds, ...props }: BoardRootProps) {
|
|
82
|
+
const board = useBoardInteractions({ targetKinds });
|
|
83
|
+
return (
|
|
84
|
+
<BoardContext.Provider value={board}>
|
|
85
|
+
{renderPrimitive("div", {
|
|
86
|
+
...props,
|
|
87
|
+
"data-dreamboard-board-root": "",
|
|
88
|
+
children,
|
|
89
|
+
})}
|
|
90
|
+
</BoardContext.Provider>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface BoardStateProps {
|
|
95
|
+
children: (board: BoardInteractionsContext) => ReactNode;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function BoardState({ children }: BoardStateProps) {
|
|
99
|
+
return <>{children(useBoardPrimitiveContext())}</>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface BoardHexViewProps<
|
|
103
|
+
TBoard extends AnyHexBoardInput,
|
|
104
|
+
TSpaceView extends { id: BoardSpaceIdOf<TBoard> },
|
|
105
|
+
> {
|
|
106
|
+
board: TBoard;
|
|
107
|
+
spaces: readonly TSpaceView[];
|
|
108
|
+
children: (view: HexBoardView<TBoard, TSpaceView>) => ReactNode;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function BoardHexView<
|
|
112
|
+
const TBoard extends AnyHexBoardInput,
|
|
113
|
+
const TSpaceView extends { id: BoardSpaceIdOf<TBoard> },
|
|
114
|
+
>({ board, spaces, children }: BoardHexViewProps<TBoard, TSpaceView>) {
|
|
115
|
+
const view = useMemo(
|
|
116
|
+
() => createHexBoardView<TBoard, TSpaceView>(board, { spaces }),
|
|
117
|
+
[board, spaces],
|
|
118
|
+
);
|
|
119
|
+
return <>{children(view)}</>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface BoardHexGridInteractions {
|
|
123
|
+
edge?: BoardTargetLayerOptions;
|
|
124
|
+
vertex?: BoardTargetLayerOptions;
|
|
125
|
+
space?: BoardTargetLayerOptions;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export type BoardHexGridInteractionFilter =
|
|
129
|
+
| "auto"
|
|
130
|
+
| false
|
|
131
|
+
| {
|
|
132
|
+
edge?: readonly string[];
|
|
133
|
+
vertex?: readonly string[];
|
|
134
|
+
space?: readonly string[];
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
type BoardHexGridView<
|
|
138
|
+
TBoard extends AnyHexBoardInput,
|
|
139
|
+
TSpaceView extends { id: BoardSpaceIdOf<TBoard> },
|
|
140
|
+
> = HexBoardView<TBoard, TSpaceView> & AnyHexBoardInput;
|
|
141
|
+
|
|
142
|
+
export type BoardHexGridProps<
|
|
143
|
+
TBoard extends AnyHexBoardInput,
|
|
144
|
+
TSpaceView extends { id: BoardSpaceIdOf<TBoard> },
|
|
145
|
+
> = Omit<
|
|
146
|
+
HexGridBoardProps<BoardHexGridView<TBoard, TSpaceView>>,
|
|
147
|
+
"board" | "interactiveEdges" | "interactiveVertices" | "interactiveSpaces"
|
|
148
|
+
> &
|
|
149
|
+
Omit<BoardHexViewProps<TBoard, TSpaceView>, "children"> & {
|
|
150
|
+
interactions?: BoardHexGridInteractionFilter;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export function BoardHexGrid<
|
|
154
|
+
const TBoard extends AnyHexBoardInput,
|
|
155
|
+
const TSpaceView extends { id: BoardSpaceIdOf<TBoard> },
|
|
156
|
+
>({
|
|
157
|
+
board,
|
|
158
|
+
spaces,
|
|
159
|
+
interactions = "auto",
|
|
160
|
+
...props
|
|
161
|
+
}: BoardHexGridProps<TBoard, TSpaceView>) {
|
|
162
|
+
const boardInteractions = useBoardPrimitiveContext();
|
|
163
|
+
const gameActionError = useGameActionError();
|
|
164
|
+
const edgeLayer =
|
|
165
|
+
interactions === false
|
|
166
|
+
? undefined
|
|
167
|
+
: boardInteractions.targetLayers.edge({
|
|
168
|
+
enabled: boardInteractions.eligible.edge.size > 0,
|
|
169
|
+
interactionKeys:
|
|
170
|
+
interactions === "auto" ? undefined : interactions.edge,
|
|
171
|
+
onError: gameActionError ?? undefined,
|
|
172
|
+
});
|
|
173
|
+
const vertexLayer =
|
|
174
|
+
interactions === false
|
|
175
|
+
? undefined
|
|
176
|
+
: boardInteractions.targetLayers.vertex({
|
|
177
|
+
enabled: boardInteractions.eligible.vertex.size > 0,
|
|
178
|
+
interactionKeys:
|
|
179
|
+
interactions === "auto" ? undefined : interactions.vertex,
|
|
180
|
+
onError: gameActionError ?? undefined,
|
|
181
|
+
});
|
|
182
|
+
const spaceLayer =
|
|
183
|
+
interactions === false
|
|
184
|
+
? undefined
|
|
185
|
+
: boardInteractions.targetLayers.space({
|
|
186
|
+
enabled: boardInteractions.eligible.space.size > 0,
|
|
187
|
+
interactionKeys:
|
|
188
|
+
interactions === "auto" ? undefined : interactions.space,
|
|
189
|
+
onError: gameActionError ?? undefined,
|
|
190
|
+
});
|
|
191
|
+
return (
|
|
192
|
+
<BoardHexView board={board} spaces={spaces}>
|
|
193
|
+
{(view) => (
|
|
194
|
+
<HexGrid
|
|
195
|
+
{...props}
|
|
196
|
+
board={view as BoardHexGridView<TBoard, TSpaceView>}
|
|
197
|
+
interactiveEdges={edgeLayer}
|
|
198
|
+
interactiveVertices={vertexLayer}
|
|
199
|
+
interactiveSpaces={spaceLayer}
|
|
200
|
+
/>
|
|
201
|
+
)}
|
|
202
|
+
</BoardHexView>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export type BoardTargetExtraInputs =
|
|
207
|
+
| Record<string, unknown>
|
|
208
|
+
| ((targetId: string) => Record<string, unknown>);
|
|
209
|
+
|
|
210
|
+
export type BoardTargetProps<Target extends string = BoardTargetKey> =
|
|
211
|
+
PrimitiveCommonProps &
|
|
212
|
+
ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
213
|
+
kind: BoardTargetKind;
|
|
214
|
+
value: Target;
|
|
215
|
+
interaction?: string;
|
|
216
|
+
input?: string;
|
|
217
|
+
extraInputs?: BoardTargetExtraInputs;
|
|
218
|
+
onSelect?: (result: BoardSelectionResult) => void;
|
|
219
|
+
onSelectError?: (error: unknown) => void;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export function BoardTarget<Target extends string = BoardTargetKey>({
|
|
223
|
+
interaction,
|
|
224
|
+
input,
|
|
225
|
+
...props
|
|
226
|
+
}: BoardTargetProps<Target>) {
|
|
227
|
+
const descriptor = usePluginState((state) =>
|
|
228
|
+
interaction
|
|
229
|
+
? state.gameplay.availableInteractions.find(
|
|
230
|
+
(candidate) =>
|
|
231
|
+
candidate.interactionKey === interaction ||
|
|
232
|
+
candidate.interactionId === interaction,
|
|
233
|
+
)
|
|
234
|
+
: undefined,
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
if (interaction) {
|
|
238
|
+
return descriptor ? (
|
|
239
|
+
<ExplicitBoardTarget descriptor={descriptor} input={input} {...props} />
|
|
240
|
+
) : (
|
|
241
|
+
<UnavailableBoardTarget
|
|
242
|
+
interaction={interaction}
|
|
243
|
+
input={input}
|
|
244
|
+
{...props}
|
|
245
|
+
/>
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return <UnambiguousBoardTarget input={input} {...props} />;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export type BoardSpaceTargetProps<Target extends string = BoardTargetKey> =
|
|
253
|
+
Omit<BoardTargetProps<Target>, "kind">;
|
|
254
|
+
|
|
255
|
+
export function BoardSpaceTarget<Target extends string = BoardTargetKey>(
|
|
256
|
+
props: BoardSpaceTargetProps<Target>,
|
|
257
|
+
) {
|
|
258
|
+
return <BoardTarget kind="space" {...props} />;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export type BoardEdgeTargetProps<Target extends string = BoardTargetKey> = Omit<
|
|
262
|
+
BoardTargetProps<Target>,
|
|
263
|
+
"kind"
|
|
264
|
+
>;
|
|
265
|
+
|
|
266
|
+
export function BoardEdgeTarget<Target extends string = BoardTargetKey>(
|
|
267
|
+
props: BoardEdgeTargetProps<Target>,
|
|
268
|
+
) {
|
|
269
|
+
return <BoardTarget kind="edge" {...props} />;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export type BoardVertexTargetProps<Target extends string = BoardTargetKey> =
|
|
273
|
+
Omit<BoardTargetProps<Target>, "kind">;
|
|
274
|
+
|
|
275
|
+
export function BoardVertexTarget<Target extends string = BoardTargetKey>(
|
|
276
|
+
props: BoardVertexTargetProps<Target>,
|
|
277
|
+
) {
|
|
278
|
+
return <BoardTarget kind="vertex" {...props} />;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function UnambiguousBoardTarget({
|
|
282
|
+
kind,
|
|
283
|
+
value,
|
|
284
|
+
extraInputs,
|
|
285
|
+
onSelect,
|
|
286
|
+
onSelectError,
|
|
287
|
+
disabled,
|
|
288
|
+
onClick,
|
|
289
|
+
children,
|
|
290
|
+
...props
|
|
291
|
+
}: Omit<BoardTargetProps, "interaction">) {
|
|
292
|
+
const board = useBoardPrimitiveContext();
|
|
293
|
+
const gameActionError = useGameActionError();
|
|
294
|
+
const targetState = board.targetState(kind, value);
|
|
295
|
+
const eligible = board.isEligible(value, kind);
|
|
296
|
+
const ambiguous = targetState.conflict;
|
|
297
|
+
const conflictInteractionKeys = targetState.conflictInteractionKeys ?? [];
|
|
298
|
+
if (ambiguous) {
|
|
299
|
+
warnAmbiguousBoardTarget({
|
|
300
|
+
kind,
|
|
301
|
+
value,
|
|
302
|
+
interactionKeys: conflictInteractionKeys,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
const isDisabled = disabled ?? (!targetState.eligible || ambiguous);
|
|
306
|
+
const ambiguityMessage =
|
|
307
|
+
ambiguous && conflictInteractionKeys.length > 0
|
|
308
|
+
? `Ambiguous ${kind} target "${value}" matched: ${conflictInteractionKeys.join(
|
|
309
|
+
", ",
|
|
310
|
+
)}`
|
|
311
|
+
: undefined;
|
|
312
|
+
return renderPrimitive("button", {
|
|
313
|
+
type: "button",
|
|
314
|
+
...props,
|
|
315
|
+
children,
|
|
316
|
+
disabled: isDisabled,
|
|
317
|
+
"aria-disabled": isDisabled,
|
|
318
|
+
"data-dreamboard-board-target": "",
|
|
319
|
+
"data-target-kind": kind,
|
|
320
|
+
"data-target-id": value,
|
|
321
|
+
"data-eligible": eligible,
|
|
322
|
+
"data-ambiguous": ambiguous || undefined,
|
|
323
|
+
"data-conflict-interactions":
|
|
324
|
+
ambiguous && conflictInteractionKeys.length > 0
|
|
325
|
+
? conflictInteractionKeys.join(" ")
|
|
326
|
+
: undefined,
|
|
327
|
+
"data-disabled": isDisabled || undefined,
|
|
328
|
+
title: props.title ?? ambiguityMessage,
|
|
329
|
+
onClick: composeEventHandlers(onClick, () => {
|
|
330
|
+
if (isDisabled) return;
|
|
331
|
+
void runInteractionAction(
|
|
332
|
+
() => board.select[kind](value, resolveExtraInputs(extraInputs, value)),
|
|
333
|
+
{
|
|
334
|
+
onSuccess: onSelect,
|
|
335
|
+
onError: onSelectError ?? gameActionError ?? undefined,
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
}),
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function ExplicitBoardTarget({
|
|
343
|
+
descriptor,
|
|
344
|
+
kind,
|
|
345
|
+
value,
|
|
346
|
+
input,
|
|
347
|
+
extraInputs,
|
|
348
|
+
onSelect,
|
|
349
|
+
onSelectError,
|
|
350
|
+
disabled,
|
|
351
|
+
onClick,
|
|
352
|
+
children,
|
|
353
|
+
...props
|
|
354
|
+
}: Omit<BoardTargetProps, "interaction"> & {
|
|
355
|
+
descriptor: InteractionDescriptor;
|
|
356
|
+
}) {
|
|
357
|
+
const board = useBoardPrimitiveContext();
|
|
358
|
+
const gameActionError = useGameActionError();
|
|
359
|
+
const store = useInteractionUiStore();
|
|
360
|
+
useStore(store, (state) => state.drafts[descriptor.interactionKey] ?? {});
|
|
361
|
+
const draft = store.getDraft(descriptor.interactionKey);
|
|
362
|
+
const inputKey = input ?? inputKeyForTarget(descriptor, kind, value, draft);
|
|
363
|
+
const rawInputDescriptor = inputKey
|
|
364
|
+
? inputByKey(descriptor, inputKey)
|
|
365
|
+
: undefined;
|
|
366
|
+
const inputDescriptor = rawInputDescriptor
|
|
367
|
+
? resolveInputDomain(rawInputDescriptor, draft)
|
|
368
|
+
: undefined;
|
|
369
|
+
const eligibleTargets = inputKey
|
|
370
|
+
? eligibleTargetsForInput(descriptor, inputKey, draft)
|
|
371
|
+
: undefined;
|
|
372
|
+
const eligible =
|
|
373
|
+
inputDescriptor !== undefined &&
|
|
374
|
+
inputDescriptor.domain.type === "boardTarget" &&
|
|
375
|
+
isResolvedTargetDomain(inputDescriptor.domain) &&
|
|
376
|
+
inputDescriptor.domain.targetKind === kind &&
|
|
377
|
+
(eligibleTargets ?? inputDescriptor.domain.eligibleTargets).includes(value);
|
|
378
|
+
const isDisabled =
|
|
379
|
+
disabled ?? (!isInteractionAvailable(descriptor) || !eligible);
|
|
380
|
+
return renderPrimitive("button", {
|
|
381
|
+
type: "button",
|
|
382
|
+
...props,
|
|
383
|
+
children,
|
|
384
|
+
disabled: isDisabled,
|
|
385
|
+
"aria-disabled": isDisabled,
|
|
386
|
+
"data-dreamboard-board-target": "",
|
|
387
|
+
"data-target-kind": kind,
|
|
388
|
+
"data-target-id": value,
|
|
389
|
+
"data-interaction-id": descriptor.interactionId,
|
|
390
|
+
"data-interaction-key": descriptor.interactionKey,
|
|
391
|
+
"data-input-name": inputKey ?? undefined,
|
|
392
|
+
"data-eligible": eligible,
|
|
393
|
+
"data-disabled": isDisabled || undefined,
|
|
394
|
+
onClick: composeEventHandlers(onClick, () => {
|
|
395
|
+
if (isDisabled || !inputKey) return;
|
|
396
|
+
const resolvedExtraInputs = resolveExtraInputs(extraInputs, value);
|
|
397
|
+
void runInteractionAction(
|
|
398
|
+
() =>
|
|
399
|
+
board.selectTarget(
|
|
400
|
+
descriptor,
|
|
401
|
+
kind,
|
|
402
|
+
value,
|
|
403
|
+
inputKey,
|
|
404
|
+
resolvedExtraInputs,
|
|
405
|
+
),
|
|
406
|
+
{
|
|
407
|
+
onSuccess: onSelect,
|
|
408
|
+
onError: onSelectError ?? gameActionError ?? undefined,
|
|
409
|
+
},
|
|
410
|
+
);
|
|
411
|
+
}),
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function UnavailableBoardTarget({
|
|
416
|
+
kind,
|
|
417
|
+
value,
|
|
418
|
+
interaction,
|
|
419
|
+
input,
|
|
420
|
+
disabled,
|
|
421
|
+
children,
|
|
422
|
+
...props
|
|
423
|
+
}: Omit<BoardTargetProps, "onSelect" | "onSelectError" | "extraInputs">) {
|
|
424
|
+
const isDisabled = disabled ?? true;
|
|
425
|
+
return renderPrimitive("button", {
|
|
426
|
+
type: "button",
|
|
427
|
+
...props,
|
|
428
|
+
children,
|
|
429
|
+
disabled: isDisabled,
|
|
430
|
+
"aria-disabled": isDisabled,
|
|
431
|
+
"data-dreamboard-board-target": "",
|
|
432
|
+
"data-target-kind": kind,
|
|
433
|
+
"data-target-id": value,
|
|
434
|
+
"data-interaction-key": interaction,
|
|
435
|
+
"data-input-name": input,
|
|
436
|
+
"data-eligible": false,
|
|
437
|
+
"data-disabled": isDisabled || undefined,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function resolveExtraInputs(
|
|
442
|
+
extraInputs: BoardTargetExtraInputs | undefined,
|
|
443
|
+
targetId: string,
|
|
444
|
+
): Record<string, unknown> {
|
|
445
|
+
return typeof extraInputs === "function"
|
|
446
|
+
? extraInputs(targetId)
|
|
447
|
+
: (extraInputs ?? {});
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export const Board = {
|
|
451
|
+
Root: BoardRoot,
|
|
452
|
+
State: BoardState,
|
|
453
|
+
HexGrid: BoardHexGrid,
|
|
454
|
+
HexView: BoardHexView,
|
|
455
|
+
Target: BoardTarget,
|
|
456
|
+
SpaceTarget: BoardSpaceTarget,
|
|
457
|
+
EdgeTarget: BoardEdgeTarget,
|
|
458
|
+
VertexTarget: BoardVertexTarget,
|
|
459
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
|
|
3
|
+
export type DialogLifecycleState = "open" | "minimized" | "dismissed";
|
|
4
|
+
|
|
5
|
+
export interface DialogLifecycleValue {
|
|
6
|
+
state: DialogLifecycleState;
|
|
7
|
+
open: boolean;
|
|
8
|
+
minimized: boolean;
|
|
9
|
+
dismissed: boolean;
|
|
10
|
+
setOpen: (open: boolean) => void;
|
|
11
|
+
restore: () => void;
|
|
12
|
+
minimize: () => void;
|
|
13
|
+
dismiss: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DialogLifecycleOptions {
|
|
17
|
+
defaultOpen?: boolean;
|
|
18
|
+
onStateChange?: (state: DialogLifecycleState) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function useDialogLifecycle({
|
|
22
|
+
defaultOpen = true,
|
|
23
|
+
onStateChange,
|
|
24
|
+
}: DialogLifecycleOptions): DialogLifecycleValue {
|
|
25
|
+
const [state, setState] = useState<DialogLifecycleState>(
|
|
26
|
+
defaultOpen ? "open" : "minimized",
|
|
27
|
+
);
|
|
28
|
+
const updateState = useCallback(
|
|
29
|
+
(nextState: DialogLifecycleState) => {
|
|
30
|
+
setState(nextState);
|
|
31
|
+
onStateChange?.(nextState);
|
|
32
|
+
},
|
|
33
|
+
[onStateChange],
|
|
34
|
+
);
|
|
35
|
+
const restore = useCallback(() => updateState("open"), [updateState]);
|
|
36
|
+
const minimize = useCallback(() => updateState("minimized"), [updateState]);
|
|
37
|
+
const dismiss = useCallback(() => updateState("dismissed"), [updateState]);
|
|
38
|
+
const setOpen = useCallback(
|
|
39
|
+
(open: boolean) => {
|
|
40
|
+
updateState(open ? "open" : "minimized");
|
|
41
|
+
},
|
|
42
|
+
[updateState],
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return useMemo<DialogLifecycleValue>(
|
|
46
|
+
() => ({
|
|
47
|
+
state,
|
|
48
|
+
open: state === "open",
|
|
49
|
+
minimized: state === "minimized",
|
|
50
|
+
dismissed: state === "dismissed",
|
|
51
|
+
setOpen,
|
|
52
|
+
restore,
|
|
53
|
+
minimize,
|
|
54
|
+
dismiss,
|
|
55
|
+
}),
|
|
56
|
+
[dismiss, minimize, restore, setOpen, state],
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createContext, useContext, type ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export type DiceValue = number | null | undefined;
|
|
4
|
+
|
|
5
|
+
export interface DiceState {
|
|
6
|
+
values: ReadonlyArray<number | undefined> | undefined;
|
|
7
|
+
/** Undefined if any die has not been rolled yet. */
|
|
8
|
+
sum: number | undefined;
|
|
9
|
+
diceCount: number;
|
|
10
|
+
allRolled: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DiceRootProps {
|
|
14
|
+
values?: readonly DiceValue[] | null;
|
|
15
|
+
/** Used when values are not provided. */
|
|
16
|
+
count?: number;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface DiceValuesProps {
|
|
21
|
+
children: (state: DiceState) => ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface DiceComponents {
|
|
25
|
+
Root(props: DiceRootProps): ReactNode;
|
|
26
|
+
Values(props: DiceValuesProps): ReactNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DiceContext = createContext<DiceState | null>(null);
|
|
30
|
+
|
|
31
|
+
export function normalizeDiceState({
|
|
32
|
+
values,
|
|
33
|
+
count = 2,
|
|
34
|
+
}: {
|
|
35
|
+
values?: readonly DiceValue[] | null;
|
|
36
|
+
count?: number;
|
|
37
|
+
}): DiceState {
|
|
38
|
+
const normalizedValues = values?.map((value) => value ?? undefined);
|
|
39
|
+
const allRolled =
|
|
40
|
+
normalizedValues?.every((value) => value !== undefined) ?? false;
|
|
41
|
+
const sum = allRolled
|
|
42
|
+
? normalizedValues?.reduce<number>(
|
|
43
|
+
(total, value) => total + (value ?? 0),
|
|
44
|
+
0,
|
|
45
|
+
)
|
|
46
|
+
: undefined;
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
values: normalizedValues,
|
|
50
|
+
sum,
|
|
51
|
+
diceCount: normalizedValues?.length ?? count,
|
|
52
|
+
allRolled,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function DiceRoot({ values, count, children }: DiceRootProps) {
|
|
57
|
+
return (
|
|
58
|
+
<DiceContext.Provider value={normalizeDiceState({ values, count })}>
|
|
59
|
+
{children}
|
|
60
|
+
</DiceContext.Provider>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function useDicePrimitiveContext(): DiceState {
|
|
65
|
+
const value = useContext(DiceContext);
|
|
66
|
+
if (!value) {
|
|
67
|
+
throw new Error("Dice primitives must be rendered inside <Dice.Root>.");
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function DiceValues({ children }: DiceValuesProps) {
|
|
73
|
+
return children(useDicePrimitiveContext());
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const Dice: DiceComponents = {
|
|
77
|
+
Root: DiceRoot,
|
|
78
|
+
Values: DiceValues,
|
|
79
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
PluginStateProvider,
|
|
4
|
+
type PluginStateProviderProps,
|
|
5
|
+
} from "../context/PluginStateContext.js";
|
|
6
|
+
import { RuntimeProvider } from "../context/RuntimeContext.js";
|
|
7
|
+
import {
|
|
8
|
+
InteractionUiProvider,
|
|
9
|
+
type InteractionUiStoreApi,
|
|
10
|
+
} from "../context/InteractionDraftContext.js";
|
|
11
|
+
import type { RuntimeAPI } from "../types/runtime-api.js";
|
|
12
|
+
|
|
13
|
+
export interface GameUIProviderProps {
|
|
14
|
+
runtime: RuntimeAPI;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
loadingComponent?: PluginStateProviderProps["loadingComponent"];
|
|
17
|
+
interactionStore?: InteractionUiStoreApi;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function GameUIProvider({
|
|
21
|
+
runtime,
|
|
22
|
+
children,
|
|
23
|
+
loadingComponent,
|
|
24
|
+
interactionStore,
|
|
25
|
+
}: GameUIProviderProps) {
|
|
26
|
+
return (
|
|
27
|
+
<RuntimeProvider runtime={runtime}>
|
|
28
|
+
<PluginStateProvider loadingComponent={loadingComponent}>
|
|
29
|
+
<InteractionUiProvider store={interactionStore}>
|
|
30
|
+
{children}
|
|
31
|
+
</InteractionUiProvider>
|
|
32
|
+
</PluginStateProvider>
|
|
33
|
+
</RuntimeProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|