@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,809 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { SchemaLike } from "../model/table";
|
|
3
|
+
import type { ManifestIdSchema } from "../model/manifest";
|
|
4
|
+
import type {
|
|
5
|
+
BoundedNumberDomainDescriptor,
|
|
6
|
+
ChoiceDomainDescriptor,
|
|
7
|
+
ChoiceListDomainDescriptor,
|
|
8
|
+
CollectorState,
|
|
9
|
+
InputCollector,
|
|
10
|
+
ResourceMapDomainDescriptor,
|
|
11
|
+
} from "../model/spec";
|
|
12
|
+
import type { PlayerIdOfState } from "../model/extract";
|
|
13
|
+
import type { TableQueriesOfState } from "../model/queries";
|
|
14
|
+
import type { DerivedResolver } from "../derived";
|
|
15
|
+
import { isPerPlayer } from "../per-player";
|
|
16
|
+
import type { DependencyValues, InputFieldRef } from "./defineInputs";
|
|
17
|
+
|
|
18
|
+
type DomainContext<
|
|
19
|
+
State extends CollectorState,
|
|
20
|
+
Values extends Readonly<Record<string, unknown>> = Record<string, never>,
|
|
21
|
+
> = {
|
|
22
|
+
state: State;
|
|
23
|
+
playerId: PlayerIdOfState<State>;
|
|
24
|
+
q: TableQueriesOfState<State>;
|
|
25
|
+
derived: DerivedResolver;
|
|
26
|
+
values: Values;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type ManifestFormInputSchema =
|
|
30
|
+
| ManifestIdSchema<unknown>
|
|
31
|
+
| z.ZodOptional<ManifestIdSchema<unknown>>
|
|
32
|
+
| z.ZodNullable<ManifestIdSchema<unknown>>;
|
|
33
|
+
|
|
34
|
+
type DomainNumber<State extends CollectorState> =
|
|
35
|
+
| number
|
|
36
|
+
| ((context: DomainContext<State>) => number);
|
|
37
|
+
|
|
38
|
+
type ChoiceValue = string | null;
|
|
39
|
+
|
|
40
|
+
type FormInputDomainDescriptor =
|
|
41
|
+
| ResourceMapDomainDescriptor
|
|
42
|
+
| BoundedNumberDomainDescriptor
|
|
43
|
+
| ChoiceDomainDescriptor
|
|
44
|
+
| ChoiceListDomainDescriptor;
|
|
45
|
+
|
|
46
|
+
type DomainChoice<Value extends ChoiceValue, State extends CollectorState> = {
|
|
47
|
+
value: Value;
|
|
48
|
+
label: string;
|
|
49
|
+
icon?: string;
|
|
50
|
+
badge?: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
disabledReason?: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type DomainChoicePresentation = {
|
|
57
|
+
badge?: string;
|
|
58
|
+
description?: string;
|
|
59
|
+
disabled?: boolean;
|
|
60
|
+
disabledReason?: string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
type ResourceMapChoiceDecorator<State extends CollectorState> = (
|
|
64
|
+
context: DomainContext<State> & {
|
|
65
|
+
resourceId: string;
|
|
66
|
+
label: string;
|
|
67
|
+
icon?: string;
|
|
68
|
+
},
|
|
69
|
+
) => DomainChoicePresentation | null | undefined;
|
|
70
|
+
|
|
71
|
+
type ResourceMapChoiceSource<State extends CollectorState> =
|
|
72
|
+
| "resourceMap"
|
|
73
|
+
| {
|
|
74
|
+
source: "resourceMap";
|
|
75
|
+
decorate?: ResourceMapChoiceDecorator<State>;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
type DomainChoices<Value extends ChoiceValue, State extends CollectorState> =
|
|
79
|
+
| ReadonlyArray<DomainChoice<Value, State>>
|
|
80
|
+
| ResourceMapChoiceSource<State>
|
|
81
|
+
| ((
|
|
82
|
+
context: DomainContext<State>,
|
|
83
|
+
) => ReadonlyArray<DomainChoice<Value, State>>);
|
|
84
|
+
|
|
85
|
+
type DependentDomainChoices<
|
|
86
|
+
Value extends ChoiceValue,
|
|
87
|
+
State extends CollectorState,
|
|
88
|
+
Dependencies extends readonly InputFieldRef<string, unknown>[],
|
|
89
|
+
> =
|
|
90
|
+
| ReadonlyArray<DomainChoice<Value, State>>
|
|
91
|
+
| ((
|
|
92
|
+
context: DomainContext<State, DependencyValues<Dependencies>>,
|
|
93
|
+
) => ReadonlyArray<DomainChoice<Value, State>>);
|
|
94
|
+
|
|
95
|
+
type ChoiceListDefaultValue<
|
|
96
|
+
Value extends string,
|
|
97
|
+
State extends CollectorState,
|
|
98
|
+
> =
|
|
99
|
+
| Value[]
|
|
100
|
+
| "all"
|
|
101
|
+
| ((
|
|
102
|
+
context: DomainContext<State> & {
|
|
103
|
+
choices: ReadonlyArray<DomainChoice<Value, State>>;
|
|
104
|
+
},
|
|
105
|
+
) => Value[]);
|
|
106
|
+
|
|
107
|
+
type ChoiceDefaultValue<
|
|
108
|
+
Value extends ChoiceValue,
|
|
109
|
+
State extends CollectorState,
|
|
110
|
+
Values extends Readonly<Record<string, unknown>> = Record<string, never>,
|
|
111
|
+
> =
|
|
112
|
+
| Value
|
|
113
|
+
| ((
|
|
114
|
+
context: DomainContext<State, Values> & {
|
|
115
|
+
choices: ReadonlyArray<DomainChoice<Value, State>>;
|
|
116
|
+
},
|
|
117
|
+
) => Value);
|
|
118
|
+
|
|
119
|
+
type ChoiceDefaultResolver<
|
|
120
|
+
Value extends ChoiceValue,
|
|
121
|
+
State extends CollectorState,
|
|
122
|
+
Values extends Readonly<Record<string, unknown>> = Record<string, never>,
|
|
123
|
+
> = (
|
|
124
|
+
context: DomainContext<State, Values> & {
|
|
125
|
+
choices: ReadonlyArray<DomainChoice<Value, State>>;
|
|
126
|
+
},
|
|
127
|
+
) => Value | undefined;
|
|
128
|
+
|
|
129
|
+
function isResourceMapChoiceSource<State extends CollectorState>(
|
|
130
|
+
choices: DomainChoices<ChoiceValue, State>,
|
|
131
|
+
): choices is ResourceMapChoiceSource<State> {
|
|
132
|
+
return (
|
|
133
|
+
choices === "resourceMap" ||
|
|
134
|
+
(typeof choices === "object" &&
|
|
135
|
+
choices !== null &&
|
|
136
|
+
!Array.isArray(choices) &&
|
|
137
|
+
"source" in choices &&
|
|
138
|
+
choices.source === "resourceMap")
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function resolveDomainNumber<State extends CollectorState>(
|
|
143
|
+
value: DomainNumber<State> | undefined,
|
|
144
|
+
context: DomainContext<State>,
|
|
145
|
+
fallback: number,
|
|
146
|
+
): number {
|
|
147
|
+
if (typeof value === "function") return value(context);
|
|
148
|
+
return value ?? fallback;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function resolveDomainChoices<
|
|
152
|
+
Value extends ChoiceValue,
|
|
153
|
+
State extends CollectorState,
|
|
154
|
+
>(
|
|
155
|
+
choices: DomainChoices<Value, State>,
|
|
156
|
+
context: DomainContext<State>,
|
|
157
|
+
): Array<{
|
|
158
|
+
value: ChoiceValue;
|
|
159
|
+
label: string;
|
|
160
|
+
icon?: string;
|
|
161
|
+
badge?: string;
|
|
162
|
+
description?: string;
|
|
163
|
+
disabled?: boolean;
|
|
164
|
+
disabledReason?: string;
|
|
165
|
+
}> {
|
|
166
|
+
if (isResourceMapChoiceSource(choices)) {
|
|
167
|
+
return resolveResourceMapChoices(choices, context);
|
|
168
|
+
}
|
|
169
|
+
const resolved = typeof choices === "function" ? choices(context) : choices;
|
|
170
|
+
return resolved.map((choice) => ({
|
|
171
|
+
value: choice.value,
|
|
172
|
+
label: choice.label,
|
|
173
|
+
icon: choice.icon,
|
|
174
|
+
badge: choice.badge,
|
|
175
|
+
description: choice.description,
|
|
176
|
+
disabled: choice.disabled,
|
|
177
|
+
disabledReason: choice.disabledReason,
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function resolveDependentDomainChoices<
|
|
182
|
+
Value extends ChoiceValue,
|
|
183
|
+
State extends CollectorState,
|
|
184
|
+
Dependencies extends readonly InputFieldRef<string, unknown>[],
|
|
185
|
+
>(
|
|
186
|
+
choices: DependentDomainChoices<Value, State, Dependencies>,
|
|
187
|
+
context: DomainContext<State, DependencyValues<Dependencies>>,
|
|
188
|
+
): Array<{
|
|
189
|
+
value: ChoiceValue;
|
|
190
|
+
label: string;
|
|
191
|
+
icon?: string;
|
|
192
|
+
badge?: string;
|
|
193
|
+
description?: string;
|
|
194
|
+
disabled?: boolean;
|
|
195
|
+
disabledReason?: string;
|
|
196
|
+
}> {
|
|
197
|
+
const resolved = typeof choices === "function" ? choices(context) : choices;
|
|
198
|
+
return resolved.map((choice) => ({
|
|
199
|
+
value: choice.value,
|
|
200
|
+
label: choice.label,
|
|
201
|
+
icon: choice.icon,
|
|
202
|
+
badge: choice.badge,
|
|
203
|
+
description: choice.description,
|
|
204
|
+
disabled: choice.disabled,
|
|
205
|
+
disabledReason: choice.disabledReason,
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function choiceValuesInclude(
|
|
210
|
+
choices: ReadonlyArray<{ value: ChoiceValue }>,
|
|
211
|
+
value: ChoiceValue,
|
|
212
|
+
): boolean {
|
|
213
|
+
return choices.some((choice) => Object.is(choice.value, value));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function assertChoiceDefaultInChoices(
|
|
217
|
+
inputName: string,
|
|
218
|
+
choices: ReadonlyArray<{ value: ChoiceValue }>,
|
|
219
|
+
defaultValue: ChoiceValue,
|
|
220
|
+
): void {
|
|
221
|
+
if (choiceValuesInclude(choices, defaultValue)) return;
|
|
222
|
+
const printable = defaultValue === null ? "null" : `'${defaultValue}'`;
|
|
223
|
+
throw new Error(
|
|
224
|
+
`${inputName} defaultValue ${printable} must be one of its choices. ` +
|
|
225
|
+
"If null is a valid value, add an explicit { value: null, label: ... } choice.",
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function choiceSchema<Value extends ChoiceValue, State extends CollectorState>(
|
|
230
|
+
choices: ReadonlyArray<DomainChoice<Value, State>>,
|
|
231
|
+
): SchemaLike<Value> {
|
|
232
|
+
const values = choices.map((choice) => choice.value);
|
|
233
|
+
const stringValues = values.filter(
|
|
234
|
+
(value): value is Exclude<Value, null> => value !== null,
|
|
235
|
+
);
|
|
236
|
+
const hasNull = values.some((value) => value === null);
|
|
237
|
+
|
|
238
|
+
if (stringValues.length === 0) {
|
|
239
|
+
return z.null() as unknown as SchemaLike<Value>;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const stringSchema = z.enum(
|
|
243
|
+
stringValues as [Exclude<Value, null>, ...Array<Exclude<Value, null>>],
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
if (hasNull) {
|
|
247
|
+
return z.union([stringSchema, z.null()]) as unknown as SchemaLike<Value>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return stringSchema as unknown as SchemaLike<Value>;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function resolveResourceMapChoices<State extends CollectorState>(
|
|
254
|
+
choices: ResourceMapChoiceSource<State>,
|
|
255
|
+
context: DomainContext<State>,
|
|
256
|
+
): Array<{
|
|
257
|
+
value: string;
|
|
258
|
+
label: string;
|
|
259
|
+
badge?: string;
|
|
260
|
+
description?: string;
|
|
261
|
+
disabled?: boolean;
|
|
262
|
+
disabledReason?: string;
|
|
263
|
+
}> {
|
|
264
|
+
const resources = context.state.table.resources as unknown;
|
|
265
|
+
const firstResourceMap =
|
|
266
|
+
isPerPlayer(resources) && resources.entries.length > 0
|
|
267
|
+
? resources.entries[0]?.[1]
|
|
268
|
+
: resources;
|
|
269
|
+
if (
|
|
270
|
+
typeof firstResourceMap !== "object" ||
|
|
271
|
+
firstResourceMap === null ||
|
|
272
|
+
Array.isArray(firstResourceMap)
|
|
273
|
+
) {
|
|
274
|
+
return [];
|
|
275
|
+
}
|
|
276
|
+
const decorate = choices === "resourceMap" ? undefined : choices.decorate;
|
|
277
|
+
return Object.keys(firstResourceMap)
|
|
278
|
+
.sort()
|
|
279
|
+
.map((resourceId) => {
|
|
280
|
+
const label = resourceId;
|
|
281
|
+
const presentation = decorate?.({ ...context, resourceId, label });
|
|
282
|
+
return {
|
|
283
|
+
value: resourceId,
|
|
284
|
+
label,
|
|
285
|
+
badge: presentation?.badge,
|
|
286
|
+
description: presentation?.description,
|
|
287
|
+
disabled: presentation?.disabled,
|
|
288
|
+
disabledReason: presentation?.disabledReason,
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function createFormInput<
|
|
294
|
+
Schema extends SchemaLike<unknown>,
|
|
295
|
+
State extends CollectorState = CollectorState,
|
|
296
|
+
>(
|
|
297
|
+
schema: Schema,
|
|
298
|
+
options?: { defaultValue?: z.infer<Schema> },
|
|
299
|
+
): InputCollector<Schema, State, "form"> {
|
|
300
|
+
return {
|
|
301
|
+
kind: "form",
|
|
302
|
+
schema,
|
|
303
|
+
...(options && "defaultValue" in options
|
|
304
|
+
? { defaultValue: options.defaultValue }
|
|
305
|
+
: {}),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function baseFormInput<
|
|
310
|
+
Schema extends ManifestFormInputSchema & SchemaLike<unknown>,
|
|
311
|
+
State extends CollectorState = CollectorState,
|
|
312
|
+
>(schema: Schema): InputCollector<Schema, State, "form">;
|
|
313
|
+
function baseFormInput<
|
|
314
|
+
Schema extends ManifestFormInputSchema & SchemaLike<unknown>,
|
|
315
|
+
State extends CollectorState = CollectorState,
|
|
316
|
+
>(
|
|
317
|
+
schema: Schema,
|
|
318
|
+
options: { defaultValue: z.infer<Schema> },
|
|
319
|
+
): InputCollector<Schema, State, "form"> & {
|
|
320
|
+
readonly defaultValue: z.infer<Schema>;
|
|
321
|
+
};
|
|
322
|
+
function baseFormInput<
|
|
323
|
+
Schema extends ManifestFormInputSchema & SchemaLike<unknown>,
|
|
324
|
+
State extends CollectorState = CollectorState,
|
|
325
|
+
>(
|
|
326
|
+
schema: Schema,
|
|
327
|
+
options?: { defaultValue?: z.infer<Schema> },
|
|
328
|
+
): InputCollector<Schema, State, "form"> {
|
|
329
|
+
return createFormInput(schema, options);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function resourceMapInput<
|
|
333
|
+
State extends CollectorState = CollectorState,
|
|
334
|
+
>(options: {
|
|
335
|
+
resources: ReadonlyArray<{
|
|
336
|
+
resourceId: string;
|
|
337
|
+
label?: string;
|
|
338
|
+
icon?: string;
|
|
339
|
+
min?: DomainNumber<State>;
|
|
340
|
+
max: DomainNumber<State>;
|
|
341
|
+
}>;
|
|
342
|
+
}): InputCollector<z.ZodRecord<z.ZodString, z.ZodNumber>, State, "form">;
|
|
343
|
+
function resourceMapInput<
|
|
344
|
+
State extends CollectorState = CollectorState,
|
|
345
|
+
>(options: {
|
|
346
|
+
resources: ReadonlyArray<{
|
|
347
|
+
resourceId: string;
|
|
348
|
+
label?: string;
|
|
349
|
+
icon?: string;
|
|
350
|
+
min?: DomainNumber<State>;
|
|
351
|
+
max: DomainNumber<State>;
|
|
352
|
+
}>;
|
|
353
|
+
defaultValue: Record<string, number>;
|
|
354
|
+
}): InputCollector<z.ZodRecord<z.ZodString, z.ZodNumber>, State, "form"> & {
|
|
355
|
+
readonly defaultValue: Record<string, number>;
|
|
356
|
+
};
|
|
357
|
+
function resourceMapInput<
|
|
358
|
+
State extends CollectorState = CollectorState,
|
|
359
|
+
>(options: {
|
|
360
|
+
resources: ReadonlyArray<{
|
|
361
|
+
resourceId: string;
|
|
362
|
+
label?: string;
|
|
363
|
+
icon?: string;
|
|
364
|
+
min?: DomainNumber<State>;
|
|
365
|
+
max: DomainNumber<State>;
|
|
366
|
+
}>;
|
|
367
|
+
defaultValue?: Record<string, number>;
|
|
368
|
+
}): InputCollector<z.ZodRecord<z.ZodString, z.ZodNumber>, State, "form"> {
|
|
369
|
+
return {
|
|
370
|
+
kind: "form",
|
|
371
|
+
schema: z.record(z.string(), z.number().int().nonnegative()),
|
|
372
|
+
...("defaultValue" in options
|
|
373
|
+
? { defaultValue: options.defaultValue }
|
|
374
|
+
: {}),
|
|
375
|
+
domain: (state, playerId, q, derived): FormInputDomainDescriptor => {
|
|
376
|
+
const context = {
|
|
377
|
+
state: state as State,
|
|
378
|
+
playerId: playerId as PlayerIdOfState<State>,
|
|
379
|
+
q: q as TableQueriesOfState<State>,
|
|
380
|
+
derived,
|
|
381
|
+
values: {},
|
|
382
|
+
};
|
|
383
|
+
return {
|
|
384
|
+
type: "resourceMap",
|
|
385
|
+
resources: options.resources.map((resource) => ({
|
|
386
|
+
resourceId: resource.resourceId,
|
|
387
|
+
label: resource.label,
|
|
388
|
+
icon: resource.icon,
|
|
389
|
+
min: resolveDomainNumber(resource.min, context, 0),
|
|
390
|
+
max: resolveDomainNumber(resource.max, context, 0),
|
|
391
|
+
})),
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function numberInput<State extends CollectorState = CollectorState>(options: {
|
|
398
|
+
min: DomainNumber<State>;
|
|
399
|
+
max: DomainNumber<State>;
|
|
400
|
+
step?: DomainNumber<State>;
|
|
401
|
+
}): InputCollector<z.ZodNumber, State, "form">;
|
|
402
|
+
function numberInput<State extends CollectorState = CollectorState>(options: {
|
|
403
|
+
min: DomainNumber<State>;
|
|
404
|
+
max: DomainNumber<State>;
|
|
405
|
+
step?: DomainNumber<State>;
|
|
406
|
+
defaultValue: number;
|
|
407
|
+
}): InputCollector<z.ZodNumber, State, "form"> & {
|
|
408
|
+
readonly defaultValue: number;
|
|
409
|
+
};
|
|
410
|
+
function numberInput<State extends CollectorState = CollectorState>(options: {
|
|
411
|
+
min: DomainNumber<State>;
|
|
412
|
+
max: DomainNumber<State>;
|
|
413
|
+
step?: DomainNumber<State>;
|
|
414
|
+
defaultValue?: number;
|
|
415
|
+
}): InputCollector<z.ZodNumber, State, "form"> {
|
|
416
|
+
return {
|
|
417
|
+
kind: "form",
|
|
418
|
+
schema: z.number(),
|
|
419
|
+
...("defaultValue" in options
|
|
420
|
+
? { defaultValue: options.defaultValue }
|
|
421
|
+
: {}),
|
|
422
|
+
domain: (state, playerId, q, derived): FormInputDomainDescriptor => {
|
|
423
|
+
const context = {
|
|
424
|
+
state: state as State,
|
|
425
|
+
playerId: playerId as PlayerIdOfState<State>,
|
|
426
|
+
q: q as TableQueriesOfState<State>,
|
|
427
|
+
derived,
|
|
428
|
+
values: {},
|
|
429
|
+
};
|
|
430
|
+
return {
|
|
431
|
+
type: "boundedNumber",
|
|
432
|
+
min: resolveDomainNumber(options.min, context, 0),
|
|
433
|
+
max: resolveDomainNumber(options.max, context, 0),
|
|
434
|
+
step:
|
|
435
|
+
options.step === undefined
|
|
436
|
+
? undefined
|
|
437
|
+
: resolveDomainNumber(options.step, context, 1),
|
|
438
|
+
};
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function choiceInput<
|
|
444
|
+
const Dependencies extends readonly InputFieldRef<string, unknown>[],
|
|
445
|
+
Value extends ChoiceValue = string,
|
|
446
|
+
State extends CollectorState = CollectorState,
|
|
447
|
+
>(options: {
|
|
448
|
+
dependsOn: Dependencies;
|
|
449
|
+
choices: DependentDomainChoices<Value, State, Dependencies>;
|
|
450
|
+
defaultValue: Value;
|
|
451
|
+
}): InputCollector<SchemaLike<Value>, State, "form"> & {
|
|
452
|
+
readonly defaultValue: Value;
|
|
453
|
+
};
|
|
454
|
+
function choiceInput<
|
|
455
|
+
const Dependencies extends readonly InputFieldRef<string, unknown>[],
|
|
456
|
+
Value extends ChoiceValue = string,
|
|
457
|
+
State extends CollectorState = CollectorState,
|
|
458
|
+
>(options: {
|
|
459
|
+
dependsOn: Dependencies;
|
|
460
|
+
choices: DependentDomainChoices<Value, State, Dependencies>;
|
|
461
|
+
defaultValue: ChoiceDefaultResolver<
|
|
462
|
+
Value,
|
|
463
|
+
State,
|
|
464
|
+
DependencyValues<Dependencies>
|
|
465
|
+
>;
|
|
466
|
+
}): InputCollector<SchemaLike<Value>, State, "form">;
|
|
467
|
+
function choiceInput<
|
|
468
|
+
Value extends ChoiceValue,
|
|
469
|
+
State extends CollectorState = CollectorState,
|
|
470
|
+
>(options: {
|
|
471
|
+
choices: DomainChoices<Value, State>;
|
|
472
|
+
defaultValue: Value;
|
|
473
|
+
}): InputCollector<SchemaLike<Value>, State, "form"> & {
|
|
474
|
+
readonly defaultValue: Value;
|
|
475
|
+
};
|
|
476
|
+
function choiceInput<
|
|
477
|
+
Value extends ChoiceValue,
|
|
478
|
+
State extends CollectorState = CollectorState,
|
|
479
|
+
>(options: {
|
|
480
|
+
choices: DomainChoices<Value, State>;
|
|
481
|
+
defaultValue: ChoiceDefaultResolver<Value, State>;
|
|
482
|
+
}): InputCollector<SchemaLike<Value>, State, "form">;
|
|
483
|
+
function choiceInput<
|
|
484
|
+
Value extends ChoiceValue,
|
|
485
|
+
State extends CollectorState = CollectorState,
|
|
486
|
+
const Dependencies extends readonly InputFieldRef<string, unknown>[] =
|
|
487
|
+
readonly InputFieldRef<string, unknown>[],
|
|
488
|
+
>(options: {
|
|
489
|
+
dependsOn: Dependencies;
|
|
490
|
+
choices: DependentDomainChoices<Value, State, Dependencies>;
|
|
491
|
+
defaultValue: Value;
|
|
492
|
+
}): InputCollector<SchemaLike<Value>, State, "form"> & {
|
|
493
|
+
readonly defaultValue: Value;
|
|
494
|
+
};
|
|
495
|
+
function choiceInput<
|
|
496
|
+
Value extends ChoiceValue,
|
|
497
|
+
State extends CollectorState = CollectorState,
|
|
498
|
+
const Dependencies extends readonly InputFieldRef<string, unknown>[] =
|
|
499
|
+
readonly InputFieldRef<string, unknown>[],
|
|
500
|
+
>(options: {
|
|
501
|
+
dependsOn: Dependencies;
|
|
502
|
+
choices: DependentDomainChoices<Value, State, Dependencies>;
|
|
503
|
+
defaultValue: ChoiceDefaultResolver<
|
|
504
|
+
Value,
|
|
505
|
+
State,
|
|
506
|
+
DependencyValues<Dependencies>
|
|
507
|
+
>;
|
|
508
|
+
}): InputCollector<SchemaLike<Value>, State, "form">;
|
|
509
|
+
function choiceInput<
|
|
510
|
+
Value extends ChoiceValue,
|
|
511
|
+
State extends CollectorState = CollectorState,
|
|
512
|
+
>(options: {
|
|
513
|
+
choices:
|
|
514
|
+
| DomainChoices<Value, State>
|
|
515
|
+
| DependentDomainChoices<
|
|
516
|
+
Value,
|
|
517
|
+
State,
|
|
518
|
+
readonly InputFieldRef<string, unknown>[]
|
|
519
|
+
>;
|
|
520
|
+
dependsOn?: readonly InputFieldRef<string, unknown>[];
|
|
521
|
+
defaultValue: ChoiceDefaultValue<
|
|
522
|
+
Value,
|
|
523
|
+
State,
|
|
524
|
+
Readonly<Record<string, unknown>>
|
|
525
|
+
>;
|
|
526
|
+
}): InputCollector<SchemaLike<Value>, State, "form"> {
|
|
527
|
+
const dependsOn = options.dependsOn?.map((dependency) => dependency.key);
|
|
528
|
+
if (Array.isArray(options.choices) && options.choices.length === 0) {
|
|
529
|
+
throw new Error("formInput.choice requires at least one choice.");
|
|
530
|
+
}
|
|
531
|
+
const staticChoices = Array.isArray(options.choices) ? options.choices : null;
|
|
532
|
+
const hasStaticDefault = typeof options.defaultValue !== "function";
|
|
533
|
+
const staticDefault = options.defaultValue as ChoiceValue;
|
|
534
|
+
if (staticChoices && hasStaticDefault) {
|
|
535
|
+
assertChoiceDefaultInChoices(
|
|
536
|
+
"formInput.choice",
|
|
537
|
+
staticChoices,
|
|
538
|
+
staticDefault,
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
const schema = staticChoices
|
|
542
|
+
? (choiceSchema(staticChoices) as SchemaLike<Value>)
|
|
543
|
+
: (z.string().nullable() as unknown as SchemaLike<Value>);
|
|
544
|
+
const dynamicDefault =
|
|
545
|
+
typeof options.defaultValue === "function"
|
|
546
|
+
? options.defaultValue
|
|
547
|
+
: undefined;
|
|
548
|
+
return {
|
|
549
|
+
kind: "form",
|
|
550
|
+
schema,
|
|
551
|
+
...(hasStaticDefault ? { defaultValue: staticDefault as Value } : {}),
|
|
552
|
+
...(dependsOn ? { dependsOn } : {}),
|
|
553
|
+
domain: (
|
|
554
|
+
state,
|
|
555
|
+
playerId,
|
|
556
|
+
q,
|
|
557
|
+
derived,
|
|
558
|
+
values,
|
|
559
|
+
): FormInputDomainDescriptor => {
|
|
560
|
+
const context = {
|
|
561
|
+
state: state as State,
|
|
562
|
+
playerId: playerId as PlayerIdOfState<State>,
|
|
563
|
+
q: q as TableQueriesOfState<State>,
|
|
564
|
+
derived,
|
|
565
|
+
};
|
|
566
|
+
const choices = dependsOn
|
|
567
|
+
? resolveDependentDomainChoices(
|
|
568
|
+
options.choices as DependentDomainChoices<
|
|
569
|
+
Value,
|
|
570
|
+
State,
|
|
571
|
+
readonly InputFieldRef<string, unknown>[]
|
|
572
|
+
>,
|
|
573
|
+
{
|
|
574
|
+
...context,
|
|
575
|
+
values: (values ?? {}) as DependencyValues<
|
|
576
|
+
readonly InputFieldRef<string, unknown>[]
|
|
577
|
+
>,
|
|
578
|
+
},
|
|
579
|
+
)
|
|
580
|
+
: resolveDomainChoices(options.choices as DomainChoices<Value, State>, {
|
|
581
|
+
...context,
|
|
582
|
+
values: {},
|
|
583
|
+
});
|
|
584
|
+
if (hasStaticDefault) {
|
|
585
|
+
assertChoiceDefaultInChoices(
|
|
586
|
+
"formInput.choice",
|
|
587
|
+
choices,
|
|
588
|
+
staticDefault,
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
return {
|
|
592
|
+
type: "choice",
|
|
593
|
+
choices,
|
|
594
|
+
};
|
|
595
|
+
},
|
|
596
|
+
...(dynamicDefault
|
|
597
|
+
? {
|
|
598
|
+
resolveDefaultValue: (state, playerId, q, derived, domain) => {
|
|
599
|
+
const choices =
|
|
600
|
+
domain.type === "choice"
|
|
601
|
+
? domain.choices.map((choice) => ({
|
|
602
|
+
value: choice.value as Value,
|
|
603
|
+
label: choice.label,
|
|
604
|
+
icon: choice.icon,
|
|
605
|
+
badge: choice.badge,
|
|
606
|
+
description: choice.description,
|
|
607
|
+
disabled: choice.disabled,
|
|
608
|
+
disabledReason: choice.disabledReason,
|
|
609
|
+
}))
|
|
610
|
+
: [];
|
|
611
|
+
const resolved = dynamicDefault({
|
|
612
|
+
state: state as State,
|
|
613
|
+
playerId: playerId as PlayerIdOfState<State>,
|
|
614
|
+
q: q as TableQueriesOfState<State>,
|
|
615
|
+
derived,
|
|
616
|
+
values: {},
|
|
617
|
+
choices,
|
|
618
|
+
});
|
|
619
|
+
if (resolved === undefined) return undefined;
|
|
620
|
+
assertChoiceDefaultInChoices("formInput.choice", choices, resolved);
|
|
621
|
+
return resolved;
|
|
622
|
+
},
|
|
623
|
+
}
|
|
624
|
+
: {}),
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
function choiceListInput<
|
|
629
|
+
Value extends string,
|
|
630
|
+
State extends CollectorState = CollectorState,
|
|
631
|
+
>(options: {
|
|
632
|
+
choices: DomainChoices<Value, State>;
|
|
633
|
+
min?: DomainNumber<State>;
|
|
634
|
+
max?: DomainNumber<State>;
|
|
635
|
+
defaultValue: Value[];
|
|
636
|
+
}): InputCollector<SchemaLike<Value[]>, State, "form"> & {
|
|
637
|
+
readonly defaultValue: Value[];
|
|
638
|
+
};
|
|
639
|
+
function choiceListInput<
|
|
640
|
+
Value extends string,
|
|
641
|
+
State extends CollectorState = CollectorState,
|
|
642
|
+
>(options: {
|
|
643
|
+
choices: DomainChoices<Value, State>;
|
|
644
|
+
min?: DomainNumber<State>;
|
|
645
|
+
max?: DomainNumber<State>;
|
|
646
|
+
defaultValue?: ChoiceListDefaultValue<Value, State>;
|
|
647
|
+
}): InputCollector<SchemaLike<Value[]>, State, "form">;
|
|
648
|
+
function choiceListInput<
|
|
649
|
+
Value extends string,
|
|
650
|
+
State extends CollectorState = CollectorState,
|
|
651
|
+
>(options: {
|
|
652
|
+
choices: DomainChoices<Value, State>;
|
|
653
|
+
min?: DomainNumber<State>;
|
|
654
|
+
max?: DomainNumber<State>;
|
|
655
|
+
defaultValue?: ChoiceListDefaultValue<Value, State>;
|
|
656
|
+
}): InputCollector<SchemaLike<Value[]>, State, "form"> {
|
|
657
|
+
if (Array.isArray(options.choices) && options.choices.length === 0) {
|
|
658
|
+
throw new Error("formInput.choiceList requires at least one choice.");
|
|
659
|
+
}
|
|
660
|
+
const staticDefaultValue = Array.isArray(options.defaultValue)
|
|
661
|
+
? options.defaultValue
|
|
662
|
+
: undefined;
|
|
663
|
+
const dynamicDefaultValue =
|
|
664
|
+
options.defaultValue === "all" || typeof options.defaultValue === "function"
|
|
665
|
+
? options.defaultValue
|
|
666
|
+
: undefined;
|
|
667
|
+
return {
|
|
668
|
+
kind: "form",
|
|
669
|
+
schema: z.array(z.string()) as unknown as SchemaLike<Value[]>,
|
|
670
|
+
...(staticDefaultValue !== undefined
|
|
671
|
+
? { defaultValue: staticDefaultValue }
|
|
672
|
+
: {}),
|
|
673
|
+
domain: (state, playerId, q, derived): FormInputDomainDescriptor => {
|
|
674
|
+
const context = {
|
|
675
|
+
state: state as State,
|
|
676
|
+
playerId: playerId as PlayerIdOfState<State>,
|
|
677
|
+
q: q as TableQueriesOfState<State>,
|
|
678
|
+
derived,
|
|
679
|
+
values: {},
|
|
680
|
+
};
|
|
681
|
+
const choices = resolveDomainChoices(options.choices, context).map(
|
|
682
|
+
(choice) => ({
|
|
683
|
+
...choice,
|
|
684
|
+
value: choice.value as string,
|
|
685
|
+
}),
|
|
686
|
+
);
|
|
687
|
+
return {
|
|
688
|
+
type: "choiceList",
|
|
689
|
+
choices,
|
|
690
|
+
min: resolveDomainNumber(options.min, context, 0),
|
|
691
|
+
max: resolveDomainNumber(options.max, context, choices.length),
|
|
692
|
+
};
|
|
693
|
+
},
|
|
694
|
+
...(dynamicDefaultValue
|
|
695
|
+
? {
|
|
696
|
+
resolveDefaultValue: (state, playerId, q, derived, domain) => {
|
|
697
|
+
const choices =
|
|
698
|
+
domain.type === "choiceList"
|
|
699
|
+
? domain.choices.map((choice) => ({
|
|
700
|
+
value: choice.value as Value,
|
|
701
|
+
label: choice.label,
|
|
702
|
+
icon: choice.icon,
|
|
703
|
+
badge: choice.badge,
|
|
704
|
+
description: choice.description,
|
|
705
|
+
disabled: choice.disabled,
|
|
706
|
+
disabledReason: choice.disabledReason,
|
|
707
|
+
}))
|
|
708
|
+
: [];
|
|
709
|
+
if (dynamicDefaultValue === "all") {
|
|
710
|
+
return choices.map((choice) => choice.value);
|
|
711
|
+
}
|
|
712
|
+
return dynamicDefaultValue({
|
|
713
|
+
state: state as State,
|
|
714
|
+
playerId: playerId as PlayerIdOfState<State>,
|
|
715
|
+
q: q as TableQueriesOfState<State>,
|
|
716
|
+
derived,
|
|
717
|
+
values: {},
|
|
718
|
+
choices,
|
|
719
|
+
});
|
|
720
|
+
},
|
|
721
|
+
}
|
|
722
|
+
: {}),
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
type FormInputForState<State extends CollectorState> = {
|
|
727
|
+
<Schema extends ManifestFormInputSchema & SchemaLike<unknown>>(
|
|
728
|
+
schema: Schema,
|
|
729
|
+
): InputCollector<Schema, State, "form">;
|
|
730
|
+
<Schema extends ManifestFormInputSchema & SchemaLike<unknown>>(
|
|
731
|
+
schema: Schema,
|
|
732
|
+
options: { defaultValue: z.infer<Schema> },
|
|
733
|
+
): InputCollector<Schema, State, "form"> & {
|
|
734
|
+
readonly defaultValue: z.infer<Schema>;
|
|
735
|
+
};
|
|
736
|
+
resourceMap(
|
|
737
|
+
options: Parameters<typeof resourceMapInput<State>>[0],
|
|
738
|
+
): ReturnType<typeof resourceMapInput<State>>;
|
|
739
|
+
resourceChoices(options?: {
|
|
740
|
+
decorate?: ResourceMapChoiceDecorator<State>;
|
|
741
|
+
}): ResourceMapChoiceSource<State>;
|
|
742
|
+
number(
|
|
743
|
+
options: Parameters<typeof numberInput<State>>[0],
|
|
744
|
+
): ReturnType<typeof numberInput<State>>;
|
|
745
|
+
choice<Value extends ChoiceValue>(options: {
|
|
746
|
+
choices: DomainChoices<Value, State>;
|
|
747
|
+
defaultValue: Value;
|
|
748
|
+
}): InputCollector<SchemaLike<Value>, State, "form"> & {
|
|
749
|
+
readonly defaultValue: Value;
|
|
750
|
+
};
|
|
751
|
+
choice<Value extends ChoiceValue>(options: {
|
|
752
|
+
choices: DomainChoices<Value, State>;
|
|
753
|
+
defaultValue: ChoiceDefaultResolver<Value, State>;
|
|
754
|
+
}): InputCollector<SchemaLike<Value>, State, "form">;
|
|
755
|
+
choiceList<Value extends string>(options: {
|
|
756
|
+
choices: DomainChoices<Value, State>;
|
|
757
|
+
min?: DomainNumber<State>;
|
|
758
|
+
max?: DomainNumber<State>;
|
|
759
|
+
defaultValue: Value[];
|
|
760
|
+
}): InputCollector<SchemaLike<Value[]>, State, "form"> & {
|
|
761
|
+
readonly defaultValue: Value[];
|
|
762
|
+
};
|
|
763
|
+
choiceList<Value extends string>(options: {
|
|
764
|
+
choices: DomainChoices<Value, State>;
|
|
765
|
+
min?: DomainNumber<State>;
|
|
766
|
+
max?: DomainNumber<State>;
|
|
767
|
+
defaultValue?: ChoiceListDefaultValue<Value, State>;
|
|
768
|
+
}): InputCollector<SchemaLike<Value[]>, State, "form">;
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
function formInputForState<
|
|
772
|
+
State extends CollectorState,
|
|
773
|
+
>(): FormInputForState<State> {
|
|
774
|
+
return Object.assign(
|
|
775
|
+
((schema: ManifestFormInputSchema & SchemaLike<unknown>, options?: {}) =>
|
|
776
|
+
baseFormInput(schema, options as never)) as FormInputForState<State>,
|
|
777
|
+
{
|
|
778
|
+
resourceMap: (options: Parameters<typeof resourceMapInput<State>>[0]) =>
|
|
779
|
+
resourceMapInput<State>(options),
|
|
780
|
+
resourceChoices: (options?: {
|
|
781
|
+
decorate?: ResourceMapChoiceDecorator<State>;
|
|
782
|
+
}) => formInput.resourceChoices<State>(options),
|
|
783
|
+
number: (options: Parameters<typeof numberInput<State>>[0]) =>
|
|
784
|
+
numberInput<State>(options),
|
|
785
|
+
choice: (options: never) => choiceInput(options),
|
|
786
|
+
choiceList: (options: never) => choiceListInput(options),
|
|
787
|
+
},
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* Manifest-backed id input. Free-form Zod schemas are intentionally explicit:
|
|
793
|
+
* if the runtime cannot disclose valid values or numeric bounds through a
|
|
794
|
+
* manifest id or domain helper, use a custom interaction surface with an
|
|
795
|
+
* explicit `paramsSchema` instead of the default form renderer.
|
|
796
|
+
*/
|
|
797
|
+
export const formInput = Object.assign(baseFormInput, {
|
|
798
|
+
resourceMap: resourceMapInput,
|
|
799
|
+
resourceChoices: <State extends CollectorState = CollectorState>(options?: {
|
|
800
|
+
decorate?: ResourceMapChoiceDecorator<State>;
|
|
801
|
+
}): ResourceMapChoiceSource<State> => ({
|
|
802
|
+
source: "resourceMap",
|
|
803
|
+
...options,
|
|
804
|
+
}),
|
|
805
|
+
number: numberInput,
|
|
806
|
+
choice: choiceInput,
|
|
807
|
+
choiceList: choiceListInput,
|
|
808
|
+
forState: formInputForState,
|
|
809
|
+
});
|