@blankdotpage/cake 0.1.3 → 0.1.5

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.
@@ -56,6 +56,7 @@ export declare class CakeEngine {
56
56
  private spellCheckEnabled;
57
57
  private extensionsRoot;
58
58
  private placeholderRoot;
59
+ private resizeObserver;
59
60
  private lastFocusRect;
60
61
  private verticalNavGoalX;
61
62
  private lastRenderPerf;
@@ -88,6 +89,8 @@ export declare class CakeEngine {
88
89
  private selectionDragState;
89
90
  private pointerDownPosition;
90
91
  private hasMovedSincePointerDown;
92
+ private lastTouchTime;
93
+ private isTouchDevice;
91
94
  constructor(options: EngineOptions);
92
95
  destroy(): void;
93
96
  setReadOnly(readOnly: boolean): void;
@@ -125,7 +128,7 @@ export declare class CakeEngine {
125
128
  private render;
126
129
  private isEmptyParagraphDoc;
127
130
  private updatePlaceholder;
128
- private syncPlaceholderPadding;
131
+ private syncPlaceholderPosition;
129
132
  private updateContentRootAttributes;
130
133
  private applySelection;
131
134
  private handleSelectionChange;
package/dist/index.cjs CHANGED
@@ -7627,6 +7627,7 @@ class CakeEngine {
7627
7627
  this.lastSelectionRects = null;
7628
7628
  this.extensionsRoot = null;
7629
7629
  this.placeholderRoot = null;
7630
+ this.resizeObserver = null;
7630
7631
  this.lastFocusRect = null;
7631
7632
  this.verticalNavGoalX = null;
7632
7633
  this.lastRenderPerf = null;
@@ -7662,6 +7663,7 @@ class CakeEngine {
7662
7663
  this.selectionDragState = null;
7663
7664
  this.pointerDownPosition = null;
7664
7665
  this.hasMovedSincePointerDown = false;
7666
+ this.lastTouchTime = 0;
7665
7667
  this.container = options.container;
7666
7668
  this.extensions = options.extensions ?? bundledExtensions;
7667
7669
  this.runtime = createRuntime(this.extensions);
@@ -7695,6 +7697,11 @@ class CakeEngine {
7695
7697
  }
7696
7698
  return target instanceof Node && (target === this.contentRoot || this.contentRoot.contains(target));
7697
7699
  }
7700
+ // Detect if this is a touch-primary device (mobile/tablet)
7701
+ // We check for touch support AND coarse pointer to exclude laptops with touchscreens
7702
+ isTouchDevice() {
7703
+ return "ontouchstart" in window && window.matchMedia("(pointer: coarse)").matches;
7704
+ }
7698
7705
  destroy() {
7699
7706
  this.detachListeners();
7700
7707
  this.uninstallCaretRangeFromPointShim();
@@ -7889,6 +7896,11 @@ class CakeEngine {
7889
7896
  );
7890
7897
  this.container.addEventListener("scroll", this.handleScrollBound);
7891
7898
  window.addEventListener("resize", this.handleResizeBound);
7899
+ this.resizeObserver = new ResizeObserver(() => {
7900
+ this.syncPlaceholderPosition();
7901
+ this.scheduleOverlayUpdate();
7902
+ });
7903
+ this.resizeObserver.observe(this.container);
7892
7904
  this.container.addEventListener("click", this.handleClickBound);
7893
7905
  this.container.addEventListener("keydown", this.handleKeyDownBound);
7894
7906
  this.container.addEventListener("paste", this.handlePasteBound);
@@ -7920,6 +7932,7 @@ class CakeEngine {
7920
7932
  this.contentRoot.removeEventListener("dragend", this.handleDragEndBound);
7921
7933
  }
7922
7934
  detachListeners() {
7935
+ var _a;
7923
7936
  this.container.removeEventListener(
7924
7937
  "beforeinput",
7925
7938
  this.handleBeforeInputBound
@@ -7939,6 +7952,8 @@ class CakeEngine {
7939
7952
  );
7940
7953
  this.container.removeEventListener("scroll", this.handleScrollBound);
7941
7954
  window.removeEventListener("resize", this.handleResizeBound);
7955
+ (_a = this.resizeObserver) == null ? void 0 : _a.disconnect();
7956
+ this.resizeObserver = null;
7942
7957
  this.container.removeEventListener("click", this.handleClickBound);
7943
7958
  this.container.removeEventListener("keydown", this.handleKeyDownBound);
7944
7959
  this.container.removeEventListener("paste", this.handlePasteBound);
@@ -8047,6 +8062,9 @@ class CakeEngine {
8047
8062
  }
8048
8063
  this.contentRoot = document.createElement("div");
8049
8064
  this.contentRoot.className = "cake-content";
8065
+ if (this.isTouchDevice()) {
8066
+ this.contentRoot.classList.add("cake-touch-mode");
8067
+ }
8050
8068
  this.updateContentRootAttributes();
8051
8069
  const overlay = this.ensureOverlayRoot();
8052
8070
  const extensionsRoot = this.ensureExtensionsRoot();
@@ -8117,6 +8135,8 @@ class CakeEngine {
8117
8135
  if (!this.placeholderRoot) {
8118
8136
  this.placeholderRoot = document.createElement("div");
8119
8137
  this.placeholderRoot.className = "cake-placeholder";
8138
+ this.placeholderRoot.style.position = "absolute";
8139
+ this.placeholderRoot.style.pointerEvents = "none";
8120
8140
  }
8121
8141
  if (!shouldShow) {
8122
8142
  if (this.placeholderRoot.isConnected) {
@@ -8126,20 +8146,21 @@ class CakeEngine {
8126
8146
  return;
8127
8147
  }
8128
8148
  this.placeholderRoot.textContent = placeholderText ?? "";
8129
- this.syncPlaceholderPadding();
8130
8149
  if (!this.placeholderRoot.isConnected) {
8131
8150
  this.container.prepend(this.placeholderRoot);
8132
8151
  }
8152
+ this.syncPlaceholderPosition();
8133
8153
  }
8134
- syncPlaceholderPadding() {
8135
- if (!this.placeholderRoot) {
8154
+ syncPlaceholderPosition() {
8155
+ if (!this.placeholderRoot || !this.contentRoot) {
8136
8156
  return;
8137
8157
  }
8138
- const style = window.getComputedStyle(this.container);
8139
- this.placeholderRoot.style.paddingTop = style.paddingTop;
8140
- this.placeholderRoot.style.paddingRight = style.paddingRight;
8141
- this.placeholderRoot.style.paddingBottom = style.paddingBottom;
8142
- this.placeholderRoot.style.paddingLeft = style.paddingLeft;
8158
+ const containerRect = this.container.getBoundingClientRect();
8159
+ const contentRect = this.contentRoot.getBoundingClientRect();
8160
+ this.placeholderRoot.style.top = `${contentRect.top - containerRect.top}px`;
8161
+ this.placeholderRoot.style.left = `${contentRect.left - containerRect.left}px`;
8162
+ this.placeholderRoot.style.width = `${contentRect.width}px`;
8163
+ this.placeholderRoot.style.height = `${contentRect.height}px`;
8143
8164
  }
8144
8165
  updateContentRootAttributes() {
8145
8166
  if (!this.contentRoot) {
@@ -10074,6 +10095,19 @@ class CakeEngine {
10074
10095
  if (!this.overlayRoot || !this.contentRoot) {
10075
10096
  return;
10076
10097
  }
10098
+ if (!this.hasFocus()) {
10099
+ this.updateCaret(null);
10100
+ this.syncSelectionRects([]);
10101
+ return;
10102
+ }
10103
+ const isRecentTouch = Date.now() - this.lastTouchTime < 2e3;
10104
+ if (this.isTouchDevice() || isRecentTouch) {
10105
+ this.contentRoot.classList.add("cake-touch-mode");
10106
+ this.updateCaret(null);
10107
+ this.syncSelectionRects([]);
10108
+ return;
10109
+ }
10110
+ this.contentRoot.classList.remove("cake-touch-mode");
10077
10111
  const lines = getDocLines(this.state.doc);
10078
10112
  const geometry = getSelectionGeometry({
10079
10113
  root: this.contentRoot,
@@ -10309,9 +10343,7 @@ class CakeEngine {
10309
10343
  return;
10310
10344
  }
10311
10345
  if (event.pointerType === "touch") {
10312
- this.ignoreTouchNativeSelectionUntil = performance.now() + 750;
10313
- this.suppressSelectionChangeForTick();
10314
- event.preventDefault();
10346
+ this.lastTouchTime = Date.now();
10315
10347
  return;
10316
10348
  }
10317
10349
  const selection = this.state.selection;
package/dist/index.js CHANGED
@@ -7625,6 +7625,7 @@ class CakeEngine {
7625
7625
  this.lastSelectionRects = null;
7626
7626
  this.extensionsRoot = null;
7627
7627
  this.placeholderRoot = null;
7628
+ this.resizeObserver = null;
7628
7629
  this.lastFocusRect = null;
7629
7630
  this.verticalNavGoalX = null;
7630
7631
  this.lastRenderPerf = null;
@@ -7660,6 +7661,7 @@ class CakeEngine {
7660
7661
  this.selectionDragState = null;
7661
7662
  this.pointerDownPosition = null;
7662
7663
  this.hasMovedSincePointerDown = false;
7664
+ this.lastTouchTime = 0;
7663
7665
  this.container = options.container;
7664
7666
  this.extensions = options.extensions ?? bundledExtensions;
7665
7667
  this.runtime = createRuntime(this.extensions);
@@ -7693,6 +7695,11 @@ class CakeEngine {
7693
7695
  }
7694
7696
  return target instanceof Node && (target === this.contentRoot || this.contentRoot.contains(target));
7695
7697
  }
7698
+ // Detect if this is a touch-primary device (mobile/tablet)
7699
+ // We check for touch support AND coarse pointer to exclude laptops with touchscreens
7700
+ isTouchDevice() {
7701
+ return "ontouchstart" in window && window.matchMedia("(pointer: coarse)").matches;
7702
+ }
7696
7703
  destroy() {
7697
7704
  this.detachListeners();
7698
7705
  this.uninstallCaretRangeFromPointShim();
@@ -7887,6 +7894,11 @@ class CakeEngine {
7887
7894
  );
7888
7895
  this.container.addEventListener("scroll", this.handleScrollBound);
7889
7896
  window.addEventListener("resize", this.handleResizeBound);
7897
+ this.resizeObserver = new ResizeObserver(() => {
7898
+ this.syncPlaceholderPosition();
7899
+ this.scheduleOverlayUpdate();
7900
+ });
7901
+ this.resizeObserver.observe(this.container);
7890
7902
  this.container.addEventListener("click", this.handleClickBound);
7891
7903
  this.container.addEventListener("keydown", this.handleKeyDownBound);
7892
7904
  this.container.addEventListener("paste", this.handlePasteBound);
@@ -7918,6 +7930,7 @@ class CakeEngine {
7918
7930
  this.contentRoot.removeEventListener("dragend", this.handleDragEndBound);
7919
7931
  }
7920
7932
  detachListeners() {
7933
+ var _a;
7921
7934
  this.container.removeEventListener(
7922
7935
  "beforeinput",
7923
7936
  this.handleBeforeInputBound
@@ -7937,6 +7950,8 @@ class CakeEngine {
7937
7950
  );
7938
7951
  this.container.removeEventListener("scroll", this.handleScrollBound);
7939
7952
  window.removeEventListener("resize", this.handleResizeBound);
7953
+ (_a = this.resizeObserver) == null ? void 0 : _a.disconnect();
7954
+ this.resizeObserver = null;
7940
7955
  this.container.removeEventListener("click", this.handleClickBound);
7941
7956
  this.container.removeEventListener("keydown", this.handleKeyDownBound);
7942
7957
  this.container.removeEventListener("paste", this.handlePasteBound);
@@ -8045,6 +8060,9 @@ class CakeEngine {
8045
8060
  }
8046
8061
  this.contentRoot = document.createElement("div");
8047
8062
  this.contentRoot.className = "cake-content";
8063
+ if (this.isTouchDevice()) {
8064
+ this.contentRoot.classList.add("cake-touch-mode");
8065
+ }
8048
8066
  this.updateContentRootAttributes();
8049
8067
  const overlay = this.ensureOverlayRoot();
8050
8068
  const extensionsRoot = this.ensureExtensionsRoot();
@@ -8115,6 +8133,8 @@ class CakeEngine {
8115
8133
  if (!this.placeholderRoot) {
8116
8134
  this.placeholderRoot = document.createElement("div");
8117
8135
  this.placeholderRoot.className = "cake-placeholder";
8136
+ this.placeholderRoot.style.position = "absolute";
8137
+ this.placeholderRoot.style.pointerEvents = "none";
8118
8138
  }
8119
8139
  if (!shouldShow) {
8120
8140
  if (this.placeholderRoot.isConnected) {
@@ -8124,20 +8144,21 @@ class CakeEngine {
8124
8144
  return;
8125
8145
  }
8126
8146
  this.placeholderRoot.textContent = placeholderText ?? "";
8127
- this.syncPlaceholderPadding();
8128
8147
  if (!this.placeholderRoot.isConnected) {
8129
8148
  this.container.prepend(this.placeholderRoot);
8130
8149
  }
8150
+ this.syncPlaceholderPosition();
8131
8151
  }
8132
- syncPlaceholderPadding() {
8133
- if (!this.placeholderRoot) {
8152
+ syncPlaceholderPosition() {
8153
+ if (!this.placeholderRoot || !this.contentRoot) {
8134
8154
  return;
8135
8155
  }
8136
- const style = window.getComputedStyle(this.container);
8137
- this.placeholderRoot.style.paddingTop = style.paddingTop;
8138
- this.placeholderRoot.style.paddingRight = style.paddingRight;
8139
- this.placeholderRoot.style.paddingBottom = style.paddingBottom;
8140
- this.placeholderRoot.style.paddingLeft = style.paddingLeft;
8156
+ const containerRect = this.container.getBoundingClientRect();
8157
+ const contentRect = this.contentRoot.getBoundingClientRect();
8158
+ this.placeholderRoot.style.top = `${contentRect.top - containerRect.top}px`;
8159
+ this.placeholderRoot.style.left = `${contentRect.left - containerRect.left}px`;
8160
+ this.placeholderRoot.style.width = `${contentRect.width}px`;
8161
+ this.placeholderRoot.style.height = `${contentRect.height}px`;
8141
8162
  }
8142
8163
  updateContentRootAttributes() {
8143
8164
  if (!this.contentRoot) {
@@ -10072,6 +10093,19 @@ class CakeEngine {
10072
10093
  if (!this.overlayRoot || !this.contentRoot) {
10073
10094
  return;
10074
10095
  }
10096
+ if (!this.hasFocus()) {
10097
+ this.updateCaret(null);
10098
+ this.syncSelectionRects([]);
10099
+ return;
10100
+ }
10101
+ const isRecentTouch = Date.now() - this.lastTouchTime < 2e3;
10102
+ if (this.isTouchDevice() || isRecentTouch) {
10103
+ this.contentRoot.classList.add("cake-touch-mode");
10104
+ this.updateCaret(null);
10105
+ this.syncSelectionRects([]);
10106
+ return;
10107
+ }
10108
+ this.contentRoot.classList.remove("cake-touch-mode");
10075
10109
  const lines = getDocLines(this.state.doc);
10076
10110
  const geometry = getSelectionGeometry({
10077
10111
  root: this.contentRoot,
@@ -10307,9 +10341,7 @@ class CakeEngine {
10307
10341
  return;
10308
10342
  }
10309
10343
  if (event.pointerType === "touch") {
10310
- this.ignoreTouchNativeSelectionUntil = performance.now() + 750;
10311
- this.suppressSelectionChangeForTick();
10312
- event.preventDefault();
10344
+ this.lastTouchTime = Date.now();
10313
10345
  return;
10314
10346
  }
10315
10347
  const selection = this.state.selection;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blankdotpage/cake",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",