Input.drag ​Contract 2.0.0 · package sha256
a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e· generated fromconfigurator-runtime.d.tsbyservices/onsite-scripter/scripts/build-contract-docs.mjs; edit the source, not this file.
Method of Input · stable · since 2.0.0 · called as session.input.drag
drag(query: Query, options: DragOptions): () => void;
Makes parts draggable. Lifecycle call: immediate. Each call adds a registration, and a press
uses the newest one whose query matches the part; the returned function or signal removes
it. Neither a new registration nor a removal ends a drag in progress, which completes under
the options it started with. During a drag: 'drag:start', 'drag:move', 'drag:end'; no 'click'
follows a drag that moved. A lost pointer capture ends it with reason 'cancelled'. A
transaction requested during a drag opens after 'drag:end'. Returns the unregister function.
Errors: throws HoloInputError on invalid options. A slow constrain records 'frame-budget'.
Through Session:
| Option | Type | Default | What it does |
|---|---|---|---|
commit |
'runtime' | 'app' |
'runtime' | 'runtime': at release the runtime writes the pose to the scene model (one recorded commit, actor 'shopper'), which enters the write queue then, behind any… |
constrain |
(move: DragMove, frame: Frame) => PoseInput | null |
undefined (the unit follows move.pose) |
Synchronous. |
on |
'floor' | Query | ((part: Part) => 'floor' | Query) |
— | The surface the proposed pose lies on; a function picks it per part at press time. |
signal |
AbortSignal |
undefined | Aborting removes this registration; a drag in progress completes. |
undo |
CommitOptions['undo'] |
'Move' | Undo label of a runtime commit, as CommitOptions.undo ('rebase' erases every earlier step). |
signal) ​This call is a creator (SignalOption.signal, the kinds of call).
A creator (
collectionfor a new name,materials.create,on,onFrame,beforeCommit,follow,input.drag,labs.lightLinking) given a signal already aborted returns at once, already ended: aCollectionorMaterialreadingdisposed: truethat holds no content and no live name, or a registration that never runs and whose disposer does nothing.It records no Problem for the abort and throws only what it would throw anyway, as the DOM's
addEventListenerwith an aborted signal adds nothing (spec section 6.5).
Imports: values (has, validate, the Holo*Error classes, the pure helpers) from @holostep-configurators/runtime-client, types from @holostep-configurators/runtime-client/contract, /math and /testing names from those entries; boot from the runtime module the root's loadRuntimeAtFloor resolves to. A type your page defines is your app's: declare it there, never import it from the package.
Compiled under the contract's strict settings (examples/declaration/11-Input.drag.ts):
import { has } from '@holostep-configurators/runtime-client';
import type { Pose, Ray, Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
// The app owns placement: the runtime shows the constrained pose, the store decides on release.
declare const planner: {
snap(pose: Pose, ray: Ray): Pose;
canDrop(node: string, pose: Pose): boolean;
};
// movePlaced returns false when the store keeps the node where it is (an equal sync)
declare const store: { movePlaced(node: string, pose: Pose): boolean };
declare const editing: AbortSignal; // aborts when editing ends
// commit: 'app' and constrain are experimental; this has() also brings input.revert
if (has(session, 'input.drag.commit.app') && session.supports('input.drag.constrain')) {
session.input.drag({ role: 'product' }, {
on: 'floor',
commit: 'app', // the runtime writes nothing at release
constrain: (move) => {
const p = planner.snap(move.pose, move.ray);
// one rotation: a Pose is not a PoseInput
return { position: p.position, quaternion: p.quaternion, scale: p.scale };
},
signal: editing,
});
// the page's signal, not editing: a drag in progress completes after the removal
session.on('drag:end', ({ part, pose, moved, reason }) => {
if (!moved || !part.node) return;
if (reason !== 'released' || !planner.canDrop(part.node, pose)) {
session.input.revert(part); // back to the scene model's pose
return;
}
// the store's sync writes the scene model; the held pose ends. An equal sync commits
// nothing and releases nothing, so revert when the store keeps the node where it is.
if (!store.movePlaced(part.node, pose)) session.input.revert(part);
}, { signal });
}
| Rule | Result |
|---|---|
| 1. Neutral name | pass: drag names no product |
| 2. A precedent | pass: Babylon.js PointerDragBehavior (startDrag, onDragObservable, validateDrag) (row G1); jQuery UI draggable (drag, revert) (row G1) |
| 3. Two apps, or labs | pass: 15 apps (ledger: app-04c2774145, app-37356bf09f, app-4762caacdc, app-fc07850558, app-fc306ec3dc; fleet cross-check: app-04c2774145, app-37356bf09f, app-4762caacdc, app-510d750508, app-59c5b5751e, app-b362a81c85, app-bcb7ef21da, app-c1384707fc and 7 more) |
| 4. The cheaper fix first | decided per need in Appendix B: rows G1, K47 at tier labs, stable (a member only where no rule, data, asset or app code serves the need) |