@dreamboard-games/sdk 0.5.0-alpha.4 → 0.5.0-alpha.6
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/README.md +14 -9
- package/dist/{chunk-OOFMBCFF.js → chunk-CSHKCPBY.js} +244 -51
- package/dist/chunk-CSHKCPBY.js.map +1 -0
- package/dist/{chunk-XU6WJW6K.js → chunk-K75F5UIJ.js} +2 -1
- package/dist/chunk-K75F5UIJ.js.map +1 -0
- package/dist/{chunk-UG2Q4NLG.js → chunk-N37D7NPB.js} +11 -3
- package/dist/chunk-N37D7NPB.js.map +1 -0
- package/dist/{chunk-C77SYIVT.js → chunk-UESVBUPU.js} +396 -392
- package/dist/chunk-UESVBUPU.js.map +1 -0
- package/dist/{diagnostics-B8d5aLad.d.ts → diagnostics-9gJgI85c.d.ts} +2 -2
- package/dist/{extract-gVKcB8Og.d.ts → extract-Bjuw_gdF.d.ts} +2413 -2387
- package/dist/index.d.ts +255 -32
- package/dist/index.js +247 -63
- package/dist/index.js.map +1 -1
- package/dist/{model-vdpLHrxh.d.ts → model-D2Z9j0Yi.d.ts} +169 -35
- package/dist/react.d.ts +45 -30
- package/dist/react.js +337 -139
- package/dist/react.js.map +1 -1
- package/dist/reducer.d.ts +68 -43
- package/dist/reducer.js +145 -245
- package/dist/reducer.js.map +1 -1
- package/dist/testing.d.ts +52 -42
- package/dist/testing.js +114 -66
- package/dist/testing.js.map +1 -1
- package/dist/{types-Bj5ZLTUV.d.ts → types-B3kIhBWb.d.ts} +4 -1
- package/package.json +2 -5
- package/dist/chunk-C77SYIVT.js.map +0 -1
- package/dist/chunk-OOFMBCFF.js.map +0 -1
- package/dist/chunk-UG2Q4NLG.js.map +0 -1
- package/dist/chunk-XU6WJW6K.js.map +0 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ pnpm add @dreamboard-games/sdk
|
|
|
13
13
|
The package declarations and export map are the API authority. There are four entry points:
|
|
14
14
|
|
|
15
15
|
- `@dreamboard-games/sdk`: framework-free instances, sources, features and canonical host protocol schemas.
|
|
16
|
-
- `@dreamboard-games/sdk/react`: typed React provider, selectors, subscriptions, and
|
|
16
|
+
- `@dreamboard-games/sdk/react`: typed React provider, selectors, subscriptions, and card gesture and drop-area hooks.
|
|
17
17
|
- `@dreamboard-games/sdk/reducer`: game authoring, manifest compilation, execution and trusted worker admission.
|
|
18
18
|
- `@dreamboard-games/sdk/testing`: browser-safe local/scenario sources, replay, inspection and bounded exploration.
|
|
19
19
|
|
|
@@ -221,7 +221,8 @@ cards: [
|
|
|
221
221
|
```
|
|
222
222
|
|
|
223
223
|
These definitions create runtime IDs `ace-1`, `ace-2`, and `king`, all in the
|
|
224
|
-
`ranked` category.
|
|
224
|
+
`ranked` category. Card IDs cannot start with `hidden:`; that prefix is reserved
|
|
225
|
+
for the positions a seat uses to address concealed cards. When the card schema has `variants`, every `cardType` must
|
|
225
226
|
name one of them; `compileManifest` and `createGame` reject unknown categories.
|
|
226
227
|
The inferred table narrows a card lookup by its runtime ID to that definition's
|
|
227
228
|
card set, category, and properties. A variant property overrides a shared
|
|
@@ -233,14 +234,15 @@ To migrate an older manifest, replace each card's `type` with `id` and set
|
|
|
233
234
|
|
|
234
235
|
`createReducerBundle(game)` returns exactly the contract version and four
|
|
235
236
|
operations: `boardStatic()`, `initialize(input)`, `dispatch({ state, input })`,
|
|
236
|
-
and `project({ state, playerIds })`. The runner contract is `0.
|
|
237
|
+
and `project({ state, playerIds })`. The runner contract is `0.8.0`; hosts must
|
|
237
238
|
require that exact version. Dispatch includes validation, direct transaction mutations, and phase entry.
|
|
238
239
|
Initialization returns
|
|
239
240
|
`{ state, terminal?, events? }`, preserving outcomes and events from initial
|
|
240
241
|
phase entry and returned transitions.
|
|
241
242
|
|
|
242
|
-
Mutation callbacks use `tx.roll(dieId)`, `tx.shuffle({ zoneId, playerId? })`,
|
|
243
|
-
`tx.deal({ fromZoneId, toZoneId, playerId, count })`
|
|
243
|
+
Mutation callbacks use `tx.roll(dieId)`, `tx.shuffle({ zoneId, playerId? })`,
|
|
244
|
+
`tx.deal({ fromZoneId, toZoneId, playerId, count })` and
|
|
245
|
+
`tx.flipCard({ cardId, faceUp })` directly. Return
|
|
244
246
|
`tx.transition(phaseName)` to enter a phase, including reentering the current
|
|
245
247
|
phase. An unreturned outcome schedules no work. Entry chains are bounded to
|
|
246
248
|
1,000 entries per dispatch. `tx.endGame(outcome, { transition })` enters the
|
|
@@ -296,10 +298,13 @@ pnpm add @dreamboard-games/sdk react@^19 react-dom@^19 @tanstack/react-store@0.1
|
|
|
296
298
|
install the React adapter. The `/react` entry delegates selectors to that package;
|
|
297
299
|
the application bundler resolves its supported React subscription dependencies.
|
|
298
300
|
|
|
299
|
-
|
|
300
|
-
`
|
|
301
|
-
BoardTargets components or your own renderer.
|
|
302
|
-
Headless `game.drag` remains browser-free and handles
|
|
301
|
+
`/react` classifies each card press as a tap, hold, drag or browse. Enable
|
|
302
|
+
`dragFeature`, export `useCardGesture`, `useDropArea` and `useDragOverlay` from the
|
|
303
|
+
binding, and use the copied Hand and BoardTargets components or your own renderer.
|
|
304
|
+
The SDK prescribes no layout. Headless `game.drag` remains browser-free and handles
|
|
305
|
+
atomic domain routing. `fanLayout` computes arc positions for a hand, and
|
|
306
|
+
`originsFeature` adds `card.getOrigin()` so a newly shown card can animate from
|
|
307
|
+
the zone or player it came from.
|
|
303
308
|
|
|
304
309
|
## Local development and tests
|
|
305
310
|
|
|
@@ -9,6 +9,66 @@ import {
|
|
|
9
9
|
requireLookup
|
|
10
10
|
} from "./chunk-3JXUL4VN.js";
|
|
11
11
|
|
|
12
|
+
// src/headless/runtime-features.ts
|
|
13
|
+
var runtimeFeatures = /* @__PURE__ */ Symbol("runtimeFeatures");
|
|
14
|
+
|
|
15
|
+
// src/headless/input-control.ts
|
|
16
|
+
function resourceValue(domain, value) {
|
|
17
|
+
const record = value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
18
|
+
return Object.fromEntries(
|
|
19
|
+
domain.resources.map((resource) => {
|
|
20
|
+
const amount = record[resource.resourceId];
|
|
21
|
+
return [resource.resourceId, typeof amount === "number" ? amount : 0];
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
function createInputControl(input, props) {
|
|
26
|
+
const domain = input.getDomain();
|
|
27
|
+
const current = input.getValue();
|
|
28
|
+
const common = { key: input.key, disabled: props.disabled, props };
|
|
29
|
+
if (domain.type === "boundedNumber") {
|
|
30
|
+
if (domain.selection?.mode === "many")
|
|
31
|
+
return {
|
|
32
|
+
...common,
|
|
33
|
+
type: "boundedNumber",
|
|
34
|
+
domain,
|
|
35
|
+
mode: "many",
|
|
36
|
+
value: Array.isArray(current) ? current.filter(
|
|
37
|
+
(value) => typeof value === "number"
|
|
38
|
+
) : [],
|
|
39
|
+
setValue: (value) => input.setValue(value)
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
...common,
|
|
43
|
+
type: "boundedNumber",
|
|
44
|
+
domain,
|
|
45
|
+
mode: "single",
|
|
46
|
+
value: typeof current === "number" ? current : void 0,
|
|
47
|
+
setValue: (value) => value === void 0 ? input.clear() : input.setValue(value)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (domain.type === "resourceMap") {
|
|
51
|
+
if (domain.selection?.mode === "many")
|
|
52
|
+
return {
|
|
53
|
+
...common,
|
|
54
|
+
type: "resourceMap",
|
|
55
|
+
domain,
|
|
56
|
+
mode: "many",
|
|
57
|
+
value: Array.isArray(current) ? current.map((value) => resourceValue(domain, value)) : [],
|
|
58
|
+
setValue: (value) => input.setValue(value)
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
...common,
|
|
62
|
+
type: "resourceMap",
|
|
63
|
+
domain,
|
|
64
|
+
mode: "single",
|
|
65
|
+
value: current === void 0 ? void 0 : resourceValue(domain, current),
|
|
66
|
+
setValue: (value) => value === void 0 ? input.clear() : input.setValue(value)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return { ...common, type: "targets", options: input.getTargetOptions() };
|
|
70
|
+
}
|
|
71
|
+
|
|
12
72
|
// src/headless/instance.ts
|
|
13
73
|
import { createStore } from "@tanstack/store";
|
|
14
74
|
|
|
@@ -348,6 +408,21 @@ var InputObject = class {
|
|
|
348
408
|
get game() {
|
|
349
409
|
return this.interaction.game;
|
|
350
410
|
}
|
|
411
|
+
get domainType() {
|
|
412
|
+
return this.descriptor.domain.type;
|
|
413
|
+
}
|
|
414
|
+
get selectionMode() {
|
|
415
|
+
return isManyInput(this.descriptor) ? "many" : "single";
|
|
416
|
+
}
|
|
417
|
+
getTargetOptions() {
|
|
418
|
+
const domain = this.getDomain();
|
|
419
|
+
return this.getEligibleTargets().map((value) => ({
|
|
420
|
+
value,
|
|
421
|
+
label: (domain.type === "choice" || domain.type === "choiceList" ? domain.choices.find((choice) => Object.is(choice.value, value))?.label : void 0) ?? (value === null ? "None" : typeof value === "object" ? JSON.stringify(value) : String(value)),
|
|
422
|
+
selected: this.getIsSelected(value),
|
|
423
|
+
props: this.getTargetProps(value)
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
351
426
|
getDomain() {
|
|
352
427
|
return this.descriptor.domain;
|
|
353
428
|
}
|
|
@@ -407,28 +482,18 @@ var InputObject = class {
|
|
|
407
482
|
onClick: () => this.getSelectHandler(value)()
|
|
408
483
|
};
|
|
409
484
|
}
|
|
410
|
-
|
|
485
|
+
getControl() {
|
|
411
486
|
const disabled = !this.interaction.getIsAvailable() || this.interaction.status !== "open" || !this.interaction.connected;
|
|
412
|
-
return {
|
|
487
|
+
return createInputControl(this, {
|
|
413
488
|
...data("option", this.interaction.key, this.key),
|
|
414
489
|
"data-seat": this.interaction.seat,
|
|
415
|
-
value: this.getValue() ?? "",
|
|
416
490
|
disabled,
|
|
417
|
-
"data-disabled": disabled
|
|
418
|
-
|
|
419
|
-
if (event.currentTarget.value === "") {
|
|
420
|
-
this.clear();
|
|
421
|
-
return;
|
|
422
|
-
}
|
|
423
|
-
this.setValue(
|
|
424
|
-
this.descriptor.domain.type === "boundedNumber" ? Number(event.currentTarget.value) : event.currentTarget.value
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
};
|
|
491
|
+
"data-disabled": disabled
|
|
492
|
+
});
|
|
428
493
|
}
|
|
429
494
|
};
|
|
430
495
|
var CardObject = class {
|
|
431
|
-
constructor(owner, id, zone, index, encoded, routes) {
|
|
496
|
+
constructor(owner, id, zone, index, encoded, backImage, routes) {
|
|
432
497
|
this.owner = owner;
|
|
433
498
|
this.id = id;
|
|
434
499
|
this.zone = zone;
|
|
@@ -440,6 +505,7 @@ var CardObject = class {
|
|
|
440
505
|
) ?? -1;
|
|
441
506
|
this.view = encoded ? immutableCopy(JSON.parse(encoded)) : null;
|
|
442
507
|
this.hidden = this.view === null;
|
|
508
|
+
this.backImage = backImage ?? null;
|
|
443
509
|
}
|
|
444
510
|
owner;
|
|
445
511
|
id;
|
|
@@ -450,6 +516,7 @@ var CardObject = class {
|
|
|
450
516
|
seat;
|
|
451
517
|
view;
|
|
452
518
|
hidden;
|
|
519
|
+
backImage;
|
|
453
520
|
get game() {
|
|
454
521
|
return this.owner.instance;
|
|
455
522
|
}
|
|
@@ -602,7 +669,60 @@ var Controller = class {
|
|
|
602
669
|
this.localDrafts = options.initialState?.drafts ?? EMPTY_DRAFTS;
|
|
603
670
|
this.localActive = options.initialState?.activeInteraction ?? null;
|
|
604
671
|
this.sourceState = options.source.store.get();
|
|
672
|
+
const current = () => this.building ?? this.store.get();
|
|
605
673
|
const root = {
|
|
674
|
+
get snapshot() {
|
|
675
|
+
return current().snapshot;
|
|
676
|
+
},
|
|
677
|
+
get view() {
|
|
678
|
+
return current().view;
|
|
679
|
+
},
|
|
680
|
+
get version() {
|
|
681
|
+
return current().version;
|
|
682
|
+
},
|
|
683
|
+
get connection() {
|
|
684
|
+
return current().connection;
|
|
685
|
+
},
|
|
686
|
+
get failure() {
|
|
687
|
+
return current().failure;
|
|
688
|
+
},
|
|
689
|
+
get request() {
|
|
690
|
+
return current().request;
|
|
691
|
+
},
|
|
692
|
+
get state() {
|
|
693
|
+
return current().state;
|
|
694
|
+
},
|
|
695
|
+
get phase() {
|
|
696
|
+
return current().phase;
|
|
697
|
+
},
|
|
698
|
+
get turn() {
|
|
699
|
+
return current().turn;
|
|
700
|
+
},
|
|
701
|
+
get me() {
|
|
702
|
+
return current().me;
|
|
703
|
+
},
|
|
704
|
+
get players() {
|
|
705
|
+
return current().players;
|
|
706
|
+
},
|
|
707
|
+
get interactions() {
|
|
708
|
+
return current().interactions;
|
|
709
|
+
},
|
|
710
|
+
get inputs() {
|
|
711
|
+
return current().inputs;
|
|
712
|
+
},
|
|
713
|
+
get zones() {
|
|
714
|
+
return current().zones;
|
|
715
|
+
},
|
|
716
|
+
get cards() {
|
|
717
|
+
return current().cards;
|
|
718
|
+
},
|
|
719
|
+
get events() {
|
|
720
|
+
return current().events;
|
|
721
|
+
},
|
|
722
|
+
store: {
|
|
723
|
+
get: () => this.store.get(),
|
|
724
|
+
subscribe: (listener) => this.store.subscribe(listener)
|
|
725
|
+
},
|
|
606
726
|
getSnapshot: () => this.building ?? this.store.get(),
|
|
607
727
|
getOptions: () => this.options,
|
|
608
728
|
setOptions: (next) => this.setOptions(next),
|
|
@@ -614,35 +734,23 @@ var Controller = class {
|
|
|
614
734
|
assertCoverage: () => this.assertCoverage(),
|
|
615
735
|
inspect: () => this.store.get()
|
|
616
736
|
};
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
"state",
|
|
626
|
-
"phase",
|
|
627
|
-
"turn",
|
|
628
|
-
"me",
|
|
629
|
-
"players",
|
|
630
|
-
"interactions",
|
|
631
|
-
"inputs",
|
|
632
|
-
"zones",
|
|
633
|
-
"cards",
|
|
634
|
-
"events"
|
|
635
|
-
])
|
|
636
|
-
Object.defineProperty(root, key, {
|
|
637
|
-
get: () => (this.building ?? this.store.get())[key]
|
|
638
|
-
});
|
|
639
|
-
this.store = createStore(Object.freeze(this.build()));
|
|
640
|
-
Object.defineProperty(root, "store", {
|
|
641
|
-
value: {
|
|
642
|
-
get: () => this.store.get(),
|
|
643
|
-
subscribe: (listener) => this.store.subscribe(listener)
|
|
737
|
+
for (const [key, descriptor] of Object.entries(
|
|
738
|
+
Object.getOwnPropertyDescriptors(root)
|
|
739
|
+
)) {
|
|
740
|
+
if (descriptor.get) {
|
|
741
|
+
Object.defineProperty(root, key, {
|
|
742
|
+
enumerable: false,
|
|
743
|
+
configurable: false
|
|
744
|
+
});
|
|
644
745
|
}
|
|
746
|
+
}
|
|
747
|
+
Object.defineProperty(root, "store", {
|
|
748
|
+
enumerable: false,
|
|
749
|
+
configurable: false,
|
|
750
|
+
writable: false
|
|
645
751
|
});
|
|
752
|
+
this.instance = root;
|
|
753
|
+
this.store = createStore(Object.freeze(this.build()));
|
|
646
754
|
if ("apply" in options.source)
|
|
647
755
|
Object.defineProperty(root, "apply", {
|
|
648
756
|
value: (action) => this.options.source.apply(action)
|
|
@@ -651,9 +759,14 @@ var Controller = class {
|
|
|
651
759
|
Object.defineProperty(root, "explore", {
|
|
652
760
|
value: (...args) => this.options.source.explore(...args)
|
|
653
761
|
});
|
|
654
|
-
const
|
|
655
|
-
|
|
656
|
-
|
|
762
|
+
const runtime = {
|
|
763
|
+
game: this.instance,
|
|
764
|
+
getBoards: () => {
|
|
765
|
+
const view = this.instance.view;
|
|
766
|
+
return view?.boards?.byId ?? {};
|
|
767
|
+
},
|
|
768
|
+
createBoard: (data2) => this.object("board", {
|
|
769
|
+
id: data2.id,
|
|
657
770
|
data: immutableCopy(data2),
|
|
658
771
|
game: this.instance
|
|
659
772
|
}),
|
|
@@ -663,6 +776,7 @@ var Controller = class {
|
|
|
663
776
|
if (!this.disposed) this.refresh();
|
|
664
777
|
}
|
|
665
778
|
};
|
|
779
|
+
const context = { ...runtime, [runtimeFeatures]: runtime };
|
|
666
780
|
for (const feature of Object.values(
|
|
667
781
|
features?.(this.instance, context) ?? {}
|
|
668
782
|
)) {
|
|
@@ -725,7 +839,8 @@ var Controller = class {
|
|
|
725
839
|
);
|
|
726
840
|
}
|
|
727
841
|
object(hook, value) {
|
|
728
|
-
|
|
842
|
+
Object.setPrototypeOf(value, this.prototypes[hook]);
|
|
843
|
+
return Object.freeze(value);
|
|
729
844
|
}
|
|
730
845
|
drafts() {
|
|
731
846
|
if (this.options.state && this.options.state === this.invalidControlledState)
|
|
@@ -1069,10 +1184,17 @@ var Controller = class {
|
|
|
1069
1184
|
if (!interaction?.currentLifetime() || !interaction.getIsAvailable())
|
|
1070
1185
|
return;
|
|
1071
1186
|
const cardInput = interaction.findInput(target.cardInputKey);
|
|
1072
|
-
|
|
1073
|
-
|
|
1187
|
+
if (!cardInput || cardInput.descriptor.domain.type !== "cardTarget" || !cardInput.getIsEligible(cardId))
|
|
1188
|
+
return;
|
|
1189
|
+
const input = target.kind === "interaction" ? void 0 : interaction.findInput(target.inputKey);
|
|
1190
|
+
if (target.kind !== "interaction" && (!input || !matchesBoardTarget(input.descriptor, target) || !input.getIsEligible(target.value)))
|
|
1074
1191
|
return;
|
|
1075
1192
|
let next = { ...this.drafts()[interaction.key] };
|
|
1193
|
+
const chosen = next[cardInput.key];
|
|
1194
|
+
if (!input && isManyInput(cardInput.descriptor) && Array.isArray(chosen) && chosen.includes(cardId)) {
|
|
1195
|
+
this.activate(interaction.key);
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1076
1198
|
routeCardInputIntent(
|
|
1077
1199
|
{
|
|
1078
1200
|
getDraft: () => next,
|
|
@@ -1087,7 +1209,7 @@ var Controller = class {
|
|
|
1087
1209
|
{
|
|
1088
1210
|
cardId,
|
|
1089
1211
|
cardInputKey: cardInput.key,
|
|
1090
|
-
dropTarget: { inputKey: input.key, value: target.value }
|
|
1212
|
+
dropTarget: input && target.kind !== "interaction" ? { inputKey: input.key, value: target.value } : void 0
|
|
1091
1213
|
}
|
|
1092
1214
|
);
|
|
1093
1215
|
this.writeDraft(interaction.key, next);
|
|
@@ -1233,6 +1355,7 @@ var Controller = class {
|
|
|
1233
1355
|
id,
|
|
1234
1356
|
index,
|
|
1235
1357
|
zone.cardViewsById[cardId],
|
|
1358
|
+
zone.cardBacksById[cardId],
|
|
1236
1359
|
Object.freeze(
|
|
1237
1360
|
(zone.playableByCardId[cardId] ?? []).map(
|
|
1238
1361
|
(descriptor) => this.object(
|
|
@@ -1331,8 +1454,78 @@ function createGameInstance() {
|
|
|
1331
1454
|
};
|
|
1332
1455
|
}
|
|
1333
1456
|
|
|
1457
|
+
// src/headless/gesture.ts
|
|
1458
|
+
var GESTURE_THRESHOLDS = Object.freeze({
|
|
1459
|
+
/** Movement, in CSS pixels, before a press becomes a drag or a browse. */
|
|
1460
|
+
slop: 8,
|
|
1461
|
+
/** A touch or pen held this long without moving inspects the card. */
|
|
1462
|
+
holdMs: 350,
|
|
1463
|
+
/** A mouse resting on a card this long inspects it. */
|
|
1464
|
+
hoverMs: 250,
|
|
1465
|
+
/** A finger drags when upward travel exceeds this multiple of sideways travel. */
|
|
1466
|
+
axisBias: 1.25
|
|
1467
|
+
});
|
|
1468
|
+
function createGestureRecognizer(down, callbacks) {
|
|
1469
|
+
const origin = { x: down.clientX, y: down.clientY };
|
|
1470
|
+
const mouse = down.pointerType === "mouse";
|
|
1471
|
+
let kind = "tap";
|
|
1472
|
+
let finished = false;
|
|
1473
|
+
const holdTimer = mouse ? void 0 : setTimeout(() => {
|
|
1474
|
+
kind = "hold";
|
|
1475
|
+
callbacks.hold();
|
|
1476
|
+
}, GESTURE_THRESHOLDS.holdMs);
|
|
1477
|
+
const point = (event) => ({
|
|
1478
|
+
x: event.clientX,
|
|
1479
|
+
y: event.clientY
|
|
1480
|
+
});
|
|
1481
|
+
const ours = (event) => !finished && (!event || event.pointerId === down.pointerId);
|
|
1482
|
+
function finish() {
|
|
1483
|
+
finished = true;
|
|
1484
|
+
clearTimeout(holdTimer);
|
|
1485
|
+
}
|
|
1486
|
+
return {
|
|
1487
|
+
move(event) {
|
|
1488
|
+
if (!ours(event)) return;
|
|
1489
|
+
if (kind === "drag") return callbacks.dragMove(point(event));
|
|
1490
|
+
const dx = event.clientX - origin.x;
|
|
1491
|
+
const dy = event.clientY - origin.y;
|
|
1492
|
+
if (kind !== "tap" || Math.hypot(dx, dy) < GESTURE_THRESHOLDS.slop)
|
|
1493
|
+
return;
|
|
1494
|
+
clearTimeout(holdTimer);
|
|
1495
|
+
const lifts = mouse || -dy > GESTURE_THRESHOLDS.axisBias * Math.abs(dx);
|
|
1496
|
+
if (lifts && callbacks.dragStart(origin)) {
|
|
1497
|
+
kind = "drag";
|
|
1498
|
+
callbacks.dragMove(point(event));
|
|
1499
|
+
} else kind = "browse";
|
|
1500
|
+
},
|
|
1501
|
+
up(event) {
|
|
1502
|
+
if (!ours(event)) return;
|
|
1503
|
+
finish();
|
|
1504
|
+
callbacks.end(kind, point(event));
|
|
1505
|
+
},
|
|
1506
|
+
cancel(event) {
|
|
1507
|
+
if (!ours(event)) return;
|
|
1508
|
+
finish();
|
|
1509
|
+
callbacks.cancel(kind);
|
|
1510
|
+
}
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
// src/headless/drop-targets.ts
|
|
1515
|
+
function isSameDropTarget(left, right) {
|
|
1516
|
+
if (left.interactionKey !== right.interactionKey || left.cardInputKey !== right.cardInputKey)
|
|
1517
|
+
return false;
|
|
1518
|
+
if (left.kind === "interaction" || right.kind === "interaction")
|
|
1519
|
+
return left.kind === right.kind;
|
|
1520
|
+
return left.kind === right.kind && left.valueKind === right.valueKind && inputValueKey(left.value) === inputValueKey(right.value) && (left.valueKind !== "board-id" || right.valueKind === "board-id" && left.boardId === right.boardId) && left.inputKey === right.inputKey;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1334
1523
|
export {
|
|
1524
|
+
runtimeFeatures,
|
|
1335
1525
|
AmbiguousTargetError,
|
|
1336
|
-
createGameInstance
|
|
1526
|
+
createGameInstance,
|
|
1527
|
+
isSameDropTarget,
|
|
1528
|
+
GESTURE_THRESHOLDS,
|
|
1529
|
+
createGestureRecognizer
|
|
1337
1530
|
};
|
|
1338
|
-
//# sourceMappingURL=chunk-
|
|
1531
|
+
//# sourceMappingURL=chunk-CSHKCPBY.js.map
|