@seamlet/astro 0.11.1 → 0.11.3

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 (2) hide show
  1. package/dist/bridge.js +102 -10
  2. package/package.json +1 -1
package/dist/bridge.js CHANGED
@@ -372,11 +372,57 @@ function createLayoutReports(document2, report) {
372
372
  };
373
373
  }
374
374
 
375
+ // src/bridge/page-presses.ts
376
+ function followPresses(document2, onRelease) {
377
+ const view = document2.defaultView;
378
+ let isPressed = false;
379
+ let releaseTimer;
380
+ const press = () => {
381
+ clearTimeout(releaseTimer);
382
+ isPressed = true;
383
+ };
384
+ const release = () => {
385
+ if (!isPressed) return;
386
+ isPressed = false;
387
+ releaseTimer = setTimeout(onRelease, 0);
388
+ };
389
+ const releaseOnMove = (event) => {
390
+ if (event.buttons === 0) release();
391
+ };
392
+ const listeners = [
393
+ ["pointerdown", press],
394
+ ["pointerup", release],
395
+ ["pointercancel", release],
396
+ ["pointermove", releaseOnMove]
397
+ ];
398
+ for (const [type, listener] of listeners) {
399
+ document2.addEventListener(type, listener, true);
400
+ }
401
+ view?.addEventListener("blur", release);
402
+ return {
403
+ isPressed: () => isPressed,
404
+ stop: () => {
405
+ clearTimeout(releaseTimer);
406
+ for (const [type, listener] of listeners) {
407
+ document2.removeEventListener(type, listener, true);
408
+ }
409
+ view?.removeEventListener("blur", release);
410
+ }
411
+ };
412
+ }
413
+
375
414
  // src/bridge/page-rendering.ts
376
415
  function createPageRenderer(options) {
377
416
  let request;
417
+ let heldPage;
418
+ const show = (html) => {
419
+ if (!options.canReplacePage()) return;
420
+ replacePageBody(options.document, html);
421
+ options.onRendered();
422
+ };
378
423
  const render2 = (content) => {
379
424
  request?.abort();
425
+ heldPage = void 0;
380
426
  const currentRequest = new AbortController();
381
427
  request = currentRequest;
382
428
  fetchRenderedPage(
@@ -384,18 +430,27 @@ function createPageRenderer(options) {
384
430
  content,
385
431
  currentRequest.signal
386
432
  ).then((html) => {
387
- if (!options.canReplacePage()) return;
388
- replacePageBody(options.document, html);
389
- options.onRendered();
433
+ if (options.isPagePressed()) {
434
+ heldPage = html;
435
+ return;
436
+ }
437
+ show(html);
390
438
  }).catch((error) => {
391
439
  if (currentRequest.signal.aborted) return;
392
440
  options.onFailed(error);
393
441
  });
394
442
  };
443
+ const showHeldPage = () => {
444
+ const html = heldPage;
445
+ heldPage = void 0;
446
+ if (html !== void 0) show(html);
447
+ };
395
448
  return {
396
449
  render: render2,
450
+ showHeldPage,
397
451
  stop: () => {
398
452
  request?.abort();
453
+ heldPage = void 0;
399
454
  }
400
455
  };
401
456
  }
@@ -426,6 +481,38 @@ function replacePageBody(document2, html) {
426
481
  restoreRevealedParts(document2, revealed);
427
482
  }
428
483
 
484
+ // src/bridge/editable-elements.ts
485
+ var OUTLINE = "outline";
486
+ var NO_OUTLINE = "none";
487
+ var IMPORTANT = "important";
488
+ var keptOutlines = /* @__PURE__ */ new WeakMap();
489
+ function makeEditable(element, editable) {
490
+ element.setAttribute("contenteditable", editable);
491
+ if (keptOutlines.has(element)) return;
492
+ const { style } = element;
493
+ keptOutlines.set(element, {
494
+ value: style.getPropertyValue(OUTLINE),
495
+ priority: style.getPropertyPriority(OUTLINE)
496
+ });
497
+ style.setProperty(OUTLINE, NO_OUTLINE, IMPORTANT);
498
+ }
499
+ function makeUneditable(element) {
500
+ element.removeAttribute("contenteditable");
501
+ const kept = keptOutlines.get(element);
502
+ if (kept === void 0) return;
503
+ keptOutlines.delete(element);
504
+ restoreOutline(element, kept);
505
+ }
506
+ function restoreOutline(element, kept) {
507
+ const { style } = element;
508
+ if (kept.value === "") {
509
+ style.removeProperty(OUTLINE);
510
+ } else {
511
+ style.setProperty(OUTLINE, kept.value, kept.priority);
512
+ }
513
+ if (style.length === 0) element.removeAttribute("style");
514
+ }
515
+
429
516
  // src/bridge/element-text.ts
430
517
  var LINE_BREAK = "\n";
431
518
  var NO_BREAK_SPACE = /\u00a0/gu;
@@ -505,7 +592,7 @@ function startInlineTextEditing(element, options) {
505
592
  element.removeEventListener("input", reportInput);
506
593
  element.removeEventListener("keydown", endOnKey);
507
594
  element.removeEventListener("blur", endOnBlur);
508
- element.removeAttribute("contenteditable");
595
+ makeUneditable(element);
509
596
  };
510
597
  let hasEnded = false;
511
598
  const end = (outcome) => {
@@ -514,7 +601,7 @@ function startInlineTextEditing(element, options) {
514
601
  stop();
515
602
  options.onEnd(outcome);
516
603
  };
517
- element.setAttribute("contenteditable", EDITABLE_AS_PLAIN_TEXT);
604
+ makeEditable(element, EDITABLE_AS_PLAIN_TEXT);
518
605
  element.addEventListener("input", reportInput);
519
606
  element.addEventListener("keydown", endOnKey);
520
607
  element.addEventListener("blur", endOnBlur);
@@ -653,7 +740,7 @@ function startRichTextEditing(element, options) {
653
740
  document2.removeEventListener("selectionchange", followSelection);
654
741
  document2.removeEventListener("scroll", scheduleReport, true);
655
742
  view?.removeEventListener("resize", scheduleReport);
656
- element.removeAttribute("contenteditable");
743
+ makeUneditable(element);
657
744
  };
658
745
  let hasEnded = false;
659
746
  const end = (outcome) => {
@@ -663,7 +750,7 @@ function startRichTextEditing(element, options) {
663
750
  options.onSelect(void 0);
664
751
  options.onEnd(outcome);
665
752
  };
666
- element.setAttribute("contenteditable", EDITABLE_AS_RICH_TEXT);
753
+ makeEditable(element, EDITABLE_AS_RICH_TEXT);
667
754
  element.addEventListener("input", reportInput);
668
755
  element.addEventListener("keydown", pressKey);
669
756
  element.addEventListener("paste", pastePlainText);
@@ -749,7 +836,7 @@ function createPageTyping(options) {
749
836
  clearTimeout(prepared.timer);
750
837
  if (!isTyped && stopEditing === void 0) {
751
838
  prepared.element.blur();
752
- prepared.element.removeAttribute("contenteditable");
839
+ makeUneditable(prepared.element);
753
840
  }
754
841
  prepared = void 0;
755
842
  };
@@ -757,7 +844,7 @@ function createPageTyping(options) {
757
844
  const isTypedAlready = element.hasAttribute("contenteditable");
758
845
  if (isTypedAlready) return;
759
846
  takePrepared(false);
760
- element.setAttribute("contenteditable", EDITABLE_VALUES[kind]);
847
+ makeEditable(element, EDITABLE_VALUES[kind]);
761
848
  element.focus({ preventScroll: true });
762
849
  const timer = setTimeout(() => {
763
850
  takePrepared(false);
@@ -823,7 +910,7 @@ function createPageTyping(options) {
823
910
  };
824
911
  return {
825
912
  prepare,
826
- isTyping: () => stopEditing !== void 0,
913
+ isTyping: () => stopEditing !== void 0 || prepared !== void 0,
827
914
  start,
828
915
  startRich,
829
916
  format: (format) => richEditing?.format(format),
@@ -864,10 +951,14 @@ function connectPage(document2, schema, send) {
864
951
  send({ type: "layout", layout: measured });
865
952
  });
866
953
  const typing = createPageTyping({ document: document2, send, onInput: layout.schedule });
954
+ const presses = followPresses(document2, () => {
955
+ renderer.showHeldPage();
956
+ });
867
957
  const renderer = createPageRenderer({
868
958
  document: document2,
869
959
  // Replacing the page under a text being typed would throw the typing away.
870
960
  canReplacePage: () => !typing.isTyping(),
961
+ isPagePressed: presses.isPressed,
871
962
  onRendered: () => {
872
963
  layout.reportNow();
873
964
  send({ type: "rendered" });
@@ -949,6 +1040,7 @@ function connectPage(document2, schema, send) {
949
1040
  stop: () => {
950
1041
  typing.stop();
951
1042
  renderer.stop();
1043
+ presses.stop();
952
1044
  layout.stop();
953
1045
  stopListening();
954
1046
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamlet/astro",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "description": "Connects an Astro site to the Seamlet CMS: the schema of its content, the preview the editor frames, and its published content.",
5
5
  "license": "MIT",
6
6
  "type": "module",