@weasel-js/labkit 0.7.2 → 1.0.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 +21 -0
- package/README.md +11 -3
- package/dist/_dts/{DrawCommand-CEvS5AdV.d.ts → DrawCommand-BwRCZYuo.d.ts} +106 -52
- package/dist/_dts/{useExperimentState-eSvpwV_P.d.ts → useExperimentState-CJn2hHzd.d.ts} +6 -4
- package/dist/{chunk-SSMHPMDV.js → chunk-53XSBIUK.js} +12 -11
- package/dist/chunk-53XSBIUK.js.map +1 -0
- package/dist/{chunk-BG6NLMOL.js → chunk-FP5LYDVX.js} +1229 -1227
- package/dist/chunk-FP5LYDVX.js.map +1 -0
- package/dist/{chunk-ERZQAU4N.js → chunk-HNXVLKBG.js} +3 -3
- package/dist/{chunk-ERZQAU4N.js.map → chunk-HNXVLKBG.js.map} +1 -1
- package/dist/{chunk-5XDFILHZ.js → chunk-XVBXYKFJ.js} +1675 -670
- package/dist/chunk-XVBXYKFJ.js.map +1 -0
- package/dist/fonts/inter-latin.woff2 +0 -0
- package/dist/fonts/oswald-latin-variable.woff2 +0 -0
- package/dist/index.d.ts +37 -13
- package/dist/index.js +776 -27
- package/dist/index.js.map +1 -1
- package/dist/passthrough/weasel-canvas.d.ts +1 -1
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +332 -189
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/state/index.d.ts +2 -2
- package/dist/state/index.js +2 -2
- package/dist/styles.css +229 -288
- package/dist/ui/layers/index.js +3 -3
- package/package.json +5 -6
- package/src/canvas/CanvasStack.less +1 -1
- package/src/controls/ControlPanel.less +12 -12
- package/src/dragdrop/DragGhost.less +2 -2
- package/src/dragdrop/Palette.less +6 -6
- package/src/index.ts +2 -0
- package/src/lab/Lab.test.tsx +20 -15
- package/src/lab/Lab.tsx +33 -32
- package/src/lab/LabContext.ts +3 -3
- package/src/lab/LabShell.less +14 -14
- package/src/lab/LabShell.test.tsx +7 -20
- package/src/lab/LabShell.tsx +22 -13
- package/src/lab/WorkspaceGrid.less +1 -1
- package/src/lab/WorkspaceGrid.stories.tsx +4 -4
- package/src/lab/index.ts +1 -1
- package/src/lab/useSystemMode.ts +30 -0
- package/src/layers/LayerList.less +9 -9
- package/src/primitives/FpsMeter.less +5 -5
- package/src/primitives/ScaleIndicator.less +7 -7
- package/src/primitives/Sidebar.less +12 -12
- package/src/primitives/StatusBar.less +10 -10
- package/src/primitives/Toolbar.less +16 -16
- package/src/state/store.test.ts +17 -9
- package/src/state/store.ts +13 -10
- package/src/state/types.ts +5 -2
- package/src/theme/Interstellar.stories.less +20 -20
- package/src/theme/Interstellar.stories.tsx +44 -59
- package/src/theme/base.less +29 -28
- package/src/theme/interstellar.test.ts +30 -0
- package/src/theme/interstellar.tokens.json +57 -0
- package/src/theme/interstellar.ts +9 -0
- package/src/ui/layers/LayerStack.less +21 -21
- package/src/ui/properties/CurveField.less +5 -5
- package/src/ui/properties/EffectCard.tsx +2 -2
- package/src/ui/properties/PropertyGroup.less +6 -6
- package/src/ui/properties/PropertyPanel.less +70 -70
- package/src/ui/properties/SpeechBalloonPanels.stories.tsx +1 -1
- package/src/ui/properties/storyLayouts.tsx +1 -1
- package/src/workspace/Workspace.less +14 -14
- package/src/workspace/Workspace.stories.tsx +2 -2
- package/src/workspace/Workspace.test.tsx +2 -2
- package/dist/chunk-5XDFILHZ.js.map +0 -1
- package/dist/chunk-BG6NLMOL.js.map +0 -1
- package/dist/chunk-SSMHPMDV.js.map +0 -1
- package/dist/theme-interstellar.css +0 -25
- package/dist/theme-light.css +0 -13
- package/src/fonts/oswald-latin-variable.woff2 +0 -0
- package/src/theme/interstellar.less +0 -34
- package/src/theme/light.less +0 -14
- package/src/theme/tokens.less +0 -85
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { Ref } from 'react';
|
|
3
|
-
import { N as Node, V as View, D as DrawCommand, S as Scene, B as Bounds, a as ViewportDims, P as PathDrawCommand } from '../_dts/DrawCommand-
|
|
3
|
+
import { N as Node, V as View, D as DrawCommand, S as Scene, B as Bounds, a as ViewportDims, P as PathDrawCommand } from '../_dts/DrawCommand-BwRCZYuo.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `renderSceneToCanvas` — substrate for detached, read-only scene views
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, buildSceneViewCommands, computeFitView2 as computeFitView, computeIndicatorCommand, renderSceneToCanvas } from '../chunk-
|
|
1
|
+
export { FALLBACK_FIT_VIEW, MinimapCanvas, SceneViewCanvas, buildSceneViewCommands, computeFitView2 as computeFitView, computeIndicatorCommand, renderSceneToCanvas } from '../chunk-XVBXYKFJ.js';
|
|
2
2
|
//# sourceMappingURL=weasel-canvas.js.map
|
|
3
3
|
//# sourceMappingURL=weasel-canvas.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { ReactNode, CSSProperties, ButtonHTMLAttributes, ReactElement, MutableRefObject, PointerEvent as PointerEvent$1, KeyboardEvent, RefCallback } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { V as View, D as DrawCommand, O as Op, b as NodeId, c as Path, S as Scene, H as History, B as Bounds } from '../_dts/DrawCommand-BwRCZYuo.js';
|
|
5
5
|
import { TextFieldProps, ValidationResult, CheckboxProps as CheckboxProps$1, SwitchProps as SwitchProps$1, TabProps as TabProps$1, TabListProps as TabListProps$1, TabPanelProps as TabPanelProps$1, TabsProps as TabsProps$1, RadioProps as RadioProps$1, RadioGroupProps as RadioGroupProps$1, NumberFieldProps as NumberFieldProps$1, SelectProps as SelectProps$1, ListBoxItemProps, ComboBoxProps as ComboBoxProps$1, SliderProps as SliderProps$1, ModalOverlayProps, DialogProps as DialogProps$1 } from 'react-aria-components';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1124,6 +1124,181 @@ interface PowerlineProps {
|
|
|
1124
1124
|
}
|
|
1125
1125
|
declare function Powerline({ segments, startCap, size, variant, depth, gap, className, ...rest }: PowerlineProps): react_jsx_runtime.JSX.Element;
|
|
1126
1126
|
|
|
1127
|
+
/**
|
|
1128
|
+
* Snapshot of modifier-key state at gesture dispatch.
|
|
1129
|
+
*
|
|
1130
|
+
* Lives in core rather than beside the gesture types that produce it because
|
|
1131
|
+
* `core/selection/chromeState.ts` reads it, and core may not import from
|
|
1132
|
+
* `interactions/`. Re-exported from `interactions/gestures/types.ts`, which
|
|
1133
|
+
* is still where gesture code names it.
|
|
1134
|
+
*/
|
|
1135
|
+
interface ModifierState {
|
|
1136
|
+
alt: boolean;
|
|
1137
|
+
shift: boolean;
|
|
1138
|
+
meta: boolean;
|
|
1139
|
+
ctrl: boolean;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/**
|
|
1143
|
+
* @experimental
|
|
1144
|
+
* Result of an affordance hit — what the region computed about itself.
|
|
1145
|
+
*
|
|
1146
|
+
* `initialScratch` is the payload: what the region already knows (which
|
|
1147
|
+
* corner, which target id) so the action that picks up the drag doesn't
|
|
1148
|
+
* re-derive it. `<SceneCanvas>` reads it out of the layer hit-test and packs
|
|
1149
|
+
* it into `AffordanceHit`, which flows to the matching action through
|
|
1150
|
+
* `InvocationCtx.drag.affordance`.
|
|
1151
|
+
*
|
|
1152
|
+
* This used to also carry a `drag: DragChannel` naming the handlers the
|
|
1153
|
+
* tool-routing dispatcher should wire up. Every implementation supplied a
|
|
1154
|
+
* no-op stub that claimed, because the real routing had already moved to
|
|
1155
|
+
* bindings; the field went with that dispatcher.
|
|
1156
|
+
*/
|
|
1157
|
+
interface AffordanceBinding<TScratch = unknown> {
|
|
1158
|
+
initialScratch?: TScratch;
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* What a **registered layer's** `hitTest` returns. Extends `AffordanceBinding`
|
|
1162
|
+
* so existing implementations keep typechecking; the added fields are how a
|
|
1163
|
+
* consumer's own chrome says the things kit chrome says through
|
|
1164
|
+
* `AffordanceRegion` — which cursor to show, and whether it owns the point
|
|
1165
|
+
* outright.
|
|
1166
|
+
*/
|
|
1167
|
+
interface LayerHit<TScratch = unknown> extends AffordanceBinding<TScratch> {
|
|
1168
|
+
/** CSS cursor while the pointer is over this hit. Reaches the hover-cursor
|
|
1169
|
+
* pump as `AffordanceHit.cursor`, the same path kit chrome uses. */
|
|
1170
|
+
cursor?: string;
|
|
1171
|
+
/** `'exclusive'` bars every binding whose target doesn't consult the
|
|
1172
|
+
* affordance. Omitted means `'shared'` — today's behavior. Same name and
|
|
1173
|
+
* meaning as `AffordanceHit.strength`, which it becomes. */
|
|
1174
|
+
strength?: 'exclusive' | 'shared';
|
|
1175
|
+
/** Which gestures an exclusive claim bars. Omitted bars all of them. */
|
|
1176
|
+
claimedKinds?: readonly ClaimableGesture[];
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Gesture kinds an affordance claim can bar, in the spec vocabulary bindings
|
|
1180
|
+
* are written in. `'pointer'` is one token because `pointerDown` / `click` /
|
|
1181
|
+
* `drag` are a single press protocol — at the event level the first two are
|
|
1182
|
+
* the same `kind: 'pointerdown'`, told apart only by `stage`.
|
|
1183
|
+
*/
|
|
1184
|
+
type ClaimableGesture = 'pointer' | 'doubleClick' | 'contextMenu' | 'longPress' | 'wheel';
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* Canvas size in CSS pixels — passed to `draw` for layers that anchor to
|
|
1188
|
+
* canvas edges (e.g. the debug overlay's layer-list panel). The GL backend
|
|
1189
|
+
* supplies it explicitly so layers don't have to know about DPR.
|
|
1190
|
+
*/
|
|
1191
|
+
interface Dims {
|
|
1192
|
+
width: number;
|
|
1193
|
+
height: number;
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* A single named render sub-layer within a canvas renderer.
|
|
1197
|
+
*
|
|
1198
|
+
* @template TData - The data object passed to each draw call.
|
|
1199
|
+
*/
|
|
1200
|
+
interface RenderLayer<TData> {
|
|
1201
|
+
/** Unique identifier used in visibility maps and ordering arrays. */
|
|
1202
|
+
id: string;
|
|
1203
|
+
/** Human-readable name for UI toggles. */
|
|
1204
|
+
label: string;
|
|
1205
|
+
/**
|
|
1206
|
+
* Emit a DrawCommand tree for the GL backend to dispatch.
|
|
1207
|
+
*
|
|
1208
|
+
* For world-space layers (the default), emit commands in WORLD COORDS —
|
|
1209
|
+
* `drawLayers` automatically wraps them in `{ kind: 'group', transform:
|
|
1210
|
+
* viewToMat3(view), ... }` before handing them to the renderer. Do NOT
|
|
1211
|
+
* apply the view transform yourself.
|
|
1212
|
+
*
|
|
1213
|
+
* For screen-space layers (`space: 'screen'`), emit commands in CSS-pixel
|
|
1214
|
+
* coords directly; `drawLayers` passes them through unchanged. If part
|
|
1215
|
+
* of a screen-space layer's output needs to track the view, wrap that
|
|
1216
|
+
* subset manually with `viewToMat3(view)`.
|
|
1217
|
+
*/
|
|
1218
|
+
draw: (data: TData, view: View, dims: Dims) => DrawCommand[];
|
|
1219
|
+
/**
|
|
1220
|
+
* Whether the layer is shown when no explicit visibility entry exists.
|
|
1221
|
+
* Defaults to `true` when absent.
|
|
1222
|
+
*/
|
|
1223
|
+
defaultVisible?: boolean;
|
|
1224
|
+
/**
|
|
1225
|
+
* When true, the layer is always drawn regardless of the visibility map.
|
|
1226
|
+
* Useful for layers that must never be hidden (e.g. base grid).
|
|
1227
|
+
*/
|
|
1228
|
+
alwaysOn?: boolean;
|
|
1229
|
+
/**
|
|
1230
|
+
* Coordinate space the layer draws in.
|
|
1231
|
+
*
|
|
1232
|
+
* - `'world'` (default): the layer's `draw` returns world-space commands;
|
|
1233
|
+
* `drawLayers` wraps them in a `kind: 'group'` with `viewToMat3(view)`
|
|
1234
|
+
* automatically.
|
|
1235
|
+
* - `'screen'`: the layer's `draw` returns screen-space (CSS-pixel)
|
|
1236
|
+
* commands; `drawLayers` passes them through unchanged. World-anchored
|
|
1237
|
+
* chrome inside a screen-space layer must call `worldToScreen` or wrap
|
|
1238
|
+
* the relevant subset with `viewToMat3(view)` manually.
|
|
1239
|
+
*/
|
|
1240
|
+
space?: 'world' | 'screen';
|
|
1241
|
+
/**
|
|
1242
|
+
* Optional hit-test for **consumer-attached** layers.
|
|
1243
|
+
*
|
|
1244
|
+
* Only layers registered through `CanvasExtensionApi.registerLayer` are
|
|
1245
|
+
* hit-tested: `hitTestExtras` walks them last-registered-first on
|
|
1246
|
+
* pointerdown, and `<SceneCanvas>` folds the result into its `affordanceAt`
|
|
1247
|
+
* thunk ahead of the kit's own selection chrome. First non-null result
|
|
1248
|
+
* wins; null means "I don't claim this hit, try the next layer."
|
|
1249
|
+
*
|
|
1250
|
+
* Layers that reach the draw stack some other way — a `Tool.overlay`, an
|
|
1251
|
+
* entry in the `layers` map — are painted but never hit-tested, so defining
|
|
1252
|
+
* `hitTest` on one has no effect. (The kit's own chrome doesn't need it: it
|
|
1253
|
+
* goes through `buildAffordanceAt`.)
|
|
1254
|
+
*
|
|
1255
|
+
* Coordinates are world-space. The `data` arg is the layer's
|
|
1256
|
+
* configured data slot (same as `draw`); `view` and `dims` mirror
|
|
1257
|
+
* `draw`'s arguments.
|
|
1258
|
+
*/
|
|
1259
|
+
hitTest?: (worldX: number, worldY: number, data: TData, view: View, dims: Dims,
|
|
1260
|
+
/** Chrome-caps visibility predicate. When supplied, the layer must
|
|
1261
|
+
* not return a hit from any chrome element whose id reports
|
|
1262
|
+
* `false`. Absent → every element is hittable. */
|
|
1263
|
+
isVisible?: (id: string) => boolean) => LayerHit | null;
|
|
1264
|
+
/**
|
|
1265
|
+
* Called on every pointermove when no gesture is currently captured.
|
|
1266
|
+
* Lets layers (e.g. HUD widgets) track hover state without participating
|
|
1267
|
+
* in the drag pipeline. Coords are world-space; the layer is responsible
|
|
1268
|
+
* for any further conversion (e.g. world→screen for screen-space layers)
|
|
1269
|
+
* and for its own throttling.
|
|
1270
|
+
*/
|
|
1271
|
+
onUncapturedMove?: (worldX: number, worldY: number, evt: PointerEvent, view: View, dims: Dims) => void;
|
|
1272
|
+
/**
|
|
1273
|
+
* Called when the cursor leaves the canvas element. Lets layers clear
|
|
1274
|
+
* any hover state they're holding.
|
|
1275
|
+
*/
|
|
1276
|
+
onUncapturedLeave?: () => void;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
/**
|
|
1280
|
+
* Facts about the device the canvas is running on.
|
|
1281
|
+
*
|
|
1282
|
+
* One object, recomputed when the underlying media queries change, read by
|
|
1283
|
+
* two consumers: the chrome-caps rule layer (via `RuleCtx.device`) and the
|
|
1284
|
+
* handle-sizing constants (via `targetScale`).
|
|
1285
|
+
*
|
|
1286
|
+
* Deliberately NOT a form-factor concept. There is no `isPhone` here and
|
|
1287
|
+
* there should never be one: chrome layout is the consuming app's decision.
|
|
1288
|
+
* The kit's job is to stop assuming a mouse.
|
|
1289
|
+
*/
|
|
1290
|
+
interface DeviceProfile {
|
|
1291
|
+
/** `matchMedia('(pointer: coarse)')` — the primary pointer is imprecise. */
|
|
1292
|
+
readonly coarsePointer: boolean;
|
|
1293
|
+
/** `matchMedia('(hover: hover)')` — the primary pointer can hover. */
|
|
1294
|
+
readonly canHover: boolean;
|
|
1295
|
+
/** Live device pixel ratio. */
|
|
1296
|
+
readonly dpr: number;
|
|
1297
|
+
/** Multiplier for handle sizes and hit radii. Derived from
|
|
1298
|
+
* `coarsePointer` unless explicitly overridden. */
|
|
1299
|
+
readonly targetScale: number;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1127
1302
|
type ContainerBounds = {
|
|
1128
1303
|
x: number;
|
|
1129
1304
|
y: number;
|
|
@@ -1309,13 +1484,6 @@ interface InsertAdapter<TNode extends {
|
|
|
1309
1484
|
getSelection(): string[];
|
|
1310
1485
|
}
|
|
1311
1486
|
|
|
1312
|
-
/** Snapshot of modifier-key state at gesture dispatch. */
|
|
1313
|
-
interface ModifierState {
|
|
1314
|
-
alt: boolean;
|
|
1315
|
-
shift: boolean;
|
|
1316
|
-
meta: boolean;
|
|
1317
|
-
ctrl: boolean;
|
|
1318
|
-
}
|
|
1319
1487
|
/** Pointer position in both world and client coords. */
|
|
1320
1488
|
interface PointerState {
|
|
1321
1489
|
worldX: number;
|
|
@@ -1430,118 +1598,6 @@ interface PointSnapBehavior<TPose extends ResizePose> {
|
|
|
1430
1598
|
onMove(ctx: PointSnapContext<TPose>): PointSnapResult | null | undefined;
|
|
1431
1599
|
}
|
|
1432
1600
|
|
|
1433
|
-
/**
|
|
1434
|
-
* @experimental
|
|
1435
|
-
* Result of an affordance hit — what the region computed about itself.
|
|
1436
|
-
*
|
|
1437
|
-
* `initialScratch` is the payload: what the region already knows (which
|
|
1438
|
-
* corner, which target id) so the action that picks up the drag doesn't
|
|
1439
|
-
* re-derive it. `<SceneCanvas>` reads it out of the layer hit-test and packs
|
|
1440
|
-
* it into `AffordanceHit`, which flows to the matching action through
|
|
1441
|
-
* `InvocationCtx.drag.affordance`.
|
|
1442
|
-
*
|
|
1443
|
-
* This used to also carry a `drag: DragChannel` naming the handlers the
|
|
1444
|
-
* tool-routing dispatcher should wire up. Every implementation supplied a
|
|
1445
|
-
* no-op stub that claimed, because the real routing had already moved to
|
|
1446
|
-
* bindings; the field went with that dispatcher.
|
|
1447
|
-
*/
|
|
1448
|
-
interface AffordanceBinding<TScratch = unknown> {
|
|
1449
|
-
initialScratch?: TScratch;
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
/**
|
|
1453
|
-
* Canvas size in CSS pixels — passed to `draw` for layers that anchor to
|
|
1454
|
-
* canvas edges (e.g. the debug overlay's layer-list panel). The GL backend
|
|
1455
|
-
* supplies it explicitly so layers don't have to know about DPR.
|
|
1456
|
-
*/
|
|
1457
|
-
interface Dims {
|
|
1458
|
-
width: number;
|
|
1459
|
-
height: number;
|
|
1460
|
-
}
|
|
1461
|
-
/**
|
|
1462
|
-
* A single named render sub-layer within a canvas renderer.
|
|
1463
|
-
*
|
|
1464
|
-
* @template TData - The data object passed to each draw call.
|
|
1465
|
-
*/
|
|
1466
|
-
interface RenderLayer<TData> {
|
|
1467
|
-
/** Unique identifier used in visibility maps and ordering arrays. */
|
|
1468
|
-
id: string;
|
|
1469
|
-
/** Human-readable name for UI toggles. */
|
|
1470
|
-
label: string;
|
|
1471
|
-
/**
|
|
1472
|
-
* Emit a DrawCommand tree for the GL backend to dispatch.
|
|
1473
|
-
*
|
|
1474
|
-
* For world-space layers (the default), emit commands in WORLD COORDS —
|
|
1475
|
-
* `drawLayers` automatically wraps them in `{ kind: 'group', transform:
|
|
1476
|
-
* viewToMat3(view), ... }` before handing them to the renderer. Do NOT
|
|
1477
|
-
* apply the view transform yourself.
|
|
1478
|
-
*
|
|
1479
|
-
* For screen-space layers (`space: 'screen'`), emit commands in CSS-pixel
|
|
1480
|
-
* coords directly; `drawLayers` passes them through unchanged. If part
|
|
1481
|
-
* of a screen-space layer's output needs to track the view, wrap that
|
|
1482
|
-
* subset manually with `viewToMat3(view)`.
|
|
1483
|
-
*/
|
|
1484
|
-
draw: (data: TData, view: View, dims: Dims) => DrawCommand[];
|
|
1485
|
-
/**
|
|
1486
|
-
* Whether the layer is shown when no explicit visibility entry exists.
|
|
1487
|
-
* Defaults to `true` when absent.
|
|
1488
|
-
*/
|
|
1489
|
-
defaultVisible?: boolean;
|
|
1490
|
-
/**
|
|
1491
|
-
* When true, the layer is always drawn regardless of the visibility map.
|
|
1492
|
-
* Useful for layers that must never be hidden (e.g. base grid).
|
|
1493
|
-
*/
|
|
1494
|
-
alwaysOn?: boolean;
|
|
1495
|
-
/**
|
|
1496
|
-
* Coordinate space the layer draws in.
|
|
1497
|
-
*
|
|
1498
|
-
* - `'world'` (default): the layer's `draw` returns world-space commands;
|
|
1499
|
-
* `drawLayers` wraps them in a `kind: 'group'` with `viewToMat3(view)`
|
|
1500
|
-
* automatically.
|
|
1501
|
-
* - `'screen'`: the layer's `draw` returns screen-space (CSS-pixel)
|
|
1502
|
-
* commands; `drawLayers` passes them through unchanged. World-anchored
|
|
1503
|
-
* chrome inside a screen-space layer must call `worldToScreen` or wrap
|
|
1504
|
-
* the relevant subset with `viewToMat3(view)` manually.
|
|
1505
|
-
*/
|
|
1506
|
-
space?: 'world' | 'screen';
|
|
1507
|
-
/**
|
|
1508
|
-
* Optional hit-test for **consumer-attached** layers.
|
|
1509
|
-
*
|
|
1510
|
-
* Only layers registered through `CanvasExtensionApi.registerLayer` are
|
|
1511
|
-
* hit-tested: `hitTestExtras` walks them last-registered-first on
|
|
1512
|
-
* pointerdown, and `<SceneCanvas>` folds the result into its `affordanceAt`
|
|
1513
|
-
* thunk ahead of the kit's own selection chrome. First non-null result
|
|
1514
|
-
* wins; null means "I don't claim this hit, try the next layer."
|
|
1515
|
-
*
|
|
1516
|
-
* Layers that reach the draw stack some other way — a `Tool.overlay`, an
|
|
1517
|
-
* entry in the `layers` map — are painted but never hit-tested, so defining
|
|
1518
|
-
* `hitTest` on one has no effect. (The kit's own chrome doesn't need it: it
|
|
1519
|
-
* goes through `buildAffordanceAt`.)
|
|
1520
|
-
*
|
|
1521
|
-
* Coordinates are world-space. The `data` arg is the layer's
|
|
1522
|
-
* configured data slot (same as `draw`); `view` and `dims` mirror
|
|
1523
|
-
* `draw`'s arguments.
|
|
1524
|
-
*/
|
|
1525
|
-
hitTest?: (worldX: number, worldY: number, data: TData, view: View, dims: Dims,
|
|
1526
|
-
/** Chrome-caps visibility predicate. When supplied, the layer must
|
|
1527
|
-
* not return a hit from any chrome element whose id reports
|
|
1528
|
-
* `false`. Absent → every element is hittable. */
|
|
1529
|
-
isVisible?: (id: string) => boolean) => AffordanceBinding | null;
|
|
1530
|
-
/**
|
|
1531
|
-
* Called on every pointermove when no gesture is currently captured.
|
|
1532
|
-
* Lets layers (e.g. HUD widgets) track hover state without participating
|
|
1533
|
-
* in the drag pipeline. Coords are world-space; the layer is responsible
|
|
1534
|
-
* for any further conversion (e.g. world→screen for screen-space layers)
|
|
1535
|
-
* and for its own throttling.
|
|
1536
|
-
*/
|
|
1537
|
-
onUncapturedMove?: (worldX: number, worldY: number, evt: PointerEvent, view: View, dims: Dims) => void;
|
|
1538
|
-
/**
|
|
1539
|
-
* Called when the cursor leaves the canvas element. Lets layers clear
|
|
1540
|
-
* any hover state they're holding.
|
|
1541
|
-
*/
|
|
1542
|
-
onUncapturedLeave?: () => void;
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
1601
|
/** The full vocabulary of capability tags shipped in the default preset.
|
|
1546
1602
|
* Apps and other consumers can add their own tags; this list is what
|
|
1547
1603
|
* `weasel-modes` itself uses. */
|
|
@@ -1625,6 +1681,13 @@ interface RuleCtx {
|
|
|
1625
1681
|
* with nothing being edited should draw no anchors. Absent is treated
|
|
1626
1682
|
* as false. */
|
|
1627
1683
|
readonly editingAnchors?: boolean;
|
|
1684
|
+
/** Device facts — pointer coarseness, hover capability, density.
|
|
1685
|
+
*
|
|
1686
|
+
* Absent (legacy ctx builders) is treated as
|
|
1687
|
+
* {@link DEFAULT_DEVICE_PROFILE}: a fine pointer that can hover, at
|
|
1688
|
+
* density 1. That is what the kit assumed before this field existed, so
|
|
1689
|
+
* an absent profile is behavior-preserving by construction. */
|
|
1690
|
+
readonly device?: DeviceProfile;
|
|
1628
1691
|
}
|
|
1629
1692
|
|
|
1630
1693
|
/**
|
|
@@ -1661,6 +1724,12 @@ interface Selector {
|
|
|
1661
1724
|
* (resizable), so `{ resizable: true }` passes for legacy ctx builders
|
|
1662
1725
|
* that don't compute it. */
|
|
1663
1726
|
resizable?: boolean;
|
|
1727
|
+
/** Matches `ctx.device.coarsePointer` — the primary pointer is imprecise
|
|
1728
|
+
* (touch, most styluses). Absent device is treated as `false`. */
|
|
1729
|
+
coarsePointer?: boolean;
|
|
1730
|
+
/** Matches `ctx.device.canHover` — the primary pointer can hover. Absent
|
|
1731
|
+
* device is treated as `true`. */
|
|
1732
|
+
canHover?: boolean;
|
|
1664
1733
|
}
|
|
1665
1734
|
/**
|
|
1666
1735
|
* Composable visibility/eligibility rule. Trees of `all`/`any`/`not` nodes
|
|
@@ -1836,6 +1905,7 @@ interface KeyHeldSpec {
|
|
|
1836
1905
|
interface WheelSpec {
|
|
1837
1906
|
kind: 'wheel';
|
|
1838
1907
|
direction?: 'up' | 'down' | '*';
|
|
1908
|
+
target?: TargetSpec;
|
|
1839
1909
|
mods?: ModSpec;
|
|
1840
1910
|
phase?: PhaseSpec;
|
|
1841
1911
|
}
|
|
@@ -1893,6 +1963,24 @@ interface PointerDownSpec {
|
|
|
1893
1963
|
mods?: ModSpec;
|
|
1894
1964
|
phase?: PhaseSpec;
|
|
1895
1965
|
}
|
|
1966
|
+
/**
|
|
1967
|
+
* Press held past the long-press threshold without crossing the drag
|
|
1968
|
+
* threshold. Synthesized by `useGestureDispatcher` from the pointer stream.
|
|
1969
|
+
*
|
|
1970
|
+
* Fires for `touch` and `pen` pointers only. A mouse held still for half a
|
|
1971
|
+
* second is an ordinary slow click, and firing on it would produce a context
|
|
1972
|
+
* menu nobody asked for.
|
|
1973
|
+
*
|
|
1974
|
+
* When a long-press matches no binding, the dispatcher re-dispatches it as a
|
|
1975
|
+
* `contextmenu` event — so `contextMenu` bindings work under a finger with no
|
|
1976
|
+
* consumer changes, while `longPress` stays independently bindable.
|
|
1977
|
+
*/
|
|
1978
|
+
interface LongPressSpec {
|
|
1979
|
+
kind: 'longPress';
|
|
1980
|
+
target?: TargetSpec;
|
|
1981
|
+
mods?: ModSpec;
|
|
1982
|
+
phase?: PhaseSpec;
|
|
1983
|
+
}
|
|
1896
1984
|
/** Multi-touch gesture. `fingers` is the required touch count. */
|
|
1897
1985
|
interface MultiTouchSpec {
|
|
1898
1986
|
kind: 'multiTouch';
|
|
@@ -1927,9 +2015,9 @@ interface PasteSpec {
|
|
|
1927
2015
|
phase?: PhaseSpec;
|
|
1928
2016
|
}
|
|
1929
2017
|
/** The full union of supported gesture spec kinds. New invocation forms
|
|
1930
|
-
* (
|
|
2018
|
+
* (two-stage, modal-dialog) extend this union without touching
|
|
1931
2019
|
* the `Action` type. */
|
|
1932
|
-
type GestureSpec = KeySpec | KeyHeldSpec | WheelSpec | ClickSpec | DoubleClickSpec | ContextMenuSpec | DragSpec | PointerDownSpec | MultiTouchSpec | MultiTouchTapSpec | DropSpec | PasteSpec;
|
|
2020
|
+
type GestureSpec = KeySpec | KeyHeldSpec | WheelSpec | ClickSpec | DoubleClickSpec | ContextMenuSpec | DragSpec | PointerDownSpec | LongPressSpec | MultiTouchSpec | MultiTouchTapSpec | DropSpec | PasteSpec;
|
|
1933
2021
|
|
|
1934
2022
|
/** A 2D point in either world or screen coordinates. */
|
|
1935
2023
|
interface Point2 {
|
|
@@ -1960,6 +2048,15 @@ interface Point2 {
|
|
|
1960
2048
|
interface AffordanceHit {
|
|
1961
2049
|
/** Discriminator string, e.g. `'handle:bottom-right'`. */
|
|
1962
2050
|
kind: string;
|
|
2051
|
+
/** Id of whatever produced this hit — a kit affordance's `id`, or the
|
|
2052
|
+
* registered layer's id. Read only by the dispatcher's dead-claim warning today. */
|
|
2053
|
+
owner?: string;
|
|
2054
|
+
/** `'exclusive'` means no binding may act on this point unless its target
|
|
2055
|
+
* consults the affordance. `'shared'` (the default) competes on scope and
|
|
2056
|
+
* specificity as bindings always have. */
|
|
2057
|
+
strength?: 'exclusive' | 'shared';
|
|
2058
|
+
/** Which gestures an exclusive claim bars. Omitted bars all of them. */
|
|
2059
|
+
claimedKinds?: readonly ClaimableGesture[];
|
|
1963
2060
|
/** World-space fixed/pivot point. For resize: opposite corner. For rotate: pivot. */
|
|
1964
2061
|
fixedPoint?: {
|
|
1965
2062
|
x: number;
|
|
@@ -2287,6 +2384,50 @@ interface OngoingInvoker {
|
|
|
2287
2384
|
* the `Action` type. */
|
|
2288
2385
|
type Invoker = ImmediateInvoker | OngoingInvoker;
|
|
2289
2386
|
|
|
2387
|
+
/**
|
|
2388
|
+
* GestureBinding — connects a GestureSpec to an Action id (with per-binding
|
|
2389
|
+
* options). Tools own arrays of these on their `bindings` field; ambient
|
|
2390
|
+
* gesture-bindings are registered globally.
|
|
2391
|
+
*
|
|
2392
|
+
* See `docs/superpowers/specs/2026-05-16-registry-unification-design.md`.
|
|
2393
|
+
*/
|
|
2394
|
+
|
|
2395
|
+
interface GestureBinding {
|
|
2396
|
+
spec: GestureSpec;
|
|
2397
|
+
actionId: string;
|
|
2398
|
+
opts?: BindingOpts;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
/**
|
|
2402
|
+
* Pose composition for hierarchical scene graphs.
|
|
2403
|
+
*
|
|
2404
|
+
* As of the nesting change, `getPose(id)` on adapters returns the
|
|
2405
|
+
* **local** pose — relative to the object's direct parent. Anything in the
|
|
2406
|
+
* kit that needs to draw, hit-test, snap, or otherwise reason about world
|
|
2407
|
+
* coordinates routes through `composeWorldPose`, which walks the parent
|
|
2408
|
+
* chain and folds local poses together via a consumer-supplied `compose`.
|
|
2409
|
+
*
|
|
2410
|
+
* Pose shape is generic, so the compose strategy is too. For the common
|
|
2411
|
+
* `{x, y, width, height}` axis-aligned rect, use `composeRectPose` —
|
|
2412
|
+
* translation only, child dimensions preserved. Custom pose shapes (paths,
|
|
2413
|
+
* matrix transforms) supply their own.
|
|
2414
|
+
*
|
|
2415
|
+
* The inverse — `rebaseLocalPose` — converts a world-space pose into a
|
|
2416
|
+
* local pose under a target parent. Used when reparenting so the visual
|
|
2417
|
+
* world position of a child is preserved across the parent change.
|
|
2418
|
+
*/
|
|
2419
|
+
/** Re-exported; the declaration lives in `core/scene/types.ts`, which names
|
|
2420
|
+
* it and may not import from features. */
|
|
2421
|
+
|
|
2422
|
+
/** Consumer's pose-composition strategy for hierarchical scenes. `compose`
|
|
2423
|
+
* folds a child's pose (in parent's frame) up to the next frame; `decompose`
|
|
2424
|
+
* is its inverse. Default is IDENTITY — an absolute-pose scene where every
|
|
2425
|
+
* node already stores world coords (parent is grouping-only, no transform). */
|
|
2426
|
+
interface PoseComposition<TPose> {
|
|
2427
|
+
compose: (parent: TPose, child: TPose) => TPose;
|
|
2428
|
+
decompose: (parent: TPose, world: TPose) => TPose;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2290
2431
|
/** Boolean op identifiers — five Pathfinder primaries plus Crop. */
|
|
2291
2432
|
type BooleanOp = 'union' | 'intersect' | 'subtract' | 'exclude' | 'divide' | 'crop';
|
|
2292
2433
|
/**
|
|
@@ -2576,6 +2717,20 @@ interface SliceDep {
|
|
|
2576
2717
|
commit(a: Point2, b: Point2): void;
|
|
2577
2718
|
}
|
|
2578
2719
|
|
|
2720
|
+
/**
|
|
2721
|
+
* Clipboard dep — the imperative surface `useClipboardOps` returns.
|
|
2722
|
+
*
|
|
2723
|
+
* Consumers publish their live clipboard through `useDepSource('clipboard',
|
|
2724
|
+
* …)` from inside the `<DepRegistryProvider>` (i.e. under `<SceneCanvas>`).
|
|
2725
|
+
* The kit deliberately does not build one for them: `useClipboardOps` needs
|
|
2726
|
+
* an adapter and a selection reader that only the consumer can supply.
|
|
2727
|
+
*/
|
|
2728
|
+
interface ClipboardDep {
|
|
2729
|
+
copy(): void;
|
|
2730
|
+
paste(): void;
|
|
2731
|
+
isEmpty(): boolean;
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2579
2734
|
/**
|
|
2580
2735
|
* Bridges arbitrary `TPose` shapes into the resize hook's bounds-driven math.
|
|
2581
2736
|
* The hook reads bounds via `getBounds`, runs anchor-relative math on those
|
|
@@ -3147,6 +3302,15 @@ interface DepSchema {
|
|
|
3147
3302
|
* Optional: when absent, `sliceAction` is a no-op.
|
|
3148
3303
|
*/
|
|
3149
3304
|
slice?: SliceDep;
|
|
3305
|
+
/**
|
|
3306
|
+
* Clipboard dep — the imperative surface `useClipboardOps` returns.
|
|
3307
|
+
*
|
|
3308
|
+
* Published by the consumer (`useDepSource('clipboard', …)` from under
|
|
3309
|
+
* `<SceneCanvas>`), because `useClipboardOps` needs an adapter and a
|
|
3310
|
+
* selection reader only the consumer has. Feeds `clipboard.copy` /
|
|
3311
|
+
* `clipboard.cut`; both no-op when the dep is absent.
|
|
3312
|
+
*/
|
|
3313
|
+
clipboard?: ClipboardDep;
|
|
3150
3314
|
/**
|
|
3151
3315
|
* Optional consumer commit hook. When present, `moveAction` (and other
|
|
3152
3316
|
* default actions) submit their committed ops through it instead of
|
|
@@ -3196,20 +3360,6 @@ interface DepSchema {
|
|
|
3196
3360
|
*/
|
|
3197
3361
|
type DepName = keyof DepSchema;
|
|
3198
3362
|
|
|
3199
|
-
/**
|
|
3200
|
-
* GestureBinding — connects a GestureSpec to an Action id (with per-binding
|
|
3201
|
-
* options). Tools own arrays of these on their `bindings` field; ambient
|
|
3202
|
-
* gesture-bindings are registered globally.
|
|
3203
|
-
*
|
|
3204
|
-
* See `docs/superpowers/specs/2026-05-16-registry-unification-design.md`.
|
|
3205
|
-
*/
|
|
3206
|
-
|
|
3207
|
-
interface GestureBinding {
|
|
3208
|
-
spec: GestureSpec;
|
|
3209
|
-
actionId: string;
|
|
3210
|
-
opts?: BindingOpts;
|
|
3211
|
-
}
|
|
3212
|
-
|
|
3213
3363
|
type HandleKind = 'corner' | 'rotation' | 'anchor';
|
|
3214
3364
|
type HitShape = {
|
|
3215
3365
|
kind: 'rect';
|
|
@@ -3254,6 +3404,38 @@ interface DebugSink {
|
|
|
3254
3404
|
clearSnap(): void;
|
|
3255
3405
|
}
|
|
3256
3406
|
|
|
3407
|
+
/**
|
|
3408
|
+
* When an entry's bindings are live. A set, not one value: the hand tool is
|
|
3409
|
+
* palette-selectable AND engaged by holding space, and both hold at once.
|
|
3410
|
+
*/
|
|
3411
|
+
interface Eligibility {
|
|
3412
|
+
/** Selectable as the focused entry — exclusive, one at a time. */
|
|
3413
|
+
focus?: boolean;
|
|
3414
|
+
/** Also live while this key is held. */
|
|
3415
|
+
offhand?: HotkeyTrigger;
|
|
3416
|
+
/** Live regardless of what is focused. */
|
|
3417
|
+
always?: boolean;
|
|
3418
|
+
/** Live only for input this entry's own affordances produced. */
|
|
3419
|
+
claimed?: boolean;
|
|
3420
|
+
/** Modality filter, applied wherever it would otherwise be live. */
|
|
3421
|
+
capabilities?: CapabilityTag[];
|
|
3422
|
+
}
|
|
3423
|
+
/**
|
|
3424
|
+
* A registry entry: what it contributes, and when it is eligible. Every role
|
|
3425
|
+
* is optional and independent — an entry that only routes input declares only
|
|
3426
|
+
* `bindings` and `actions`.
|
|
3427
|
+
*/
|
|
3428
|
+
interface Contribution {
|
|
3429
|
+
id: string;
|
|
3430
|
+
eligibility: Eligibility;
|
|
3431
|
+
bindings?: GestureBinding[];
|
|
3432
|
+
actions?: Action[];
|
|
3433
|
+
overlay?: RenderLayer<unknown>;
|
|
3434
|
+
presentation?: ToolPresentation;
|
|
3435
|
+
/** Reflection escape hatch — the authored form, when there was one. */
|
|
3436
|
+
def?: unknown;
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3257
3439
|
/** Modifier-key snapshot at event dispatch time. `space` is included
|
|
3258
3440
|
* because tools commonly use space as a hotkey-slot trigger and may
|
|
3259
3441
|
* also want to read it as a flag mid-gesture. */
|
|
@@ -3303,6 +3485,10 @@ interface ToolCtx<TScratch = unknown> {
|
|
|
3303
3485
|
debug?: DebugSink;
|
|
3304
3486
|
scratch: TScratch;
|
|
3305
3487
|
}
|
|
3488
|
+
/** Hotkey-slot trigger key. The slot is engaged while this key is held —
|
|
3489
|
+
* hence "hotkey": active as long as the key is hot. `null` (or omitted)
|
|
3490
|
+
* means the tool is not eligible for the hotkey slot. */
|
|
3491
|
+
type HotkeyTrigger = 'space' | 'alt' | 'ctrl' | 'meta' | 'shift';
|
|
3306
3492
|
/** World-space AABB shape used by `previewBounds`. Alias of the kit-wide
|
|
3307
3493
|
* `Bounds` type — the optional `rotation` field carries through so a tool
|
|
3308
3494
|
* can report an oriented preview rect (e.g. mid-rotate). */
|
|
@@ -3311,8 +3497,8 @@ type ToolBounds = Bounds;
|
|
|
3311
3497
|
* tool — consumers that render a palette (`<ToolPalette>`) read these
|
|
3312
3498
|
* fields to display the tool; consumers that don't can ignore them.
|
|
3313
3499
|
*
|
|
3314
|
-
* Note: cursor is NOT here.
|
|
3315
|
-
* already plumbed through `<Canvas>` to `style.cursor` on the host. */
|
|
3500
|
+
* Note: cursor is NOT here. `Tool.cursor` (inherited from `Contribution`)
|
|
3501
|
+
* is already plumbed through `<Canvas>` to `style.cursor` on the host. */
|
|
3316
3502
|
interface ToolPresentation<TScratch = unknown> {
|
|
3317
3503
|
/** Human-readable label, distinct from the `id`. Falls back to `id`. */
|
|
3318
3504
|
label?: string;
|
|
@@ -3327,34 +3513,13 @@ interface ToolPresentation<TScratch = unknown> {
|
|
|
3327
3513
|
* derives one from `Tool.keybinding` via its own formatter. */
|
|
3328
3514
|
shortcut?: string;
|
|
3329
3515
|
}
|
|
3330
|
-
/**
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
* strings — apps can define their own. Untagged tools are treated as
|
|
3338
|
-
* ineligible by all modes except those whose `allows` list includes
|
|
3339
|
-
* every implicit-or-declared tag (i.e. `normal` in the default preset).
|
|
3340
|
-
*/
|
|
3341
|
-
capabilities?: CapabilityTag[];
|
|
3342
|
-
/**
|
|
3343
|
-
* Actions this tool owns and needs registered while it is in the tools
|
|
3344
|
-
* registry — e.g. polygon's `polygon.adjustSides`, which its own bindings
|
|
3345
|
-
* reference by id.
|
|
3346
|
-
*
|
|
3347
|
-
* Declared here rather than registered by the hook with `useAction`,
|
|
3348
|
-
* because tool hooks run wherever the consumer calls them — for
|
|
3349
|
-
* `<SceneCanvas>` that is ABOVE `<ActionsProviderIfRoot>`, where
|
|
3350
|
-
* `useActionsRegistry()` returns null and `useAction` silently no-ops. The
|
|
3351
|
-
* result was a binding pointing at an action id nothing had registered, so
|
|
3352
|
-
* the gesture fell through to whatever matched next (polygon's
|
|
3353
|
-
* wheel/arrow-key side adjustment did nothing and `nudge.*` moved the
|
|
3354
|
-
* selection instead). `<ToolActionsMounter>` registers these from inside
|
|
3355
|
-
* the provider.
|
|
3356
|
-
*/
|
|
3357
|
-
actions?: Action[];
|
|
3516
|
+
/**
|
|
3517
|
+
* The focus-declaring case of a `Contribution`: a mode the user switches
|
|
3518
|
+
* into, plus the hooks that only make sense for one (`initScratch`,
|
|
3519
|
+
* activate/deactivate, live preview, `cursor`). Everything else — bindings,
|
|
3520
|
+
* actions, overlay, presentation — is inherited.
|
|
3521
|
+
*/
|
|
3522
|
+
interface Tool<TScratch = unknown> extends Contribution {
|
|
3358
3523
|
/** Optional caller-supplied key. Most built-in tools have their activation
|
|
3359
3524
|
* key declared in `BUILTIN_SELECT_KEYS` in `useKeybindings.ts`; this field
|
|
3360
3525
|
* is for tools that want their activation key to be configurable by the
|
|
@@ -3364,11 +3529,9 @@ interface Tool<TScratch = unknown> {
|
|
|
3364
3529
|
* the invoker knows which tool to switch to). */
|
|
3365
3530
|
keybinding?: ToolKeybinding;
|
|
3366
3531
|
initScratch?: () => TScratch;
|
|
3532
|
+
cursor?: string | ((ctx: ToolCtx<TScratch>) => string);
|
|
3367
3533
|
onActivate?: (ctx: ToolCtx<TScratch>) => void;
|
|
3368
3534
|
onDeactivate?: (ctx: ToolCtx<TScratch>) => void;
|
|
3369
|
-
cursor?: string | ((ctx: ToolCtx<TScratch>) => string);
|
|
3370
|
-
/** Presentation metadata for tool palettes. See `ToolPresentation`. */
|
|
3371
|
-
presentation?: ToolPresentation<TScratch>;
|
|
3372
3535
|
/** Returns the in-flight preview pose for `id` if this tool is mid-gesture
|
|
3373
3536
|
* on it; otherwise `null`. Lets `Canvas.helpersRef.getEffectivePose`
|
|
3374
3537
|
* reflect live gesture state without reaching into hook internals. The
|
|
@@ -3386,26 +3549,6 @@ interface Tool<TScratch = unknown> {
|
|
|
3386
3549
|
* consults this alongside `previewPose` to avoid double-rendering. Returns
|
|
3387
3550
|
* `null` when no gesture is in flight. */
|
|
3388
3551
|
previewIds?: () => Iterable<string> | null;
|
|
3389
|
-
/** Optional overlay layer rendered on top of the scene/chrome whenever
|
|
3390
|
-
* this tool is in any active slot (active, hotkey, or ambient).
|
|
3391
|
-
* The layer's `draw` function reads from this tool's scratch via React
|
|
3392
|
-
* closure (re-evaluated each render). Return early from `draw` to render
|
|
3393
|
-
* nothing — typically gated on a scratch field like
|
|
3394
|
-
* `if (!scratch.overlay) return`. */
|
|
3395
|
-
overlay?: RenderLayer<unknown>;
|
|
3396
|
-
/** Declarative gesture bindings — the tool's entire input surface. The
|
|
3397
|
-
* gesture dispatcher consults these at active scope while this tool is
|
|
3398
|
-
* active, and at hotkey scope while it is held. See
|
|
3399
|
-
* `docs/superpowers/specs/2026-05-16-registry-unification-design.md`. */
|
|
3400
|
-
bindings?: GestureBinding[];
|
|
3401
|
-
/** Reflection escape hatch: when this `Tool` was produced by `defineTool`,
|
|
3402
|
-
* the source `ToolDef` is attached here so introspection consumers
|
|
3403
|
-
* (`buildRouteRegistry`, `findConflicts`, the toolkit-builder UI, the
|
|
3404
|
-
* reflection demo) can read the authored form — `hookName` in particular,
|
|
3405
|
-
* which the runtime `Tool` doesn't carry. Tools constructed without
|
|
3406
|
-
* `defineTool` may leave this undefined. Typed as `unknown` to keep this
|
|
3407
|
-
* file from importing the routing types — consumers cast at the use site. */
|
|
3408
|
-
def?: unknown;
|
|
3409
3552
|
}
|
|
3410
3553
|
/** Internal alias for "a Tool of any scratch type" — used in registries and
|
|
3411
3554
|
* dispatchers that hold tools of heterogeneous scratch shapes. `any` is
|