@inkbar/core 0.10.0 → 0.11.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/dist/dom.mjs CHANGED
@@ -228,6 +228,347 @@ function mostVisiblePageCss(layout, scrollTop, viewportHeight) {
228
228
  return best;
229
229
  }
230
230
  //#endregion
231
+ //#region src/dom/pinch.ts
232
+ const midpoint = (a, b) => ({
233
+ x: (a.x + b.x) / 2,
234
+ y: (a.y + b.y) / 2
235
+ });
236
+ function pinchFrame(start, now, startScale, minZoom, maxZoom) {
237
+ const from = Math.hypot(start[1].x - start[0].x, start[1].y - start[0].y);
238
+ const to = Math.hypot(now[1].x - now[0].x, now[1].y - now[0].y);
239
+ const zoom = from > 0 ? Math.min(maxZoom, Math.max(minZoom, startScale * to / from)) : startScale;
240
+ const anchor = midpoint(start[0], start[1]);
241
+ const mid = midpoint(now[0], now[1]);
242
+ return {
243
+ zoom,
244
+ factor: from > 0 ? zoom / startScale : 1,
245
+ anchor,
246
+ pan: {
247
+ x: mid.x - anchor.x,
248
+ y: mid.y - anchor.y
249
+ }
250
+ };
251
+ }
252
+ const SETTLE_MS = 150;
253
+ /**
254
+ * The pinch preview: a transform on the pages element, which the browser composites without
255
+ * laying anything out. `settle` covers what a preview can show but the committed layout
256
+ * cannot reach (mainly scroll clamped at the content edges): the pages start where the fingers
257
+ * left them and slide into place.
258
+ */
259
+ function createZoomPreview(container, pagesEl) {
260
+ const win = container.ownerDocument.defaultView ?? window;
261
+ let frame = 0;
262
+ let timer;
263
+ function stopSettling() {
264
+ if (frame) win.cancelAnimationFrame(frame);
265
+ frame = 0;
266
+ if (timer !== void 0) clearTimeout(timer);
267
+ timer = void 0;
268
+ pagesEl.removeEventListener("transitionend", onTransitionEnd);
269
+ pagesEl.style.removeProperty("transition");
270
+ }
271
+ function settled() {
272
+ stopSettling();
273
+ pagesEl.style.removeProperty("transform");
274
+ }
275
+ const onTransitionEnd = (e) => {
276
+ if (e.target === pagesEl && e.propertyName === "transform") settled();
277
+ };
278
+ function clear() {
279
+ stopSettling();
280
+ pagesEl.style.removeProperty("transform");
281
+ pagesEl.style.removeProperty("transform-origin");
282
+ }
283
+ return {
284
+ show(factor, anchor, pan) {
285
+ stopSettling();
286
+ const x = anchor.x + container.scrollLeft - pagesEl.offsetLeft;
287
+ const y = anchor.y + container.scrollTop - pagesEl.offsetTop;
288
+ pagesEl.style.transformOrigin = `${x}px ${y}px`;
289
+ pagesEl.style.transform = `translate(${pan.x}px, ${pan.y}px) scale(${factor})`;
290
+ },
291
+ clear,
292
+ settle(offset) {
293
+ clear();
294
+ pagesEl.style.transform = `translate(${offset.x}px, ${offset.y}px)`;
295
+ frame = win.requestAnimationFrame(() => {
296
+ frame = 0;
297
+ getComputedStyle(pagesEl).transform;
298
+ pagesEl.style.transition = `transform ${SETTLE_MS}ms ease-out`;
299
+ pagesEl.style.removeProperty("transform");
300
+ pagesEl.addEventListener("transitionend", onTransitionEnd);
301
+ timer = setTimeout(settled, 200);
302
+ });
303
+ },
304
+ destroy: clear
305
+ };
306
+ }
307
+ /**
308
+ * Tracks touches on the container with touch events, which every touch browser sends as one
309
+ * stream (pointer events may be cancelled once the browser decides to pan). The first two
310
+ * fingers down start a pinch; a third is ignored. The pinch ends when either of its fingers
311
+ * lifts or is cancelled, and any finger still down then starts nothing until every finger has
312
+ * lifted. While two fingers are down their moves are prevented, so the browser neither pans
313
+ * nor zooms underneath; one finger's moves never are, so a one-finger scroll stays native. A
314
+ * move the browser will not let us cancel means it is scrolling natively already: that travel
315
+ * is left to it, and only what the fingers do after it is scrolled here.
316
+ * The viewport claims pinch on the container (`touch-action: pan-x pan-y`), which keeps the
317
+ * page from zooming as well; the tool controller turns off one-finger panning on the pages
318
+ * element while a drag tool is ready, and two fingers still land here. A finger
319
+ * that lands alone starts afresh, so an end the browser never sent leaves nothing behind.
320
+ */
321
+ function attachTouchPinch(opts) {
322
+ const { container, preview } = opts;
323
+ let pinch;
324
+ let spent = false;
325
+ /** The touches that went down on the container, by identifier. */
326
+ const mine = /* @__PURE__ */ new Set();
327
+ const down = (list) => [...list].filter((t) => mine.has(t.identifier));
328
+ function at(t) {
329
+ const r = container.getBoundingClientRect();
330
+ return {
331
+ x: t.clientX - r.left - container.clientLeft,
332
+ y: t.clientY - r.top - container.clientTop
333
+ };
334
+ }
335
+ const onStart = (e) => {
336
+ const live = new Set([...e.touches].map((t) => t.identifier));
337
+ for (const id of mine) if (!live.has(id)) mine.delete(id);
338
+ for (const t of e.changedTouches) mine.add(t.identifier);
339
+ const fingers = down(e.touches);
340
+ if (fingers.length === 1) {
341
+ if (pinch) preview.clear();
342
+ pinch = void 0;
343
+ spent = false;
344
+ }
345
+ if (pinch || spent || fingers.length < 2) return;
346
+ const [a, b] = fingers;
347
+ const start = [at(a), at(b)];
348
+ const scale = opts.scale();
349
+ pinch = {
350
+ ids: [a.identifier, b.identifier],
351
+ start,
352
+ scale,
353
+ last: pinchFrame(start, start, scale, opts.minZoom, opts.maxZoom),
354
+ scrolled: {
355
+ x: 0,
356
+ y: 0
357
+ },
358
+ mid: midpoint(start[0], start[1])
359
+ };
360
+ };
361
+ const onMove = (e) => {
362
+ if (down(e.touches).length >= 2 && e.cancelable) e.preventDefault();
363
+ if (!pinch) return;
364
+ const ids = pinch.ids;
365
+ const touches = [...e.touches];
366
+ const a = touches.find((t) => t.identifier === ids[0]);
367
+ const b = touches.find((t) => t.identifier === ids[1]);
368
+ if (!a || !b) return;
369
+ const now = [at(a), at(b)];
370
+ const mid = midpoint(now[0], now[1]);
371
+ const native = !e.cancelable;
372
+ if (native) {
373
+ const dx = mid.x - pinch.mid.x;
374
+ const dy = mid.y - pinch.mid.y;
375
+ pinch.start = [{
376
+ x: pinch.start[0].x + dx,
377
+ y: pinch.start[0].y + dy
378
+ }, {
379
+ x: pinch.start[1].x + dx,
380
+ y: pinch.start[1].y + dy
381
+ }];
382
+ }
383
+ pinch.mid = mid;
384
+ const frame = pinchFrame(pinch.start, now, pinch.scale, opts.minZoom, opts.maxZoom);
385
+ const { scrolled } = pinch;
386
+ if (!native) {
387
+ const took = opts.scrollBy({
388
+ x: frame.pan.x - scrolled.x,
389
+ y: frame.pan.y - scrolled.y
390
+ });
391
+ scrolled.x += took.x;
392
+ scrolled.y += took.y;
393
+ }
394
+ pinch.last = {
395
+ ...frame,
396
+ anchor: {
397
+ x: frame.anchor.x + scrolled.x,
398
+ y: frame.anchor.y + scrolled.y
399
+ },
400
+ pan: {
401
+ x: frame.pan.x - scrolled.x,
402
+ y: frame.pan.y - scrolled.y
403
+ }
404
+ };
405
+ preview.show(pinch.last.factor, pinch.last.anchor, pinch.last.pan);
406
+ };
407
+ const onEnd = (e) => {
408
+ const ended = [...e.changedTouches].map((t) => t.identifier);
409
+ for (const id of ended) mine.delete(id);
410
+ if (pinch && pinch.ids.some((id) => ended.includes(id))) {
411
+ const { last } = pinch;
412
+ pinch = void 0;
413
+ spent = true;
414
+ preview.clear();
415
+ opts.commit(last);
416
+ }
417
+ if (down(e.touches).length === 0) spent = false;
418
+ };
419
+ const listen = { passive: false };
420
+ container.addEventListener("touchstart", onStart, listen);
421
+ container.addEventListener("touchmove", onMove, listen);
422
+ container.addEventListener("touchend", onEnd, listen);
423
+ container.addEventListener("touchcancel", onEnd, listen);
424
+ return { destroy() {
425
+ container.removeEventListener("touchstart", onStart);
426
+ container.removeEventListener("touchmove", onMove);
427
+ container.removeEventListener("touchend", onEnd);
428
+ container.removeEventListener("touchcancel", onEnd);
429
+ mine.clear();
430
+ pinch = void 0;
431
+ spent = false;
432
+ } };
433
+ }
434
+ const WHEEL_STEP = 1.1;
435
+ /**
436
+ * The zoom factor one wheel event stands for. A trackpad pinch arrives as ctrl+wheel events
437
+ * with small pixel deltas, which zoom smoothly. A mouse wheel notch with ctrl held arrives in
438
+ * line or page mode, or as one large pixel delta, and is one small step, whatever its size.
439
+ */
440
+ function wheelFactor(e) {
441
+ if (e.deltaMode !== 0 || Math.abs(e.deltaY) >= 50) return e.deltaY < 0 ? WHEEL_STEP : e.deltaY > 0 ? 1 / WHEEL_STEP : 1;
442
+ return Math.exp(-e.deltaY / 100);
443
+ }
444
+ const IDLE_MS = 150;
445
+ const TOUCH_TYPES = [
446
+ "touchstart",
447
+ "touchend",
448
+ "touchcancel"
449
+ ];
450
+ /**
451
+ * A trackpad pinch over the container. Browsers report it as ctrl+wheel events, which are
452
+ * taken over so the page does not zoom; a run of them is one pinch, anchored at the pointer
453
+ * where it began and committed once the events stop, or as soon as the container scrolls (a
454
+ * plain wheel, a scroll bar), so the scroll moves the committed layout and not the preview.
455
+ * Safari also has gesture events, which give the scale directly; while one of those runs,
456
+ * ctrl+wheel is ignored so nothing counts twice. Safari on a touch screen sends gesture events
457
+ * for a touch pinch too, which `attachTouchPinch` already handles: while a finger is down on
458
+ * the container they are prevented and otherwise ignored. The wheel listener is non-passive
459
+ * because it has to call `preventDefault`.
460
+ */
461
+ function attachTrackpadPinch(opts) {
462
+ const { container, preview } = opts;
463
+ const win = container.ownerDocument.defaultView ?? window;
464
+ let run;
465
+ let gesturing = false;
466
+ /** A finger is down on the container. */
467
+ let touching = false;
468
+ let timer;
469
+ function at(e) {
470
+ const r = container.getBoundingClientRect();
471
+ return {
472
+ x: e.clientX - r.left - container.clientLeft,
473
+ y: e.clientY - r.top - container.clientTop
474
+ };
475
+ }
476
+ function update(e, next) {
477
+ if (!run) {
478
+ const scale = opts.scale();
479
+ const anchor = at(e);
480
+ run = {
481
+ anchor,
482
+ scale,
483
+ factor: 1,
484
+ last: pinchFrame([anchor, anchor], [anchor, anchor], scale, opts.minZoom, opts.maxZoom)
485
+ };
486
+ }
487
+ run.factor = next(run.factor);
488
+ const zoom = Math.min(opts.maxZoom, Math.max(opts.minZoom, run.scale * run.factor));
489
+ run.last = {
490
+ zoom,
491
+ factor: zoom / run.scale,
492
+ anchor: run.anchor,
493
+ pan: {
494
+ x: 0,
495
+ y: 0
496
+ }
497
+ };
498
+ preview.show(run.last.factor, run.last.anchor, run.last.pan);
499
+ }
500
+ function end() {
501
+ if (timer !== void 0) clearTimeout(timer);
502
+ timer = void 0;
503
+ if (!run) return;
504
+ const { last } = run;
505
+ run = void 0;
506
+ preview.clear();
507
+ opts.commit(last);
508
+ }
509
+ const onWheel = (e) => {
510
+ if (!e.ctrlKey) {
511
+ if (!gesturing) end();
512
+ return;
513
+ }
514
+ if (gesturing) return;
515
+ e.preventDefault();
516
+ update(e, (f) => f * wheelFactor(e));
517
+ if (timer !== void 0) clearTimeout(timer);
518
+ timer = setTimeout(end, IDLE_MS);
519
+ };
520
+ const onScroll = () => {
521
+ if (!gesturing) end();
522
+ };
523
+ const onTouch = (e) => {
524
+ touching = e.type === "touchstart" || e.touches.length > 0;
525
+ };
526
+ const onGestureStart = (e) => {
527
+ e.preventDefault();
528
+ if (touching) return;
529
+ if (timer !== void 0) clearTimeout(timer);
530
+ timer = void 0;
531
+ end();
532
+ gesturing = true;
533
+ update(e, () => 1);
534
+ };
535
+ const onGestureChange = (e) => {
536
+ e.preventDefault();
537
+ if (!gesturing) return;
538
+ update(e, () => e.scale);
539
+ };
540
+ const onGestureEnd = (e) => {
541
+ e.preventDefault();
542
+ if (!gesturing) return;
543
+ gesturing = false;
544
+ end();
545
+ };
546
+ container.addEventListener("wheel", onWheel, { passive: false });
547
+ container.addEventListener("scroll", onScroll, { passive: true });
548
+ const hasGestures = "GestureEvent" in win;
549
+ if (hasGestures) {
550
+ for (const type of TOUCH_TYPES) container.addEventListener(type, onTouch, { passive: true });
551
+ container.addEventListener("gesturestart", onGestureStart);
552
+ container.addEventListener("gesturechange", onGestureChange);
553
+ container.addEventListener("gestureend", onGestureEnd);
554
+ }
555
+ return { destroy() {
556
+ container.removeEventListener("wheel", onWheel);
557
+ container.removeEventListener("scroll", onScroll);
558
+ if (hasGestures) {
559
+ for (const type of TOUCH_TYPES) container.removeEventListener(type, onTouch);
560
+ container.removeEventListener("gesturestart", onGestureStart);
561
+ container.removeEventListener("gesturechange", onGestureChange);
562
+ container.removeEventListener("gestureend", onGestureEnd);
563
+ }
564
+ if (timer !== void 0) clearTimeout(timer);
565
+ timer = void 0;
566
+ run = void 0;
567
+ gesturing = false;
568
+ preview.clear();
569
+ } };
570
+ }
571
+ //#endregion
231
572
  //#region src/dom/viewport.ts
232
573
  function sameList$1(a, b) {
233
574
  return a.length === b.length && a.every((v, i) => v === b[i]);
@@ -252,10 +593,13 @@ function createViewport(opts) {
252
593
  });
253
594
  const previousStyle = {
254
595
  overflow: container.style.overflow,
255
- position: container.style.position
596
+ position: container.style.position,
597
+ touchAction: container.style.touchAction
256
598
  };
257
599
  container.dataset.inkViewport = "";
258
600
  container.style.overflow = "auto";
601
+ const pinchZoom = opts.pinchZoom ?? true;
602
+ if (pinchZoom) container.style.touchAction = "pan-x pan-y";
259
603
  if (getComputedStyle(container).position === "static") container.style.position = "relative";
260
604
  const pagesEl = container.ownerDocument.createElement("div");
261
605
  pagesEl.className = "ink-pages";
@@ -422,6 +766,21 @@ function createViewport(opts) {
422
766
  }
423
767
  return best;
424
768
  }
769
+ /** The page and user-space point under `anchor` (container-relative), from the current layout. */
770
+ function userAt(anchor) {
771
+ const o = origin();
772
+ const x = container.scrollLeft + anchor.x - o.x;
773
+ const y = container.scrollTop + anchor.y - o.y;
774
+ const box = anchorBox(layout.get(), y);
775
+ if (!box) return void 0;
776
+ return {
777
+ page: box.index,
778
+ user: transformFor(box.index).fromCss({
779
+ x: x - box.left,
780
+ y: y - box.top
781
+ })
782
+ };
783
+ }
425
784
  /**
426
785
  * Keeps the user-space point under `anchorCss` still while `change` alters the layout.
427
786
  * The anchor is taken in layout space, so it holds in the margins and gaps too: there it
@@ -433,25 +792,103 @@ function createViewport(opts) {
433
792
  x: container.clientWidth / 2,
434
793
  y: container.clientHeight / 2
435
794
  };
436
- const o = origin();
437
- const x = container.scrollLeft + anchor.x - o.x;
438
- const y = container.scrollTop + anchor.y - o.y;
439
- const old = anchorBox(layout.get(), y);
440
- const user = old ? transformFor(old.index).fromCss({
441
- x: x - old.left,
442
- y: y - old.top
443
- }) : void 0;
795
+ const at = userAt(anchor);
444
796
  change();
445
797
  relayout();
446
- if (!old || !user) return;
447
- const box = boxFor(old.index);
798
+ if (!at) return;
799
+ const box = boxFor(at.page);
448
800
  if (!box) return;
449
- const after = transformFor(old.index).toCss(user);
450
- const o2 = origin();
451
- container.scrollLeft = o2.x + box.left + after.x - anchor.x;
452
- container.scrollTop = o2.y + box.top + after.y - anchor.y;
801
+ const after = transformFor(at.page).toCss(at.user);
802
+ const o = origin();
803
+ container.scrollLeft = o.x + box.left + after.x - anchor.x;
804
+ container.scrollTop = o.y + box.top + after.y - anchor.y;
805
+ sync();
806
+ }
807
+ /**
808
+ * The translation a pinch preview applies, from the current layout. While the zoomed pages
809
+ * would still be narrower than the container, the committed layout centres them (and leaves
810
+ * nothing to scroll sideways), so the preview puts them there instead of following the fingers.
811
+ */
812
+ function previewPan(factor, anchor, pan) {
813
+ const l = layout.get();
814
+ const widest = l.boxes.reduce((max, b) => Math.max(max, b.width), 0);
815
+ const inner = innerSize().width;
816
+ if (widest * factor >= inner) return pan;
817
+ const o = origin();
818
+ const ox = anchor.x + container.scrollLeft - o.x;
819
+ const shown = o.x - container.scrollLeft + ox + (l.width / 2 - ox) * factor + pan.x;
820
+ const centred = o.x + inner / 2;
821
+ return {
822
+ x: pan.x + centred - shown,
823
+ y: pan.y
824
+ };
825
+ }
826
+ /**
827
+ * Ends a pinch: one zoom change around the point that started between the fingers, then any
828
+ * travel the touch pinch could not scroll as it went (all of it, for a trackpad pinch) as a
829
+ * scroll, so that point ends up where the preview last showed it.
830
+ * When the scroll's edges stop it getting there, the preview eases the difference out. A
831
+ * pinch that did not zoom changes no zoom, so a fit mode stays: a two-finger pan only
832
+ * scrolls, and a two-finger tap changes nothing.
833
+ */
834
+ function commitPinch(frame) {
835
+ if (destroyed) return;
836
+ const zoomed = Math.abs(frame.factor - 1) >= .001;
837
+ if (!zoomed && Math.hypot(frame.pan.x, frame.pan.y) < 1) return;
838
+ const at = userAt(frame.anchor);
839
+ const shown = previewPan(frame.factor, frame.anchor, frame.pan);
840
+ if (zoomed) withAnchor(frame.anchor, () => zoom.set(clamp(frame.zoom)));
841
+ container.scrollLeft -= frame.pan.x;
842
+ container.scrollTop -= frame.pan.y;
453
843
  sync();
844
+ const box = at && boxFor(at.page);
845
+ if (!at || !box) return;
846
+ const css = transformFor(at.page).toCss(at.user);
847
+ const o = origin();
848
+ const actual = {
849
+ x: o.x + box.left + css.x - container.scrollLeft,
850
+ y: o.y + box.top + css.y - container.scrollTop
851
+ };
852
+ const dx = frame.anchor.x + shown.x - actual.x;
853
+ const dy = frame.anchor.y + shown.y - actual.y;
854
+ if (Math.abs(dx) > 1 || Math.abs(dy) > 1) preview?.settle({
855
+ x: dx,
856
+ y: dy
857
+ });
454
858
  }
859
+ const basePreview = pinchZoom ? createZoomPreview(container, pagesEl) : void 0;
860
+ const preview = basePreview && {
861
+ ...basePreview,
862
+ show: (factor, anchor, pan) => basePreview.show(factor, anchor, previewPan(factor, anchor, pan))
863
+ };
864
+ const pinch = preview ? attachTouchPinch({
865
+ container,
866
+ preview,
867
+ scale: () => scale.get(),
868
+ minZoom,
869
+ maxZoom,
870
+ scrollBy: (delta) => {
871
+ const { scrollLeft, scrollTop } = container;
872
+ container.scrollTo({
873
+ left: scrollLeft - delta.x,
874
+ top: scrollTop - delta.y,
875
+ behavior: "instant"
876
+ });
877
+ return {
878
+ x: scrollLeft - container.scrollLeft,
879
+ y: scrollTop - container.scrollTop
880
+ };
881
+ },
882
+ commit: commitPinch
883
+ }) : void 0;
884
+ const trackpadPinch = preview ? attachTrackpadPinch({
885
+ container,
886
+ preview,
887
+ scale: () => scale.get(),
888
+ minZoom,
889
+ maxZoom,
890
+ commit: commitPinch
891
+ }) : void 0;
455
892
  const viewport = {
456
893
  zoom: readonly(zoom),
457
894
  scale: readonly(scale),
@@ -523,6 +960,9 @@ function createViewport(opts) {
523
960
  destroy() {
524
961
  if (destroyed) return;
525
962
  destroyed = true;
963
+ pinch?.destroy();
964
+ trackpadPinch?.destroy();
965
+ preview?.destroy();
526
966
  ro.disconnect();
527
967
  container.removeEventListener("scroll", onScroll);
528
968
  if (scrollFrame) cancelAnimationFrame(scrollFrame);
@@ -536,6 +976,7 @@ function createViewport(opts) {
536
976
  delete container.dataset.inkViewport;
537
977
  container.style.overflow = previousStyle.overflow;
538
978
  container.style.position = previousStyle.position;
979
+ container.style.touchAction = previousStyle.touchAction;
539
980
  }
540
981
  };
541
982
  relayout();
@@ -3744,6 +4185,7 @@ function createPluginHost(opts) {
3744
4185
  const editFns = [];
3745
4186
  const setupCleanups = [];
3746
4187
  const redecorators = /* @__PURE__ */ new Set();
4188
+ const pressListeners = /* @__PURE__ */ new Set();
3747
4189
  const marks = createMarksRegistry();
3748
4190
  const selections = /* @__PURE__ */ new Map();
3749
4191
  let opened = null;
@@ -3784,8 +4226,21 @@ function createPluginHost(opts) {
3784
4226
  for (const request of requests) request.current.set(null);
3785
4227
  for (const cleanup of state.cleanups.reverse()) guard(cleanup);
3786
4228
  };
3787
- const contextFor = (plugin) => {
4229
+ const contextFor = (plugin, owned) => {
3788
4230
  const storeNames = /* @__PURE__ */ new Set();
4231
+ const listenForPress = (kind) => (fn) => {
4232
+ const entry = {
4233
+ plugin: plugin.id,
4234
+ kind,
4235
+ fn
4236
+ };
4237
+ pressListeners.add(entry);
4238
+ owned.add(entry);
4239
+ return () => {
4240
+ pressListeners.delete(entry);
4241
+ owned.delete(entry);
4242
+ };
4243
+ };
3789
4244
  const ctx = {
3790
4245
  id: plugin.id,
3791
4246
  document: opts.document,
@@ -3834,7 +4289,9 @@ function createPluginHost(opts) {
3834
4289
  scrollTo(page, rect, scrollOpts) {
3835
4290
  opts.viewport?.()?.scrollToRect(page, rect, scrollOpts);
3836
4291
  },
3837
- search: opts.search ?? inertSearch
4292
+ search: opts.search ?? inertSearch,
4293
+ onPress: listenForPress("press"),
4294
+ onLongPress: listenForPress("long-press")
3838
4295
  };
3839
4296
  internals$1.set(ctx, {
3840
4297
  marks,
@@ -3913,13 +4370,22 @@ function createPluginHost(opts) {
3913
4370
  };
3914
4371
  for (const plugin of opts.plugins) {
3915
4372
  let cleanup;
4373
+ const owned = /* @__PURE__ */ new Set();
4374
+ const dropPresses = () => {
4375
+ for (const entry of owned) pressListeners.delete(entry);
4376
+ owned.clear();
4377
+ };
3916
4378
  try {
3917
- cleanup = plugin.setup(contextFor(plugin));
4379
+ cleanup = plugin.setup(contextFor(plugin, owned));
3918
4380
  } catch (error) {
4381
+ dropPresses();
3919
4382
  for (const done of setupCleanups.reverse()) guard(done);
3920
4383
  throw error;
3921
4384
  }
3922
- if (typeof cleanup === "function") setupCleanups.push(cleanup);
4385
+ setupCleanups.push(() => {
4386
+ dropPresses();
4387
+ if (typeof cleanup === "function") cleanup();
4388
+ });
3923
4389
  }
3924
4390
  const current = opts.document.get();
3925
4391
  if (current) open(current);
@@ -3968,6 +4434,16 @@ function createPluginHost(opts) {
3968
4434
  redecorators.delete(run);
3969
4435
  };
3970
4436
  },
4437
+ emitPress(kind, press) {
4438
+ for (const entry of [...pressListeners]) {
4439
+ if (entry.kind !== kind || !pressListeners.has(entry)) continue;
4440
+ try {
4441
+ entry.fn(press);
4442
+ } catch (error) {
4443
+ console.error(`Plugin ${entry.plugin} threw in a ${kind} listener`, error);
4444
+ }
4445
+ }
4446
+ },
3971
4447
  destroy() {
3972
4448
  if (destroyed) return;
3973
4449
  destroyed = true;
@@ -5138,6 +5614,48 @@ function createToolOptions(tools = []) {
5138
5614
  register
5139
5615
  };
5140
5616
  }
5617
+ const defaultSlop = (pointerType) => pointerType === "mouse" ? 4 : 10;
5618
+ function createPressTracker(opts) {
5619
+ const longPressMs = opts.longPressMs ?? 500;
5620
+ const slopFor = opts.slop ?? defaultSlop;
5621
+ let live;
5622
+ function cancel() {
5623
+ if (live?.timer !== void 0) clearTimeout(live.timer);
5624
+ live = void 0;
5625
+ }
5626
+ return {
5627
+ down(e, press) {
5628
+ cancel();
5629
+ const l = {
5630
+ pointerId: e.pointerId,
5631
+ x: e.clientX,
5632
+ y: e.clientY,
5633
+ slop: slopFor(press.pointerType),
5634
+ press,
5635
+ timer: void 0,
5636
+ done: false
5637
+ };
5638
+ if (press.pointerType !== "mouse") l.timer = setTimeout(() => {
5639
+ l.timer = void 0;
5640
+ l.done = true;
5641
+ opts.onLongPress(press);
5642
+ }, longPressMs);
5643
+ live = l;
5644
+ },
5645
+ move(e) {
5646
+ if (live?.pointerId !== e.pointerId) return;
5647
+ if (Math.hypot(e.clientX - live.x, e.clientY - live.y) > live.slop) cancel();
5648
+ },
5649
+ up(e) {
5650
+ if (live?.pointerId !== e.pointerId) return;
5651
+ const { press, done } = live;
5652
+ cancel();
5653
+ if (!done) opts.onPress(press);
5654
+ },
5655
+ cancel,
5656
+ destroy: cancel
5657
+ };
5658
+ }
5141
5659
  //#endregion
5142
5660
  //#region src/dom/tools/selection-edit.ts
5143
5661
  const CORNERS = [
@@ -5612,6 +6130,7 @@ function createToolController$1(opts) {
5612
6130
  clearMade();
5613
6131
  made = [...ids];
5614
6132
  ctx.root.dataset.inkMade = "";
6133
+ applyClaim();
5615
6134
  stopMade = [ctx.store.list.subscribe(checkMade), ctx.store.selection.subscribe(checkMade)];
5616
6135
  },
5617
6136
  done() {
@@ -5623,6 +6142,8 @@ function createToolController$1(opts) {
5623
6142
  const originalCursor = ctx.root.style.cursor;
5624
6143
  /** The pointer between a primary press and its release or cancel. */
5625
6144
  let pressed;
6145
+ /** Whether `pressed` is a touch, which a second touch turns into a pinch. */
6146
+ let pressedTouch = false;
5626
6147
  /** Pointers whose release belongs to a tool that is no longer active. */
5627
6148
  const swallow = /* @__PURE__ */ new Set();
5628
6149
  /** What the active one-shot tool made; undefined while it is ready. */
@@ -5630,16 +6151,51 @@ function createToolController$1(opts) {
5630
6151
  let stopMade = [];
5631
6152
  /** Whether the press now under way found the tool made (see the top of the file). */
5632
6153
  let pressFoundMade = false;
6154
+ /** Whether the press now under way commits an open editor or closes an open popover. */
6155
+ let pressDismisses = false;
5633
6156
  /** Moves and resizes what the active one-shot tool made. */
5634
6157
  let madeEdit;
5635
6158
  /** The press now under way went to `madeEdit`, not the tool. */
5636
6159
  let editingMade = false;
6160
+ const presses = createPressTracker({
6161
+ onPress: (press) => opts.onPress?.("press", press),
6162
+ onLongPress: (press) => opts.onPress?.("long-press", press)
6163
+ });
5637
6164
  function clearMade() {
5638
6165
  stopMade.forEach((stop) => stop());
5639
6166
  stopMade = [];
5640
6167
  made = void 0;
5641
6168
  delete ctx.root.dataset.inkMade;
6169
+ applyClaim();
5642
6170
  }
6171
+ /**
6172
+ * Turns off one-finger panning on the pages element while a claiming tool is ready. The
6173
+ * viewport never sets `touch-action` there, so removing the property restores it. A host
6174
+ * without a pages element (no `createViewport`) gets no claim.
6175
+ */
6176
+ function applyClaim() {
6177
+ const pages = pagesOf();
6178
+ if (!pages) return;
6179
+ if (claiming()) pages.style.touchAction = "pinch-zoom";
6180
+ else pages.style.removeProperty("touch-action");
6181
+ }
6182
+ function pagesOf() {
6183
+ return ctx.root.querySelector(":scope > [data-ink-pages]");
6184
+ }
6185
+ /** True while the active tool claims touch: it claims it and, if one-shot, is still ready. */
6186
+ function claiming() {
6187
+ return current?.claimsTouch === true && made === void 0;
6188
+ }
6189
+ /**
6190
+ * Safari on iPad can let a one-finger drag scroll the container despite the claim's
6191
+ * `touch-action`, then cancel the tool's gesture. So a claimed one-finger move on the pages
6192
+ * also cancels the browser's scroll. Two fingers are left to the pinch handler or the browser.
6193
+ */
6194
+ const onTouchMove = (e) => {
6195
+ if (!e.cancelable || e.touches.length !== 1 || !claiming()) return;
6196
+ const pages = pagesOf();
6197
+ if (pages && e.target instanceof Node && pages.contains(e.target)) e.preventDefault();
6198
+ };
5643
6199
  /** Leaves the made state when its items are gone, or switches when the selection moved on. */
5644
6200
  function checkMade() {
5645
6201
  if (!made) return;
@@ -5653,17 +6209,32 @@ function createToolController$1(opts) {
5653
6209
  }
5654
6210
  /** True for events from a pointer other than the one whose press is live. */
5655
6211
  const foreign = (e) => pressed !== void 0 && pressed !== e.pointerId;
5656
- const readFirst = () => {
6212
+ const readFirst = (e) => {
5657
6213
  pressFoundMade = made !== void 0;
6214
+ pressDismisses = dismisses(e.target, ctx.root.ownerDocument);
5658
6215
  };
5659
6216
  const readAfterEditor = () => {
5660
6217
  pressFoundMade ||= made !== void 0;
5661
6218
  };
5662
6219
  const onDown = (e) => {
6220
+ if (e.pointerType === "touch" && !e.isPrimary) {
6221
+ presses.cancel();
6222
+ if (pressedTouch) cancelPressed();
6223
+ return;
6224
+ }
6225
+ if (e.pointerType === "pen" && pressedTouch && pressed !== void 0) {
6226
+ presses.cancel();
6227
+ cancelPressed();
6228
+ }
5663
6229
  if (!e.isPrimary || e.button !== 0 || inCustomContent(e.target)) return;
5664
6230
  if (foreign(e)) return;
5665
6231
  swallow.delete(e.pointerId);
5666
- const annotationId = (e.target instanceof Element ? e.target : null)?.closest("[data-annotation]")?.getAttribute("data-annotation") ?? void 0;
6232
+ pressedTouch = e.pointerType === "touch";
6233
+ const target = e.target instanceof Element ? e.target : null;
6234
+ const annotationId = target?.closest("[data-annotation]")?.getAttribute("data-annotation") ?? void 0;
6235
+ const hit = hitFor(ctx, e);
6236
+ const reportable = (current?.id === "select-text" || current?.id === "select") && annotationId === void 0 && target?.closest("a[href], [data-handle]") == null && !pressDismisses && !closedEditor(e) && hit !== void 0;
6237
+ presses.cancel();
5667
6238
  if (current?.kind === "one-shot") {
5668
6239
  if (pressFoundMade && annotationId === void 0 && !onScrollBar(e, ctx.root)) {
5669
6240
  e.preventDefault();
@@ -5675,18 +6246,26 @@ function createToolController$1(opts) {
5675
6246
  if (a && made?.includes(a.id) && madeEdit) {
5676
6247
  pressed = e.pointerId;
5677
6248
  editingMade = true;
5678
- if (madeEdit.onPointerDown(e, hitFor(ctx, e), a.id) === true) capture(e.pointerId);
6249
+ if (madeEdit.onPointerDown(e, hit, a.id) === true) capture(e.pointerId);
5679
6250
  return;
5680
6251
  }
5681
6252
  if (a && (!isTextMarkup(a) || pressFoundMade)) set("select-text");
5682
6253
  }
5683
6254
  pressed = e.pointerId;
5684
- if (current?.onPointerDown?.(e, hitFor(ctx, e), annotationId) === true) capture(e.pointerId);
6255
+ if (current?.onPointerDown?.(e, hit, annotationId) === true) capture(e.pointerId);
6256
+ if (reportable && pressed === e.pointerId) presses.down(e, {
6257
+ page: hit.page,
6258
+ point: hit.user,
6259
+ pointerType: pointerTypeOf(e)
6260
+ });
5685
6261
  };
5686
6262
  const onMove = (e) => {
5687
6263
  if (!e.isPrimary || foreign(e)) return;
5688
6264
  const missed = pressed === e.pointerId && e.buttons === 0;
5689
- if (missed) pressed = void 0;
6265
+ if (missed) {
6266
+ pressed = void 0;
6267
+ presses.cancel();
6268
+ } else presses.move(e);
5690
6269
  if (editingMade) {
5691
6270
  madeEdit?.onPointerMove(e, hitFor(ctx, e));
5692
6271
  if (missed) editingMade = false;
@@ -5706,12 +6285,14 @@ function createToolController$1(opts) {
5706
6285
  madeEdit?.onPointerUp(e, hitFor(ctx, e));
5707
6286
  } else current?.onPointerUp?.(e, hitFor(ctx, e));
5708
6287
  release(e.pointerId);
6288
+ presses.up(e);
5709
6289
  };
5710
6290
  const onCancel = (e) => {
5711
6291
  if (!e.isPrimary || foreign(e)) return;
5712
6292
  if (e.type === "lostpointercapture" && pressed !== e.pointerId) return;
5713
6293
  if (pressed === e.pointerId) pressed = void 0;
5714
6294
  swallow.delete(e.pointerId);
6295
+ presses.cancel();
5715
6296
  if (editingMade) {
5716
6297
  editingMade = false;
5717
6298
  madeEdit?.onPointerCancel();
@@ -5777,6 +6358,7 @@ function createToolController$1(opts) {
5777
6358
  ctx.root.addEventListener("lostpointercapture", onCancel);
5778
6359
  ctx.root.addEventListener("keydown", onKey);
5779
6360
  ctx.root.addEventListener("keydown", onEditorEscape, { capture: true });
6361
+ ctx.root.addEventListener("touchmove", onTouchMove, { passive: false });
5780
6362
  const loggedUnknown = /* @__PURE__ */ new Set();
5781
6363
  function logUnknownOnce(id) {
5782
6364
  if (loggedUnknown.has(id)) return;
@@ -5790,15 +6372,8 @@ function createToolController$1(opts) {
5790
6372
  return;
5791
6373
  }
5792
6374
  if (options) registry.merge(id, options);
5793
- if (pressed !== void 0) {
5794
- if (editingMade) madeEdit?.onPointerCancel();
5795
- else current?.onPointerCancel?.(new PointerEvent("pointercancel", {
5796
- pointerId: pressed,
5797
- isPrimary: true
5798
- }));
5799
- swallow.add(pressed);
5800
- pressed = void 0;
5801
- }
6375
+ presses.cancel();
6376
+ cancelPressed();
5802
6377
  editingMade = false;
5803
6378
  madeEdit?.reset();
5804
6379
  current?.deactivate();
@@ -5808,8 +6383,22 @@ function createToolController$1(opts) {
5808
6383
  next.activate(ctx);
5809
6384
  ctx.root.dataset.inkTool = id;
5810
6385
  ctx.root.style.cursor = next.cursor;
6386
+ applyClaim();
5811
6387
  active.set(id);
5812
6388
  }
6389
+ /** Ends the live press's gesture, if any, and keeps its release from every tool. */
6390
+ function cancelPressed() {
6391
+ if (pressed === void 0) return;
6392
+ if (editingMade) {
6393
+ editingMade = false;
6394
+ madeEdit?.onPointerCancel();
6395
+ } else current?.onPointerCancel?.(new PointerEvent("pointercancel", {
6396
+ pointerId: pressed,
6397
+ isPrimary: true
6398
+ }));
6399
+ swallow.add(pressed);
6400
+ pressed = void 0;
6401
+ }
5813
6402
  set(opts.initial ?? "select-text");
5814
6403
  if (current === void 0 && opts.initial !== void 0 && opts.initial !== "select-text") set("select-text");
5815
6404
  return {
@@ -5827,11 +6416,12 @@ function createToolController$1(opts) {
5827
6416
  return registry.readable(id);
5828
6417
  },
5829
6418
  destroy() {
6419
+ presses.destroy();
5830
6420
  madeEdit?.reset();
5831
6421
  madeEdit = void 0;
5832
6422
  current?.deactivate();
5833
- clearMade();
5834
6423
  current = void 0;
6424
+ clearMade();
5835
6425
  doc.defaultView?.removeEventListener("pointerdown", readFirst, { capture: true });
5836
6426
  doc.removeEventListener("pointerdown", readAfterEditor, { capture: true });
5837
6427
  ctx.root.removeEventListener("pointerdown", onDown, { capture: true });
@@ -5841,6 +6431,7 @@ function createToolController$1(opts) {
5841
6431
  ctx.root.removeEventListener("lostpointercapture", onCancel);
5842
6432
  ctx.root.removeEventListener("keydown", onKey);
5843
6433
  ctx.root.removeEventListener("keydown", onEditorEscape, { capture: true });
6434
+ ctx.root.removeEventListener("touchmove", onTouchMove);
5844
6435
  delete ctx.root.dataset.inkTool;
5845
6436
  ctx.root.style.cursor = originalCursor;
5846
6437
  }
@@ -5861,6 +6452,18 @@ function isViewportEnter(e, root) {
5861
6452
  if (target.matches(".ink-page[data-page]")) return true;
5862
6453
  return target.closest("[data-ink-text-layer], [data-ink-canvas-layer]") !== null;
5863
6454
  }
6455
+ function pointerTypeOf(e) {
6456
+ return e.pointerType === "touch" || e.pointerType === "pen" ? e.pointerType : "mouse";
6457
+ }
6458
+ /**
6459
+ * True when a press on `target` commits an open free-text editor (which has focus while open) or
6460
+ * closes an open Inkbar popover (a press outside it does).
6461
+ */
6462
+ function dismisses(target, doc) {
6463
+ if (doc.activeElement?.closest("[data-ink-editor]")) return true;
6464
+ const node = target instanceof Node ? target : null;
6465
+ return [...doc.querySelectorAll("[data-ink-popover]")].some((panel) => !panel.hidden && !panel.contains(node));
6466
+ }
5864
6467
  /**
5865
6468
  * True for a press on `root` itself outside its client area: on a scroll bar (or its border).
5866
6469
  * Client coordinates only, so a synthetic press gives the same answer as a real one.
@@ -5914,6 +6517,7 @@ function freehandTool(opts) {
5914
6517
  /** Adds a sample. A release reports 0 pressure, so it repeats the last sample's instead. */
5915
6518
  const sample = (s, e, release = false) => {
5916
6519
  const css = clampedCssIn(s.from.host, e);
6520
+ s.travel = Math.max(s.travel, Math.hypot(e.clientX - s.origin.x, e.clientY - s.origin.y));
5917
6521
  s.css.push(css);
5918
6522
  s.user.push(s.from.transform.fromCss(css));
5919
6523
  const p = release ? s.pressure?.[s.pressure.length - 1] : pressureOf(e);
@@ -5956,6 +6560,7 @@ function freehandTool(opts) {
5956
6560
  label: opts.label,
5957
6561
  icon: opts.icon,
5958
6562
  kind: "sticky",
6563
+ claimsTouch: true,
5959
6564
  cursor: "crosshair",
5960
6565
  styleGroup: "ink",
5961
6566
  activate(c) {
@@ -5974,7 +6579,13 @@ function freehandTool(opts) {
5974
6579
  css: [],
5975
6580
  user: [],
5976
6581
  pressure: void 0,
5977
- startedAt: Date.now()
6582
+ startedAt: Date.now(),
6583
+ pointerType: e.pointerType,
6584
+ origin: {
6585
+ x: e.clientX,
6586
+ y: e.clientY
6587
+ },
6588
+ travel: 0
5978
6589
  };
5979
6590
  sample(stroke, e);
5980
6591
  e.stopPropagation();
@@ -6005,6 +6616,7 @@ function freehandTool(opts) {
6005
6616
  const end = clampedCssIn(s.from.host, e);
6006
6617
  if (end.x !== last.x || end.y !== last.y) sample(s, e, true);
6007
6618
  clear();
6619
+ if (s.pointerType === "touch" && s.travel <= 10) return;
6008
6620
  opts.commit(ctx, {
6009
6621
  page: s.from.page,
6010
6622
  points: s.user,
@@ -8287,6 +8899,7 @@ function freetextTool() {
8287
8899
  label: "Text box",
8288
8900
  icon: Type,
8289
8901
  kind: "one-shot",
8902
+ claimsTouch: true,
8290
8903
  cursor: "text",
8291
8904
  styleGroup: "text",
8292
8905
  defaultOptions: {},
@@ -8543,6 +9156,7 @@ function redactAreaTool() {
8543
9156
  label: "Mark for redaction",
8544
9157
  icon: Square,
8545
9158
  kind: "one-shot",
9159
+ claimsTouch: true,
8546
9160
  cursor: "crosshair",
8547
9161
  styleGroup: "redact",
8548
9162
  activate(c) {
@@ -8833,6 +9447,7 @@ function shapeTool() {
8833
9447
  icon: Shapes,
8834
9448
  kind: "one-shot",
8835
9449
  cursor: "crosshair",
9450
+ claimsTouch: true,
8836
9451
  styleGroup: "shape",
8837
9452
  defaultOptions: { ...DEFAULT_SHAPE_OPTIONS },
8838
9453
  activate(c) {
@@ -9383,6 +9998,7 @@ function mountViewer(opts) {
9383
9998
  const pages = /* @__PURE__ */ new Map();
9384
9999
  let gap = opts.gap;
9385
10000
  let buffer = opts.buffer;
10001
+ let pinchZoom = opts.pinchZoom;
9386
10002
  let custom = opts.customAnnotations ?? false;
9387
10003
  let viewport;
9388
10004
  let tools;
@@ -9637,6 +10253,7 @@ function mountViewer(opts) {
9637
10253
  ...state.rotation === void 0 ? {} : { rotation: state.rotation },
9638
10254
  ...gap === void 0 ? {} : { gap },
9639
10255
  ...buffer === void 0 ? {} : { buffer },
10256
+ ...pinchZoom === void 0 ? {} : { pinchZoom },
9640
10257
  onMount: mountPage,
9641
10258
  onUpdate: (page, _host, transform) => pages.get(page)?.update(transform),
9642
10259
  onUnmount: unmountPage
@@ -9646,6 +10263,7 @@ function mountViewer(opts) {
9646
10263
  ...state.tool === void 0 ? {} : { initial: state.tool },
9647
10264
  tools: list,
9648
10265
  options: toolOptions,
10266
+ ...plugins && { onPress: (kind, press) => plugins.emitPress(kind, press) },
9649
10267
  ctx: {
9650
10268
  toolStyle,
9651
10269
  store: doc.annotations,
@@ -9731,6 +10349,7 @@ function mountViewer(opts) {
9731
10349
  teardown();
9732
10350
  if (next.gap !== void 0) gap = next.gap;
9733
10351
  if (next.buffer !== void 0) buffer = next.buffer;
10352
+ if (next.pinchZoom !== void 0) pinchZoom = next.pinchZoom;
9734
10353
  if (next.customAnnotations !== void 0) custom = next.customAnnotations;
9735
10354
  build(state);
9736
10355
  },
@@ -14501,6 +15120,6 @@ function createHighlightMenu(viewer) {
14501
15120
  return root;
14502
15121
  }
14503
15122
  //#endregion
14504
- export { ARROWHEAD_CHOICES, ARROWHEAD_ENDING, COLOR_COLUMNS, COLOR_LABELS, DASH_PATTERN, DEFAULT_CORNER_RADIUS, DEFAULT_FREETEXT_WIDTH, DEFAULT_HIGHLIGHT_OPTIONS, DEFAULT_SHAPE_SIZE, FONT_FAMILIES, FORM_LABELS, LINE_WEIGHTS, MARKUP_ICONS, MARKUP_KINDS, MARKUP_LABELS, PALETTE, SHAPE_COLUMNS, SHAPE_ICONS, SHAPE_KINDS, SHAPE_LABELS, SIGNATURE_FONTS, SIGNATURE_IMAGE_MAX_LENGTH, SIGNATURE_IMAGE_MAX_SIDE, SIGNATURE_IMAGE_TYPES, SIGNATURE_LABELS, SIGNATURE_TABS, THUMBNAIL_WIDTH, TOOL_LABELS, ZOOM_LEVELS, allTools, annotationElementFor, arrowheadChoice, attachFileKeys, attachHistoryKeys, attachViewportKeys, clampFontSize, colorMenuModel, computeCssLayout, createColorMenu, createCommandButton, createDownloadButton, createFindBar, createFocusReturn, createFormAlert, createHighlightMenu, createIcon, createImageSignature, createLineStyleMenu, createMenu, createNextPage, createOverlay, createPageCount, createPageInput, createPageMount, createPageRenderer, createPageTransform, createPluginHost, createPluginLayers, createPopover, createPrevPage, createPrintButton, createRecordList, createRecordListController, createRedo, createSearchButton, createSearchController, createSearchResults, createShapeMenu, createSidebar, createSidebarController, createSignFieldMenu, createSignatureDialog, createSignatureDraft, createSignatureMenu, createSignaturePad, createSignaturePreview, createTextLayer, createTextStyleMenu, createThumbnail, createThumbnailPainter, createThumbnails, createThumbnailsController, createToolButton, createToolController, createToolOptions, createToolbar, createToolbarSeparator, createTypedSignature, createUndo, createViewer, createViewport, createZoomIn, createZoomOut, createZoomSelect, cssRectsToUserRects, cssVariableDefaults, definePlugin, downloadDocument, drawTool, editFreeText, findAnnouncer, findCountText, fitZoomCss, focusInitialMenuItem, fontFamilyValue, freetextTool, getSelectionQuads, handleFindKey, handleMenuKeys, handleRadioKeys, handleResultsFieldKey, handleTabKeys, highlightMenuModel, highlightTool, hitFor, isBlankQuery, keepHistoryFocus, lineStyleMenuModel, menuItems, mostVisiblePageCss, mountViewer, normalizeRotation, noteTool, observeAnnotationElement, pageSelectionText, placePanel, printDocument, recordsSource, redactAreaTool, renderAnnotationContent, renderTypedSignature, searchSource, selectTextTool, selectTool, shapeMenuModel, shapeTool, shouldKeepOpenOnAnnotation, sidebarBadge, signField, signatureMenuModel, signaturePreview, signatureTool, sketchTool, textStyleMenuModel, threadDeleteLabel, threadPopoverLabel, thumbnailSize, trackToolStyle, trapTab, unknownCommand, unknownTool, viewerSearchOf, visibleRangeCss, watchDetached, withHostTools };
15123
+ export { ARROWHEAD_CHOICES, ARROWHEAD_ENDING, COLOR_COLUMNS, COLOR_LABELS, DASH_PATTERN, DEFAULT_CORNER_RADIUS, DEFAULT_FREETEXT_WIDTH, DEFAULT_HIGHLIGHT_OPTIONS, DEFAULT_SHAPE_SIZE, FONT_FAMILIES, FORM_LABELS, LINE_WEIGHTS, MARKUP_ICONS, MARKUP_KINDS, MARKUP_LABELS, PALETTE, SHAPE_COLUMNS, SHAPE_ICONS, SHAPE_KINDS, SHAPE_LABELS, SIGNATURE_FONTS, SIGNATURE_IMAGE_MAX_LENGTH, SIGNATURE_IMAGE_MAX_SIDE, SIGNATURE_IMAGE_TYPES, SIGNATURE_LABELS, SIGNATURE_TABS, THUMBNAIL_WIDTH, TOOL_LABELS, ZOOM_LEVELS, allTools, annotationElementFor, arrowheadChoice, attachFileKeys, attachHistoryKeys, attachTouchPinch, attachTrackpadPinch, attachViewportKeys, clampFontSize, colorMenuModel, computeCssLayout, createColorMenu, createCommandButton, createDownloadButton, createFindBar, createFocusReturn, createFormAlert, createHighlightMenu, createIcon, createImageSignature, createLineStyleMenu, createMenu, createNextPage, createOverlay, createPageCount, createPageInput, createPageMount, createPageRenderer, createPageTransform, createPluginHost, createPluginLayers, createPopover, createPrevPage, createPrintButton, createRecordList, createRecordListController, createRedo, createSearchButton, createSearchController, createSearchResults, createShapeMenu, createSidebar, createSidebarController, createSignFieldMenu, createSignatureDialog, createSignatureDraft, createSignatureMenu, createSignaturePad, createSignaturePreview, createTextLayer, createTextStyleMenu, createThumbnail, createThumbnailPainter, createThumbnails, createThumbnailsController, createToolButton, createToolController, createToolOptions, createToolbar, createToolbarSeparator, createTypedSignature, createUndo, createViewer, createViewport, createZoomIn, createZoomOut, createZoomPreview, createZoomSelect, cssRectsToUserRects, cssVariableDefaults, definePlugin, downloadDocument, drawTool, editFreeText, findAnnouncer, findCountText, fitZoomCss, focusInitialMenuItem, fontFamilyValue, freetextTool, getSelectionQuads, handleFindKey, handleMenuKeys, handleRadioKeys, handleResultsFieldKey, handleTabKeys, highlightMenuModel, highlightTool, hitFor, isBlankQuery, keepHistoryFocus, lineStyleMenuModel, menuItems, mostVisiblePageCss, mountViewer, normalizeRotation, noteTool, observeAnnotationElement, pageSelectionText, pinchFrame, placePanel, printDocument, recordsSource, redactAreaTool, renderAnnotationContent, renderTypedSignature, searchSource, selectTextTool, selectTool, shapeMenuModel, shapeTool, shouldKeepOpenOnAnnotation, sidebarBadge, signField, signatureMenuModel, signaturePreview, signatureTool, sketchTool, textStyleMenuModel, threadDeleteLabel, threadPopoverLabel, thumbnailSize, trackToolStyle, trapTab, unknownCommand, unknownTool, viewerSearchOf, visibleRangeCss, watchDetached, wheelFactor, withHostTools };
14505
15124
 
14506
15125
  //# sourceMappingURL=dom.mjs.map