@michaelyagi/shoji 0.1.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/esm/core/EventBus.d.ts +16 -0
  4. package/dist/esm/core/FocusTrap.d.ts +9 -0
  5. package/dist/esm/core/Gallery.d.ts +221 -0
  6. package/dist/esm/core/GestureController.d.ts +50 -0
  7. package/dist/esm/core/LiveRegion.d.ts +6 -0
  8. package/dist/esm/core/SlideManager.d.ts +83 -0
  9. package/dist/esm/core/bodyScrollLock.d.ts +2 -0
  10. package/dist/esm/core/dom.d.ts +27 -0
  11. package/dist/esm/core/icons.d.ts +6 -0
  12. package/dist/esm/core/index.d.ts +5 -0
  13. package/dist/esm/core/index.js +1966 -0
  14. package/dist/esm/core/index.js.map +1 -0
  15. package/dist/esm/core/plugin.d.ts +54 -0
  16. package/dist/esm/core/rotateFlipNormalize.d.ts +19 -0
  17. package/dist/esm/core/scan.d.ts +8 -0
  18. package/dist/esm/core/types.d.ts +268 -0
  19. package/dist/esm/core/zoomTransition.d.ts +33 -0
  20. package/dist/esm/gestures/GestureEngine.d.ts +78 -0
  21. package/dist/esm/index.css +475 -0
  22. package/dist/esm/index.d.ts +32 -0
  23. package/dist/esm/index.js +24 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/index2.css +22 -0
  26. package/dist/esm/index3.css +166 -0
  27. package/dist/esm/index4.css +27 -0
  28. package/dist/esm/plugins/activeThumbnail/index.d.ts +26 -0
  29. package/dist/esm/plugins/activeThumbnail/index.js +48 -0
  30. package/dist/esm/plugins/activeThumbnail/index.js.map +1 -0
  31. package/dist/esm/plugins/autoplay/icons.d.ts +3 -0
  32. package/dist/esm/plugins/autoplay/index.d.ts +17 -0
  33. package/dist/esm/plugins/autoplay/index.js +177 -0
  34. package/dist/esm/plugins/autoplay/index.js.map +1 -0
  35. package/dist/esm/plugins/fullscreen/icons.d.ts +3 -0
  36. package/dist/esm/plugins/fullscreen/index.d.ts +17 -0
  37. package/dist/esm/plugins/fullscreen/index.js +74 -0
  38. package/dist/esm/plugins/fullscreen/index.js.map +1 -0
  39. package/dist/esm/plugins/layout/index.d.ts +191 -0
  40. package/dist/esm/plugins/layout/index.js +746 -0
  41. package/dist/esm/plugins/layout/index.js.map +1 -0
  42. package/dist/esm/plugins/layout/justified.d.ts +68 -0
  43. package/dist/esm/plugins/layout/masonry.d.ts +92 -0
  44. package/dist/esm/plugins/rotateFlip/icons.d.ts +5 -0
  45. package/dist/esm/plugins/rotateFlip/index.d.ts +17 -0
  46. package/dist/esm/plugins/rotateFlip/index.js +138 -0
  47. package/dist/esm/plugins/rotateFlip/index.js.map +1 -0
  48. package/dist/esm/plugins/video/index.d.ts +13 -0
  49. package/dist/esm/plugins/video/index.js +95 -0
  50. package/dist/esm/plugins/video/index.js.map +1 -0
  51. package/dist/esm/plugins/video/youtube.d.ts +61 -0
  52. package/dist/esm/plugins/zoom/icons.d.ts +4 -0
  53. package/dist/esm/plugins/zoom/index.d.ts +30 -0
  54. package/dist/esm/plugins/zoom/index.js +274 -0
  55. package/dist/esm/plugins/zoom/index.js.map +1 -0
  56. package/dist/esm/plugins/zoom/zoomMath.d.ts +24 -0
  57. package/dist/esm/transitions/SlideTransition.d.ts +25 -0
  58. package/dist/esm/transitions/presets.d.ts +21 -0
  59. package/dist/esm/zoomTransition-bbKHpVpA.js +110 -0
  60. package/dist/esm/zoomTransition-bbKHpVpA.js.map +1 -0
  61. package/dist/shoji.css +690 -0
  62. package/dist/shoji.js +3605 -0
  63. package/dist/shoji.js.map +1 -0
  64. package/dist/shoji.min.css +1 -0
  65. package/dist/shoji.min.js +2 -0
  66. package/dist/shoji.min.js.map +1 -0
  67. package/package.json +77 -0
@@ -0,0 +1,268 @@
1
+ import { GestureEngineOptions } from '../gestures/GestureEngine';
2
+ import { ShojiPlugin } from './plugin';
3
+ /** See DESIGN.md §2.1 — the full item model grows plugin-by-plugin (editor, ...). */
4
+ export interface GalleryItem {
5
+ id?: string;
6
+ src: string;
7
+ srcset?: string;
8
+ sizes?: string;
9
+ sources?: MediaSource[];
10
+ thumb?: string;
11
+ poster?: string;
12
+ video?: VideoDescriptor;
13
+ width?: number;
14
+ height?: number;
15
+ alt?: string;
16
+ caption?: string | HTMLElement | DangerousHtmlCaption;
17
+ download?: string | false;
18
+ /** Free-form payload, untouched by core beyond one thing: in selector mode, `scan.ts` populates this from any `data-shoji-*` attribute that isn't already one of the named fields above (e.g. `data-shoji-metadata-id="123"` → `data.{'metadata-id': '123'}`) — dynamic-mode items only ever get whatever the host puts here directly. */
19
+ data?: Record<string, unknown>;
20
+ }
21
+ /**
22
+ * Explicit, self-documenting opt-in for raw HTML in a caption — named after
23
+ * React's identical escape hatch on purpose, so it can't be triggered by
24
+ * accident and anyone who's seen that convention knows what it means. Shoji
25
+ * does not sanitize this string; the host must, if it isn't already trusted.
26
+ */
27
+ export interface DangerousHtmlCaption {
28
+ dangerouslySetInnerHTML: string;
29
+ }
30
+ /** Mirrors a `<source src type>` child. */
31
+ export interface MediaSource {
32
+ src: string;
33
+ type: string;
34
+ }
35
+ /**
36
+ * `'youtube'` is detected by core's DOM scanning too (§2.1) — cheap,
37
+ * dependency-free URL parsing, not the provider's SDK. *Rendering* any
38
+ * non-`'html5'` provider is a plugin's job (§4-video), via
39
+ * `ctx.ui.registerVideoProvider()` or `'custom'`'s own `render`.
40
+ */
41
+ export type VideoDescriptor = {
42
+ provider: 'html5';
43
+ } | {
44
+ provider: 'youtube' | 'vimeo' | 'wistia';
45
+ id: string;
46
+ url?: string;
47
+ } | {
48
+ provider: 'custom';
49
+ /** Same contract as `plugin.ts`'s `VideoProviderRenderer` — see its doc comment. */
50
+ render: (el: HTMLElement, item: GalleryItem, onReady: () => void, signal: AbortSignal) => void;
51
+ };
52
+ export interface GalleryOptions {
53
+ /** DOM selector for gallery items when not using dynamic mode. */
54
+ selector?: string;
55
+ /** Dynamic-mode item list; mutate live via gallery.updateSlides(). */
56
+ items?: GalleryItem[];
57
+ /** Index to open on — used both as `open()`'s default argument and, with `openOnInit`, as the index opened automatically at construction. */
58
+ index?: number;
59
+ /**
60
+ * Opens the lightbox immediately at construction (to `index`, default 0),
61
+ * instead of the normal default of staying closed until the host calls
62
+ * `open()` or a scanned/layout-rendered thumbnail is clicked. Default
63
+ * `false`. Useful for hash/deep-link-style integrations that should land
64
+ * straight in the lightbox; everyone else should leave this off — a
65
+ * gallery that pops open on page load without a click is rarely what's
66
+ * wanted.
67
+ */
68
+ openOnInit?: boolean;
69
+ /** Flat locale key map — see CLAUDE.md: no hardcoded English in UI. */
70
+ locale?: Record<string, string>;
71
+ /** Registered plugins; each plugin's own options nest under options[plugin.name]. */
72
+ plugins?: ShojiPlugin[];
73
+ /**
74
+ * DESIGN.md §2.8 — ms of inactivity before all buttons/overlays (toolbar,
75
+ * prev/next, counter, caption) auto-hide; default 5000. `0` is a distinct
76
+ * mode, not "disabled": controls never show at all, regardless of activity.
77
+ */
78
+ autoHideDelay?: number;
79
+ /**
80
+ * DESIGN.md §2.3 — how many slides on each side of the active one are
81
+ * kept mounted *and* proactively decoded ahead of time; default 1.
82
+ * Navigating to any index within that window shows instantly, no loading
83
+ * spinner — its content was already decoded and cached (by item index,
84
+ * surviving the pool's internal slot reshuffling) before you got there.
85
+ * Navigating further than `preload` away (a fast flick through several
86
+ * slides, or a direct `goTo()`/deep link) still shows the spinner while
87
+ * that one decodes, same as ever — this only changes what counts as
88
+ * "already ready."
89
+ */
90
+ preload?: number;
91
+ /** Shows the "N / M" counter badge; default true. Purely visual — the live-region announcement (§2.6) always includes position regardless. */
92
+ counter?: boolean;
93
+ /** DESIGN.md §2.3a — starts a video slide's caption shown instead of hidden; default `false`. No effect on a photo's caption. */
94
+ showVideoCaption?: boolean;
95
+ /**
96
+ * DESIGN.md §2.2 — `next()`/`prev()` (and the arrow-key/toolbar-button paths
97
+ * that call them) wrap past the last/first item instead of stopping; default
98
+ * true. Does not affect `goTo(index)` with an explicit out-of-range index
99
+ * (still clamps — a directed jump, not a step) or `Home`/`End` (still an
100
+ * absolute jump to the first/last item).
101
+ */
102
+ loop?: boolean;
103
+ /**
104
+ * Default `true`. `false` disables every viewer-facing way to close the
105
+ * lightbox: the close button (hidden entirely, not just inert), clicking
106
+ * the backdrop, `Escape`, and vertical swipe-to-close (no live drag
107
+ * feedback either, not just a release that fails to close). For
108
+ * non-closable embeds — a gallery meant to stay open permanently once
109
+ * shown. `gallery.close()` itself is unaffected — this only gates the
110
+ * four built-in viewer-triggered paths, host code can still close it
111
+ * programmatically at any time.
112
+ */
113
+ closable?: boolean;
114
+ /**
115
+ * DESIGN.md §2.4 — overrides the gesture engine's `lockThreshold`/
116
+ * `swipeThreshold`/`swipeVelocity` (defaults: 10px, 50px, 0.3px/ms).
117
+ * Partial: any field left out keeps its default. Momentum easing is not
118
+ * configurable here — it's the CSS custom property
119
+ * `--shoji-momentum-easing`, per CLAUDE.md's "no hardcoded sizes/timings
120
+ * in JS, everything through --shoji-* custom properties."
121
+ */
122
+ gestures?: Partial<GestureEngineOptions>;
123
+ /**
124
+ * DESIGN.md §2.5 — the slide-to-slide transition for programmatic
125
+ * navigation (buttons, keyboard, autoplay, `goTo()`); never affects a
126
+ * gesture-driven swipe, which always uses its own live-drag/settle
127
+ * animation regardless of `mode` (§2.4). Default `'slide'`. One of the
128
+ * built-in preset names (`slide`, `fade`, `zoom`, `deck`, `slideVertical`,
129
+ * `push`, `fadeUp`, `fadeDown`, `fadeLeft`, `fadeRight`, `zoomOut`,
130
+ * `scaleUp`, `scaleDown`, `rotate`, `rotateLeft`, `rotateRight`, `flipX`,
131
+ * `flipY`, `cube`, `coverflow`, `drop`) — or any other string, treated as
132
+ * a custom CSS class pair (`shoji-transition-<mode>-enter`/`-leave`) the
133
+ * host supplies its own `transition`/`@keyframes animation` for; no JS
134
+ * needed on the host's end.
135
+ */
136
+ mode?: string;
137
+ /**
138
+ * DESIGN.md §2.5 — overrides `mode`/hides baseline controls (§2.6a) under
139
+ * a `(pointer: coarse)` device (touch-primary, not a viewport-width
140
+ * breakpoint — a narrow desktop window isn't "mobile" here). Deliberately
141
+ * scoped to just these two fields, matching this section's own example,
142
+ * rather than a general "override any GalleryOptions field under a media
143
+ * query" mechanism — nothing in the roster needs broader coverage yet,
144
+ * and that would be a substantially larger, riskier feature to build
145
+ * speculatively (CLAUDE.md).
146
+ */
147
+ mobileSettings?: {
148
+ mode?: string;
149
+ /** `false` starts controls hidden on a coarse-pointer device (via the existing §2.8 auto-hide, not a separate permanent-hide state) — they still reveal on any activity, same as normal auto-hide; a viewer is never actually stranded without a way to reach Close. */
150
+ controls?: boolean;
151
+ };
152
+ [key: string]: unknown;
153
+ }
154
+ /** See DESIGN.md §2.2 — grows as core lifecycle stages and plugins land. */
155
+ export interface GalleryEvents extends Record<string, unknown> {
156
+ beforeOpen: {
157
+ index: number;
158
+ };
159
+ open: {
160
+ index: number;
161
+ };
162
+ afterOpen: {
163
+ index: number;
164
+ };
165
+ beforeClose: Record<string, never>;
166
+ close: Record<string, never>;
167
+ afterClose: Record<string, never>;
168
+ destroy: Record<string, never>;
169
+ /** DESIGN.md §2.1 — fires after the item list changes via updateSlides()/refresh(). */
170
+ itemsUpdated: {
171
+ items: GalleryItem[];
172
+ };
173
+ /**
174
+ * DESIGN.md §2.2 lists these as cancelable; that isn't implemented yet (no
175
+ * plugin needs it yet) — detail is plain `{from, to}` for now, same as the
176
+ * other lifecycle events, not the `event.preventDefault()` shape §2.2 describes.
177
+ */
178
+ beforeSlide: {
179
+ from: number;
180
+ to: number;
181
+ };
182
+ afterSlide: {
183
+ from: number;
184
+ to: number;
185
+ };
186
+ /** DESIGN.md §2.3 — fires once a slide's media has decoded/settled. */
187
+ slideItemLoad: {
188
+ index: number;
189
+ };
190
+ /** DESIGN.md §2.8 — toolbar auto-hide sync points for plugins with their own overlays. */
191
+ 'controls:hide': Record<string, never>;
192
+ 'controls:show': Record<string, never>;
193
+ /** DESIGN.md §2.2a-autoplay — emitted by the autoplay plugin, not core. */
194
+ autoplayStart: Record<string, never>;
195
+ autoplayStop: Record<string, never>;
196
+ /**
197
+ * DESIGN.md §2.4 — core drives horizontal drag-to-navigate and vertical
198
+ * drag-to-close itself (no event needed for either — they just call
199
+ * next()/prev()/close()); tap/doubleTap/pinch/wheelZoom have no built-in
200
+ * effect in core and exist purely as a relay for a future Zoom plugin
201
+ * (double-tap toggles zoom, pinch/wheel+ctrl zoom, per §4) to consume
202
+ * without core depending on that plugin existing. Coordinates are
203
+ * viewport (client) pixels, same as the underlying PointerEvent/WheelEvent.
204
+ */
205
+ tap: {
206
+ x: number;
207
+ y: number;
208
+ };
209
+ doubleTap: {
210
+ x: number;
211
+ y: number;
212
+ };
213
+ pinchStart: {
214
+ centerX: number;
215
+ centerY: number;
216
+ };
217
+ /** scale is relative to this pinch gesture's own start distance (1 = unchanged), not cumulative across separate pinches. */
218
+ pinchMove: {
219
+ scale: number;
220
+ centerX: number;
221
+ centerY: number;
222
+ };
223
+ pinchEnd: Record<string, never>;
224
+ /** deltaScale is a small per-event increment (positive = zoom in); a consumer accumulates it, it isn't an absolute scale. */
225
+ wheelZoom: {
226
+ deltaScale: number;
227
+ x: number;
228
+ y: number;
229
+ };
230
+ /** DESIGN.md §4-fullscreen — emitted by the fullscreen plugin, not core; fires from the native `fullscreenchange` event, not the toolbar button's own click, so it reflects reality even when fullscreen was entered/exited by other means (browser Escape handling, a request rejected). */
231
+ fullscreenChange: {
232
+ fullscreen: boolean;
233
+ };
234
+ /** DESIGN.md §4-rotate/flip — emitted by the rotateFlip plugin, not core, on every rotate/flip click; the plugin itself never persists this (resets per slide) — a host wanting to keep it stores this event's payload themselves. */
235
+ rotateFlipChange: {
236
+ index: number;
237
+ flipH: boolean;
238
+ flipV: boolean;
239
+ rotation: number;
240
+ };
241
+ /** DESIGN.md §4-zoom — emitted by the zoom plugin, not core, on every scale change (gesture or button-driven); resets per slide, not persisted by the plugin itself, same pattern as rotateFlipChange. */
242
+ zoomChange: {
243
+ index: number;
244
+ scale: number;
245
+ };
246
+ /**
247
+ * DESIGN.md §5 — emitted by the layout plugin, not core, once a render
248
+ * pass has built and appended tile DOM: after `fullRender()` (every tile
249
+ * currently in the container — a full rebuild, e.g. from a non-append
250
+ * items change), or after `appendRender()` (just the newly-created tiles
251
+ * — existing ones are untouched, per the plugin's own incremental-append
252
+ * behavior). `tiles` is exactly the elements built *this pass*, in item
253
+ * order — a host injecting custom content into tiles (a badge, a
254
+ * selection checkbox, anything not itself part of the layout plugin)
255
+ * uses `element` directly and `index` to look the item back up via
256
+ * `gallery.items[index]`; `element.dataset.shojiIndex` (also set on
257
+ * every tile, matching `index` here) is the same lookup from the DOM
258
+ * side, for code that only has the element itself later (e.g. a click
259
+ * handler on injected content) and needs the index back without having
260
+ * kept this event's payload around.
261
+ */
262
+ layoutRender: {
263
+ tiles: {
264
+ index: number;
265
+ element: HTMLElement;
266
+ }[];
267
+ };
268
+ }
@@ -0,0 +1,33 @@
1
+ export interface ZoomTransitionTarget {
2
+ /** The thumbnail element to animate to/from. */
3
+ origin: HTMLElement;
4
+ /** The `.shoji-slide-media` element being animated — not `.shoji-slide` itself, whose transform is already owned by pool-offset positioning. */
5
+ target: HTMLElement;
6
+ /** `item.width / item.height`, when known — `target` is always its full flex-box size, never the (usually smaller, letterboxed) rendered photo inside it; see `effectiveTargetBox`. */
7
+ aspectRatio?: number;
8
+ }
9
+ /**
10
+ * Waits for `target`'s own transform transition to end (with a safety-net
11
+ * timeout in case transitionend never fires — an interrupted/removed
12
+ * element, or a browser quirk) then calls `cb` exactly once. Exported: the
13
+ * gesture-driven drag-to-navigate/drag-to-close settle animations (§2.4,
14
+ * `Gallery.ts`) reuse this same wait-with-fallback logic rather than
15
+ * duplicating it — same instant-jump-then-transition FLIP family of moves
16
+ * as the zoom transition, just on a different element/property pairing.
17
+ */
18
+ export declare function waitForTransitionEnd(target: HTMLElement, cb: () => void): void;
19
+ /**
20
+ * FLIP-style open: `target` starts visually at `origin`'s position/size (an
21
+ * instant, untransitioned jump), then transitions to its natural layout —
22
+ * reads as "growing out of the thumbnail." Fire-and-forget: cleans up its
23
+ * own inline styles once the transition ends, nothing to await.
24
+ */
25
+ export declare function zoomIn({ origin, target, aspectRatio }: ZoomTransitionTarget): void;
26
+ /**
27
+ * Reverse of `zoomIn`: `target` transitions from its natural position down
28
+ * to `origin`'s rect — "shrinking back into the thumbnail." `onComplete`
29
+ * always fires exactly once, synchronously if there's nothing to animate
30
+ * (reduced motion, or no valid rect), otherwise once the transition ends —
31
+ * callers use this to know when it's safe to actually hide/finalize.
32
+ */
33
+ export declare function zoomOut({ origin, target, aspectRatio }: ZoomTransitionTarget, onComplete: () => void): void;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * DESIGN.md §2.4 — one Pointer-Events-based engine feeding all consumers:
3
+ * core drag-to-navigate, core vertical-swipe-to-close, and (via `onPinch`/
4
+ * `onDoubleTap`/`onWheelZoom`) a future zoom plugin that doesn't exist yet.
5
+ * Pointer Events (not separate mouse/touch listeners) give mouse-drag and
6
+ * touch-swipe parity for free — one code path, one set of thresholds.
7
+ *
8
+ * State machine: `idle → pending → dragging(h|v) → idle`. `pending` is the
9
+ * window before `lockThreshold` is crossed, where it's still ambiguous
10
+ * whether this is a tap, a horizontal drag, or a vertical drag; `dragging`
11
+ * is entered once one axis's delta exceeds the threshold first, and the
12
+ * *other* axis is ignored for the rest of that gesture (an axis lock, not
13
+ * a snapped direction — diagonal drags don't fight the engine). There's no
14
+ * literal blocking `settling` state after release: `onDragEnd` reports the
15
+ * outcome synchronously and the caller owns however long its own
16
+ * snap-back/completion animation takes; a new `pointerdown` before that
17
+ * finishes is allowed to interrupt it (matches real touch-carousel UX —
18
+ * grabbing a still-settling slide feels responsive, not broken).
19
+ *
20
+ * Pinch tracking is a separate concern layered on top of the same pointer
21
+ * map: a second simultaneous pointer suspends whatever single-pointer drag
22
+ * state was in progress (real pinches start from a single touch already
23
+ * down) and switches to distance-ratio tracking until back down to one
24
+ * pointer or zero.
25
+ */
26
+ export type GestureDirection = 'horizontal' | 'vertical';
27
+ export interface GestureEngineOptions {
28
+ /** px of movement before a direction locks in. DESIGN.md §2.4 default: 10. */
29
+ lockThreshold: number;
30
+ /** px of movement past which a released drag counts as "swiped" (completes), independent of velocity. DESIGN.md §2.4 default: 50. */
31
+ swipeThreshold: number;
32
+ /** px/ms release velocity past which a drag completes even under swipeThreshold — a fast flick counts. DESIGN.md §2.4 default: 0.3. */
33
+ swipeVelocity: number;
34
+ }
35
+ export interface GestureEngineCallbacks {
36
+ /** Direction has just locked in for this gesture — the first move past lockThreshold. */
37
+ onDragStart?(direction: GestureDirection, event: PointerEvent): void;
38
+ /** delta: signed px moved along the locked axis so far (this move's cumulative total, not a per-frame diff). */
39
+ onDragMove?(direction: GestureDirection, delta: number, event: PointerEvent): void;
40
+ /** Pointer released (or cancelled) after a drag was in progress. velocity is signed px/ms over the whole gesture; completed reflects swipeThreshold/swipeVelocity. cancelled is true for pointercancel (e.g. an OS gesture took over) — always treated as not-completed regardless of delta/velocity. */
41
+ onDragEnd?(direction: GestureDirection, delta: number, velocity: number, completed: boolean, cancelled: boolean): void;
42
+ /** A pointerdown that never crossed lockThreshold before release — not a drag. Used to detect double-tap (the engine tracks tap timing/position itself and calls onDoubleTap instead when two land close enough together) as well as being a simple tap signal on its own. */
43
+ onTap?(x: number, y: number, event: PointerEvent): void;
44
+ onDoubleTap?(x: number, y: number, event: PointerEvent): void;
45
+ /** scale is relative to the pinch's own start distance (1 = unchanged), not a cumulative multiplier across multiple pinch gestures. */
46
+ onPinchStart?(centerX: number, centerY: number): void;
47
+ onPinchMove?(scale: number, centerX: number, centerY: number): void;
48
+ onPinchEnd?(): void;
49
+ /** Ctrl+wheel (trackpad pinch reports this way in every major browser) or a genuine ctrl+scroll-wheel. deltaScale is a small increment (positive = zoom in), not an absolute scale — the caller accumulates it. */
50
+ onWheelZoom?(deltaScale: number, x: number, y: number, event: WheelEvent): void;
51
+ /** Only consulted on pointerdown — returning true means this pointer is ignored for the rest of its lifetime (a click on a real button/control shouldn't also start a drag). */
52
+ ignore?(event: PointerEvent): boolean;
53
+ /** Consulted right before capturing a locked drag's pointer — `false` skips capture for this gesture entirely (not just its drag effect). Default `true` if omitted. See onPointerMove's capture branch for why this needs to be a real skip, not just a suppressed effect. */
54
+ shouldCapture?(): boolean;
55
+ }
56
+ export declare class GestureEngine {
57
+ private readonly target;
58
+ private readonly options;
59
+ private readonly callbacks;
60
+ private readonly pointers;
61
+ private primaryPointerId;
62
+ private direction;
63
+ private dragStartDistance;
64
+ private pinching;
65
+ private pinchStartDistance;
66
+ private lastTapTime;
67
+ private lastTapX;
68
+ private lastTapY;
69
+ constructor(target: HTMLElement, callbacks: GestureEngineCallbacks, options?: Partial<GestureEngineOptions>);
70
+ destroy(): void;
71
+ private readonly onPointerDown;
72
+ private readonly onPointerMove;
73
+ private readonly onPointerUp;
74
+ private readonly onPointerCancel;
75
+ private finishPointer;
76
+ private registerTap;
77
+ private readonly onWheel;
78
+ }