hono-decks 0.4.5 → 0.5.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/advanced.js CHANGED
@@ -707,6 +707,7 @@ function renderPresentationScript(nonce) {
707
707
  let isTransitioning = false;
708
708
  let pendingNavigation = null;
709
709
  let transitionToken = 0;
710
+ let touchStart = null;
710
711
 
711
712
  function fitDeck() {
712
713
  if (!(stage instanceof HTMLElement) || !(deck instanceof HTMLElement)) return;
@@ -1039,6 +1040,33 @@ function renderPresentationScript(nonce) {
1039
1040
  if (action === "overview") toggleOverview();
1040
1041
  }
1041
1042
 
1043
+ function isInteractiveTouchTarget(target) {
1044
+ return target instanceof Element && Boolean(target.closest("a,button,input,select,textarea,[contenteditable],[role='button']"));
1045
+ }
1046
+
1047
+ function handleTouchStart(event) {
1048
+ if (event.touches.length !== 1 || isInteractiveTouchTarget(event.target)) {
1049
+ touchStart = null;
1050
+ return;
1051
+ }
1052
+ const touch = event.touches[0];
1053
+ touchStart = { x: touch.clientX, y: touch.clientY };
1054
+ }
1055
+
1056
+ function handleTouchEnd(event) {
1057
+ if (!touchStart || event.changedTouches.length !== 1) {
1058
+ touchStart = null;
1059
+ return;
1060
+ }
1061
+ const touch = event.changedTouches[0];
1062
+ const deltaX = touch.clientX - touchStart.x;
1063
+ const deltaY = touch.clientY - touchStart.y;
1064
+ touchStart = null;
1065
+ const threshold = Math.max(48, window.innerWidth * 0.08);
1066
+ if (Math.abs(deltaX) < threshold || Math.abs(deltaX) <= Math.abs(deltaY) * 1.25) return;
1067
+ handleCommand(deltaX < 0 ? "next" : "previous");
1068
+ }
1069
+
1042
1070
  async function toggleFullscreen() {
1043
1071
  if (document.fullscreenElement) {
1044
1072
  await document.exitFullscreen?.();
@@ -1062,6 +1090,9 @@ function renderPresentationScript(nonce) {
1062
1090
  if (event.key === "p") handleCommand("presenter");
1063
1091
  if (event.key === "o") handleCommand("overview");
1064
1092
  });
1093
+ document.addEventListener("touchstart", handleTouchStart, { passive: true });
1094
+ document.addEventListener("touchend", handleTouchEnd, { passive: true });
1095
+ document.addEventListener("touchcancel", () => { touchStart = null; }, { passive: true });
1065
1096
 
1066
1097
  window.addEventListener("message", (event) => {
1067
1098
  const message = event.data;
@@ -2469,10 +2500,25 @@ async function renderDeckExternalEmbedResponse(input) {
2469
2500
  mountPath,
2470
2501
  title: deck.meta.title ?? slug
2471
2502
  }, input.document, input.options.document);
2503
+ const viewerOptions = typeof input.options.viewer === "function" ? await input.options.viewer(input.context) : input.options.viewer;
2504
+ const controls = viewerOptions?.controls === void 0 ? { items: (_defaults, context) => [{
2505
+ type: "link",
2506
+ key: "open-viewer",
2507
+ href: context.meta.paths.viewer,
2508
+ label: "Open full viewer in new tab",
2509
+ icon: "external-link",
2510
+ attributes: {
2511
+ "aria-label": "Open full viewer in new tab",
2512
+ "data-hono-decks-viewer-link": true,
2513
+ target: "_blank",
2514
+ rel: "noreferrer"
2515
+ }
2516
+ }] } : viewerOptions.controls;
2472
2517
  const viewer = await createDeckViewerEmbed({
2473
2518
  deck,
2474
2519
  mountPath,
2475
- ...typeof input.options.viewer === "function" ? await input.options.viewer(input.context) : input.options.viewer,
2520
+ ...viewerOptions,
2521
+ controls,
2476
2522
  availablePages: input.availablePages,
2477
2523
  nonce: document.nonce
2478
2524
  });
package/dist/node.js CHANGED
@@ -3130,6 +3130,7 @@ function renderPresentationScript(nonce) {
3130
3130
  let isTransitioning = false;
3131
3131
  let pendingNavigation = null;
3132
3132
  let transitionToken = 0;
3133
+ let touchStart = null;
3133
3134
 
3134
3135
  function fitDeck() {
3135
3136
  if (!(stage instanceof HTMLElement) || !(deck instanceof HTMLElement)) return;
@@ -3462,6 +3463,33 @@ function renderPresentationScript(nonce) {
3462
3463
  if (action === "overview") toggleOverview();
3463
3464
  }
3464
3465
 
3466
+ function isInteractiveTouchTarget(target) {
3467
+ return target instanceof Element && Boolean(target.closest("a,button,input,select,textarea,[contenteditable],[role='button']"));
3468
+ }
3469
+
3470
+ function handleTouchStart(event) {
3471
+ if (event.touches.length !== 1 || isInteractiveTouchTarget(event.target)) {
3472
+ touchStart = null;
3473
+ return;
3474
+ }
3475
+ const touch = event.touches[0];
3476
+ touchStart = { x: touch.clientX, y: touch.clientY };
3477
+ }
3478
+
3479
+ function handleTouchEnd(event) {
3480
+ if (!touchStart || event.changedTouches.length !== 1) {
3481
+ touchStart = null;
3482
+ return;
3483
+ }
3484
+ const touch = event.changedTouches[0];
3485
+ const deltaX = touch.clientX - touchStart.x;
3486
+ const deltaY = touch.clientY - touchStart.y;
3487
+ touchStart = null;
3488
+ const threshold = Math.max(48, window.innerWidth * 0.08);
3489
+ if (Math.abs(deltaX) < threshold || Math.abs(deltaX) <= Math.abs(deltaY) * 1.25) return;
3490
+ handleCommand(deltaX < 0 ? "next" : "previous");
3491
+ }
3492
+
3465
3493
  async function toggleFullscreen() {
3466
3494
  if (document.fullscreenElement) {
3467
3495
  await document.exitFullscreen?.();
@@ -3485,6 +3513,9 @@ function renderPresentationScript(nonce) {
3485
3513
  if (event.key === "p") handleCommand("presenter");
3486
3514
  if (event.key === "o") handleCommand("overview");
3487
3515
  });
3516
+ document.addEventListener("touchstart", handleTouchStart, { passive: true });
3517
+ document.addEventListener("touchend", handleTouchEnd, { passive: true });
3518
+ document.addEventListener("touchcancel", () => { touchStart = null; }, { passive: true });
3488
3519
 
3489
3520
  window.addEventListener("message", (event) => {
3490
3521
  const message = event.data;
@@ -4829,10 +4860,25 @@ async function renderDeckExternalEmbedResponse(input) {
4829
4860
  mountPath,
4830
4861
  title: deck.meta.title ?? slug
4831
4862
  }, input.document, input.options.document);
4863
+ const viewerOptions = typeof input.options.viewer === "function" ? await input.options.viewer(input.context) : input.options.viewer;
4864
+ const controls = viewerOptions?.controls === void 0 ? { items: (_defaults, context) => [{
4865
+ type: "link",
4866
+ key: "open-viewer",
4867
+ href: context.meta.paths.viewer,
4868
+ label: "Open full viewer in new tab",
4869
+ icon: "external-link",
4870
+ attributes: {
4871
+ "aria-label": "Open full viewer in new tab",
4872
+ "data-hono-decks-viewer-link": true,
4873
+ target: "_blank",
4874
+ rel: "noreferrer"
4875
+ }
4876
+ }] } : viewerOptions.controls;
4832
4877
  const viewer = await createDeckViewerEmbed({
4833
4878
  deck,
4834
4879
  mountPath,
4835
- ...typeof input.options.viewer === "function" ? await input.options.viewer(input.context) : input.options.viewer,
4880
+ ...viewerOptions,
4881
+ controls,
4836
4882
  availablePages: input.availablePages,
4837
4883
  nonce: document.nonce
4838
4884
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-decks",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "Slide decks for Hono and Cloudflare Workers",
5
5
  "keywords": [
6
6
  "cloudflare-workers",