@pubwave/editor 0.1.3 → 0.2.1

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 (3) hide show
  1. package/dist/index.cjs +146 -24
  2. package/dist/index.js +146 -24
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -4854,6 +4854,89 @@ function calculateVerticalPositionFromRect(triggerRect, dropdownHeight, margin =
4854
4854
  margin
4855
4855
  );
4856
4856
  }
4857
+ function calculateHorizontalPosition(triggerLeft, triggerRight, dropdownWidth, preferredAlign = "left", margin = 8) {
4858
+ const viewportWidth = window.innerWidth;
4859
+ const triggerCenter = (triggerLeft + triggerRight) / 2;
4860
+ const spaceLeft = triggerLeft;
4861
+ const spaceRight = viewportWidth - triggerRight;
4862
+ const requiredSpaceForLeft = dropdownWidth + margin;
4863
+ const requiredSpaceForRight = dropdownWidth + margin;
4864
+ const requiredSpaceForCenter = dropdownWidth / 2 + margin;
4865
+ let align = preferredAlign;
4866
+ let left2;
4867
+ if (preferredAlign === "left") {
4868
+ left2 = triggerLeft;
4869
+ if (left2 < margin || left2 + dropdownWidth > viewportWidth - margin) {
4870
+ if (spaceRight >= requiredSpaceForRight && triggerRight + dropdownWidth <= viewportWidth - margin) {
4871
+ align = "right";
4872
+ left2 = triggerRight - dropdownWidth;
4873
+ } else if (spaceLeft >= requiredSpaceForCenter && triggerCenter - dropdownWidth / 2 >= margin) {
4874
+ align = "center";
4875
+ left2 = triggerCenter - dropdownWidth / 2;
4876
+ } else {
4877
+ if (spaceRight >= spaceLeft) {
4878
+ align = "right";
4879
+ left2 = triggerRight - dropdownWidth;
4880
+ } else {
4881
+ align = "left";
4882
+ left2 = triggerLeft;
4883
+ }
4884
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4885
+ }
4886
+ }
4887
+ } else if (preferredAlign === "center") {
4888
+ left2 = triggerCenter - dropdownWidth / 2;
4889
+ if (left2 < margin || left2 + dropdownWidth > viewportWidth - margin) {
4890
+ if (spaceRight >= requiredSpaceForRight && triggerRight + dropdownWidth <= viewportWidth - margin) {
4891
+ align = "right";
4892
+ left2 = triggerRight - dropdownWidth;
4893
+ } else if (spaceLeft >= requiredSpaceForLeft && triggerLeft + dropdownWidth <= viewportWidth - margin) {
4894
+ align = "left";
4895
+ left2 = triggerLeft;
4896
+ } else {
4897
+ if (spaceRight >= spaceLeft) {
4898
+ align = "right";
4899
+ left2 = triggerRight - dropdownWidth;
4900
+ } else {
4901
+ align = "left";
4902
+ left2 = triggerLeft;
4903
+ }
4904
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4905
+ }
4906
+ }
4907
+ } else {
4908
+ left2 = triggerRight - dropdownWidth;
4909
+ if (left2 < margin || left2 + dropdownWidth > viewportWidth - margin) {
4910
+ if (spaceLeft >= requiredSpaceForLeft && triggerLeft + dropdownWidth <= viewportWidth - margin) {
4911
+ align = "left";
4912
+ left2 = triggerLeft;
4913
+ } else if (spaceLeft >= requiredSpaceForCenter && triggerCenter - dropdownWidth / 2 >= margin) {
4914
+ align = "center";
4915
+ left2 = triggerCenter - dropdownWidth / 2;
4916
+ } else {
4917
+ if (spaceLeft >= spaceRight) {
4918
+ align = "left";
4919
+ left2 = triggerLeft;
4920
+ } else {
4921
+ align = "right";
4922
+ left2 = triggerRight - dropdownWidth;
4923
+ }
4924
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4925
+ }
4926
+ }
4927
+ }
4928
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4929
+ return { align, left: left2 };
4930
+ }
4931
+ function calculateHorizontalPositionFromRect(triggerRect, dropdownWidth, preferredAlign = "left", margin = 8) {
4932
+ return calculateHorizontalPosition(
4933
+ triggerRect.left,
4934
+ triggerRect.right,
4935
+ dropdownWidth,
4936
+ preferredAlign,
4937
+ margin
4938
+ );
4939
+ }
4857
4940
  function PositionedDropdown({
4858
4941
  isOpen,
4859
4942
  buttonRef,
@@ -4866,7 +4949,8 @@ function PositionedDropdown({
4866
4949
  onClick,
4867
4950
  "data-testid": dataTestId
4868
4951
  }) {
4869
- const [position, setPosition] = React.useState("top");
4952
+ const [verticalPosition, setVerticalPosition] = React.useState("top");
4953
+ const [horizontalPosition, setHorizontalPosition] = React.useState(null);
4870
4954
  const dropdownRef = React.useRef(null);
4871
4955
  React.useEffect(() => {
4872
4956
  if (!isOpen || !buttonRef.current) return;
@@ -4874,15 +4958,37 @@ function PositionedDropdown({
4874
4958
  if (!dropdownRef.current || !buttonRef.current) return;
4875
4959
  const buttonRect = buttonRef.current.getBoundingClientRect();
4876
4960
  const dropdownHeight = dropdownRef.current.offsetHeight || 300;
4877
- const newPosition = calculateVerticalPositionFromRect(buttonRect, dropdownHeight, margin);
4878
- setPosition(newPosition);
4961
+ const dropdownWidth = dropdownRef.current.offsetWidth || 240;
4962
+ const newVerticalPosition = calculateVerticalPositionFromRect(buttonRect, dropdownHeight, margin);
4963
+ setVerticalPosition(newVerticalPosition);
4964
+ let parentContainer = buttonRef.current.parentElement;
4965
+ while (parentContainer) {
4966
+ const style2 = window.getComputedStyle(parentContainer);
4967
+ if (style2.position === "relative" || style2.position === "absolute" || style2.position === "fixed") {
4968
+ break;
4969
+ }
4970
+ parentContainer = parentContainer.parentElement;
4971
+ }
4972
+ const horizontalPos = calculateHorizontalPositionFromRect(
4973
+ buttonRect,
4974
+ dropdownWidth,
4975
+ align,
4976
+ margin
4977
+ );
4978
+ if (parentContainer) {
4979
+ const parentRect = parentContainer.getBoundingClientRect();
4980
+ const relativeLeft = horizontalPos.left - parentRect.left;
4981
+ setHorizontalPosition({ align: horizontalPos.align, left: relativeLeft });
4982
+ } else {
4983
+ setHorizontalPosition(horizontalPos);
4984
+ }
4879
4985
  };
4880
4986
  checkPosition();
4881
4987
  const rafId = requestAnimationFrame(() => {
4882
4988
  checkPosition();
4883
4989
  });
4884
4990
  return () => cancelAnimationFrame(rafId);
4885
- }, [isOpen, buttonRef, margin]);
4991
+ }, [isOpen, buttonRef, margin, align]);
4886
4992
  React.useEffect(() => {
4887
4993
  if (!isOpen || !onClickOutside2) return;
4888
4994
  const handleClickOutside = (event) => {
@@ -4897,6 +5003,11 @@ function PositionedDropdown({
4897
5003
  }, [isOpen, onClickOutside2, buttonRef]);
4898
5004
  if (!isOpen) return null;
4899
5005
  const getHorizontalStyle = () => {
5006
+ if (horizontalPosition) {
5007
+ return {
5008
+ left: `${horizontalPosition.left}px`
5009
+ };
5010
+ }
4900
5011
  switch (align) {
4901
5012
  case "center":
4902
5013
  return {
@@ -4922,7 +5033,7 @@ function PositionedDropdown({
4922
5033
  "data-testid": dataTestId,
4923
5034
  style: {
4924
5035
  position: "absolute",
4925
- ...position === "top" ? {
5036
+ ...verticalPosition === "top" ? {
4926
5037
  bottom: "100%",
4927
5038
  marginBottom: `${margin}px`
4928
5039
  } : {
@@ -5254,6 +5365,9 @@ function LinkButton({ editor, isOpen, onToggle, onClose, selectionState }) {
5254
5365
  }
5255
5366
  }, [isOpen, currentLinkHref, editor]);
5256
5367
  React.useEffect(() => {
5368
+ if (isMobileDevice()) {
5369
+ return;
5370
+ }
5257
5371
  if (!isOpen) {
5258
5372
  tippyInstancesRef.current.forEach((instance) => instance.destroy());
5259
5373
  tippyInstancesRef.current = [];
@@ -5601,6 +5715,9 @@ function ColorPicker({ editor, onClose, buttonRef }) {
5601
5715
  }
5602
5716
  };
5603
5717
  React.useEffect(() => {
5718
+ if (isMobileDevice()) {
5719
+ return;
5720
+ }
5604
5721
  if (!pickerRef.current) return;
5605
5722
  tippyInstancesRef.current.forEach((instance) => instance.destroy());
5606
5723
  tippyInstancesRef.current = [];
@@ -5992,8 +6109,6 @@ function calculatePosition(editor, toolbarEl) {
5992
6109
  const toolbarRect = toolbarEl.getBoundingClientRect();
5993
6110
  const toolbarWidth = toolbarRect.width;
5994
6111
  const toolbarHeight = toolbarRect.height;
5995
- const centerX = (selectionLeft + selectionRight) / 2;
5996
- let left2 = centerX - toolbarWidth / 2;
5997
6112
  const selectionBottom = Math.max(start2.bottom, end2.bottom);
5998
6113
  const verticalPosition = calculateVerticalPosition(
5999
6114
  selectionTop,
@@ -6007,20 +6122,21 @@ function calculatePosition(editor, toolbarEl) {
6007
6122
  } else {
6008
6123
  top2 = selectionBottom + TOOLBAR_OFFSET;
6009
6124
  }
6125
+ const horizontalPos = calculateHorizontalPosition(
6126
+ selectionLeft,
6127
+ selectionRight,
6128
+ toolbarWidth,
6129
+ "center",
6130
+ // Default to center alignment
6131
+ TOOLBAR_OFFSET
6132
+ );
6133
+ const left2 = horizontalPos.left;
6010
6134
  const viewportWidth = window.innerWidth;
6011
6135
  const viewportHeight = window.innerHeight;
6012
- const padding = 8;
6013
- if (left2 < padding) {
6014
- left2 = padding;
6015
- } else if (left2 + toolbarWidth > viewportWidth - padding) {
6016
- left2 = viewportWidth - toolbarWidth - padding;
6017
- }
6018
- if (top2 < padding) {
6019
- top2 = padding;
6020
- } else if (top2 + toolbarHeight > viewportHeight - padding) {
6021
- top2 = viewportHeight - toolbarHeight - padding;
6022
- }
6023
- return { top: top2, left: left2, visible: true };
6136
+ const padding = TOOLBAR_OFFSET;
6137
+ const clampedLeft = Math.max(padding, Math.min(left2, viewportWidth - toolbarWidth - padding));
6138
+ const clampedTop = Math.max(padding, Math.min(top2, viewportHeight - toolbarHeight - padding));
6139
+ return { top: clampedTop, left: clampedLeft, visible: true };
6024
6140
  }
6025
6141
  function BubbleToolbar({
6026
6142
  editor,
@@ -6181,6 +6297,9 @@ function BubbleToolbar({
6181
6297
  }, [shouldShow, updatePosition]);
6182
6298
  const locale = useLocale();
6183
6299
  React.useEffect(() => {
6300
+ if (isMobileDevice()) {
6301
+ return;
6302
+ }
6184
6303
  if (!shouldShow || !position.visible || !toolbarRef.current) {
6185
6304
  tippyInstancesRef.current.forEach((instance) => instance.destroy());
6186
6305
  tippyInstancesRef.current = [];
@@ -6265,6 +6384,7 @@ function BubbleToolbar({
6265
6384
  }
6266
6385
  );
6267
6386
  }
6387
+ const MIN_WINDOW_WIDTH = 768;
6268
6388
  function getClosestBlock(target, proseMirror, editor) {
6269
6389
  if (!target || !(target instanceof Node)) return null;
6270
6390
  try {
@@ -6310,14 +6430,16 @@ function BlockHandle({ editor }) {
6310
6430
  const [isDragging, setIsDragging] = React.useState(false);
6311
6431
  const [position, setPosition] = React.useState({ top: 0 });
6312
6432
  const [isMobile, setIsMobile] = React.useState(false);
6433
+ const [isWindowTooSmall, setIsWindowTooSmall] = React.useState(false);
6313
6434
  React.useEffect(() => {
6314
- const checkMobile = () => {
6435
+ const checkDeviceAndWindow = () => {
6315
6436
  setIsMobile(isMobileDevice());
6437
+ setIsWindowTooSmall(window.innerWidth < MIN_WINDOW_WIDTH);
6316
6438
  };
6317
- checkMobile();
6318
- window.addEventListener("resize", checkMobile);
6439
+ checkDeviceAndWindow();
6440
+ window.addEventListener("resize", checkDeviceAndWindow);
6319
6441
  return () => {
6320
- window.removeEventListener("resize", checkMobile);
6442
+ window.removeEventListener("resize", checkDeviceAndWindow);
6321
6443
  };
6322
6444
  }, []);
6323
6445
  const updatePosition = React.useCallback(() => {
@@ -6552,7 +6674,7 @@ function BlockHandle({ editor }) {
6552
6674
  }
6553
6675
  setVisible(false);
6554
6676
  }, []);
6555
- if (isMobile || !visible) return null;
6677
+ if (isMobile || isWindowTooSmall || !visible) return null;
6556
6678
  return /* @__PURE__ */ jsxRuntime.jsxs(
6557
6679
  "div",
6558
6680
  {
package/dist/index.js CHANGED
@@ -4852,6 +4852,89 @@ function calculateVerticalPositionFromRect(triggerRect, dropdownHeight, margin =
4852
4852
  margin
4853
4853
  );
4854
4854
  }
4855
+ function calculateHorizontalPosition(triggerLeft, triggerRight, dropdownWidth, preferredAlign = "left", margin = 8) {
4856
+ const viewportWidth = window.innerWidth;
4857
+ const triggerCenter = (triggerLeft + triggerRight) / 2;
4858
+ const spaceLeft = triggerLeft;
4859
+ const spaceRight = viewportWidth - triggerRight;
4860
+ const requiredSpaceForLeft = dropdownWidth + margin;
4861
+ const requiredSpaceForRight = dropdownWidth + margin;
4862
+ const requiredSpaceForCenter = dropdownWidth / 2 + margin;
4863
+ let align = preferredAlign;
4864
+ let left2;
4865
+ if (preferredAlign === "left") {
4866
+ left2 = triggerLeft;
4867
+ if (left2 < margin || left2 + dropdownWidth > viewportWidth - margin) {
4868
+ if (spaceRight >= requiredSpaceForRight && triggerRight + dropdownWidth <= viewportWidth - margin) {
4869
+ align = "right";
4870
+ left2 = triggerRight - dropdownWidth;
4871
+ } else if (spaceLeft >= requiredSpaceForCenter && triggerCenter - dropdownWidth / 2 >= margin) {
4872
+ align = "center";
4873
+ left2 = triggerCenter - dropdownWidth / 2;
4874
+ } else {
4875
+ if (spaceRight >= spaceLeft) {
4876
+ align = "right";
4877
+ left2 = triggerRight - dropdownWidth;
4878
+ } else {
4879
+ align = "left";
4880
+ left2 = triggerLeft;
4881
+ }
4882
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4883
+ }
4884
+ }
4885
+ } else if (preferredAlign === "center") {
4886
+ left2 = triggerCenter - dropdownWidth / 2;
4887
+ if (left2 < margin || left2 + dropdownWidth > viewportWidth - margin) {
4888
+ if (spaceRight >= requiredSpaceForRight && triggerRight + dropdownWidth <= viewportWidth - margin) {
4889
+ align = "right";
4890
+ left2 = triggerRight - dropdownWidth;
4891
+ } else if (spaceLeft >= requiredSpaceForLeft && triggerLeft + dropdownWidth <= viewportWidth - margin) {
4892
+ align = "left";
4893
+ left2 = triggerLeft;
4894
+ } else {
4895
+ if (spaceRight >= spaceLeft) {
4896
+ align = "right";
4897
+ left2 = triggerRight - dropdownWidth;
4898
+ } else {
4899
+ align = "left";
4900
+ left2 = triggerLeft;
4901
+ }
4902
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4903
+ }
4904
+ }
4905
+ } else {
4906
+ left2 = triggerRight - dropdownWidth;
4907
+ if (left2 < margin || left2 + dropdownWidth > viewportWidth - margin) {
4908
+ if (spaceLeft >= requiredSpaceForLeft && triggerLeft + dropdownWidth <= viewportWidth - margin) {
4909
+ align = "left";
4910
+ left2 = triggerLeft;
4911
+ } else if (spaceLeft >= requiredSpaceForCenter && triggerCenter - dropdownWidth / 2 >= margin) {
4912
+ align = "center";
4913
+ left2 = triggerCenter - dropdownWidth / 2;
4914
+ } else {
4915
+ if (spaceLeft >= spaceRight) {
4916
+ align = "left";
4917
+ left2 = triggerLeft;
4918
+ } else {
4919
+ align = "right";
4920
+ left2 = triggerRight - dropdownWidth;
4921
+ }
4922
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4923
+ }
4924
+ }
4925
+ }
4926
+ left2 = Math.max(margin, Math.min(left2, viewportWidth - dropdownWidth - margin));
4927
+ return { align, left: left2 };
4928
+ }
4929
+ function calculateHorizontalPositionFromRect(triggerRect, dropdownWidth, preferredAlign = "left", margin = 8) {
4930
+ return calculateHorizontalPosition(
4931
+ triggerRect.left,
4932
+ triggerRect.right,
4933
+ dropdownWidth,
4934
+ preferredAlign,
4935
+ margin
4936
+ );
4937
+ }
4855
4938
  function PositionedDropdown({
4856
4939
  isOpen,
4857
4940
  buttonRef,
@@ -4864,7 +4947,8 @@ function PositionedDropdown({
4864
4947
  onClick,
4865
4948
  "data-testid": dataTestId
4866
4949
  }) {
4867
- const [position, setPosition] = useState("top");
4950
+ const [verticalPosition, setVerticalPosition] = useState("top");
4951
+ const [horizontalPosition, setHorizontalPosition] = useState(null);
4868
4952
  const dropdownRef = useRef(null);
4869
4953
  useEffect(() => {
4870
4954
  if (!isOpen || !buttonRef.current) return;
@@ -4872,15 +4956,37 @@ function PositionedDropdown({
4872
4956
  if (!dropdownRef.current || !buttonRef.current) return;
4873
4957
  const buttonRect = buttonRef.current.getBoundingClientRect();
4874
4958
  const dropdownHeight = dropdownRef.current.offsetHeight || 300;
4875
- const newPosition = calculateVerticalPositionFromRect(buttonRect, dropdownHeight, margin);
4876
- setPosition(newPosition);
4959
+ const dropdownWidth = dropdownRef.current.offsetWidth || 240;
4960
+ const newVerticalPosition = calculateVerticalPositionFromRect(buttonRect, dropdownHeight, margin);
4961
+ setVerticalPosition(newVerticalPosition);
4962
+ let parentContainer = buttonRef.current.parentElement;
4963
+ while (parentContainer) {
4964
+ const style2 = window.getComputedStyle(parentContainer);
4965
+ if (style2.position === "relative" || style2.position === "absolute" || style2.position === "fixed") {
4966
+ break;
4967
+ }
4968
+ parentContainer = parentContainer.parentElement;
4969
+ }
4970
+ const horizontalPos = calculateHorizontalPositionFromRect(
4971
+ buttonRect,
4972
+ dropdownWidth,
4973
+ align,
4974
+ margin
4975
+ );
4976
+ if (parentContainer) {
4977
+ const parentRect = parentContainer.getBoundingClientRect();
4978
+ const relativeLeft = horizontalPos.left - parentRect.left;
4979
+ setHorizontalPosition({ align: horizontalPos.align, left: relativeLeft });
4980
+ } else {
4981
+ setHorizontalPosition(horizontalPos);
4982
+ }
4877
4983
  };
4878
4984
  checkPosition();
4879
4985
  const rafId = requestAnimationFrame(() => {
4880
4986
  checkPosition();
4881
4987
  });
4882
4988
  return () => cancelAnimationFrame(rafId);
4883
- }, [isOpen, buttonRef, margin]);
4989
+ }, [isOpen, buttonRef, margin, align]);
4884
4990
  useEffect(() => {
4885
4991
  if (!isOpen || !onClickOutside2) return;
4886
4992
  const handleClickOutside = (event) => {
@@ -4895,6 +5001,11 @@ function PositionedDropdown({
4895
5001
  }, [isOpen, onClickOutside2, buttonRef]);
4896
5002
  if (!isOpen) return null;
4897
5003
  const getHorizontalStyle = () => {
5004
+ if (horizontalPosition) {
5005
+ return {
5006
+ left: `${horizontalPosition.left}px`
5007
+ };
5008
+ }
4898
5009
  switch (align) {
4899
5010
  case "center":
4900
5011
  return {
@@ -4920,7 +5031,7 @@ function PositionedDropdown({
4920
5031
  "data-testid": dataTestId,
4921
5032
  style: {
4922
5033
  position: "absolute",
4923
- ...position === "top" ? {
5034
+ ...verticalPosition === "top" ? {
4924
5035
  bottom: "100%",
4925
5036
  marginBottom: `${margin}px`
4926
5037
  } : {
@@ -5252,6 +5363,9 @@ function LinkButton({ editor, isOpen, onToggle, onClose, selectionState }) {
5252
5363
  }
5253
5364
  }, [isOpen, currentLinkHref, editor]);
5254
5365
  useEffect(() => {
5366
+ if (isMobileDevice()) {
5367
+ return;
5368
+ }
5255
5369
  if (!isOpen) {
5256
5370
  tippyInstancesRef.current.forEach((instance) => instance.destroy());
5257
5371
  tippyInstancesRef.current = [];
@@ -5599,6 +5713,9 @@ function ColorPicker({ editor, onClose, buttonRef }) {
5599
5713
  }
5600
5714
  };
5601
5715
  useEffect(() => {
5716
+ if (isMobileDevice()) {
5717
+ return;
5718
+ }
5602
5719
  if (!pickerRef.current) return;
5603
5720
  tippyInstancesRef.current.forEach((instance) => instance.destroy());
5604
5721
  tippyInstancesRef.current = [];
@@ -5990,8 +6107,6 @@ function calculatePosition(editor, toolbarEl) {
5990
6107
  const toolbarRect = toolbarEl.getBoundingClientRect();
5991
6108
  const toolbarWidth = toolbarRect.width;
5992
6109
  const toolbarHeight = toolbarRect.height;
5993
- const centerX = (selectionLeft + selectionRight) / 2;
5994
- let left2 = centerX - toolbarWidth / 2;
5995
6110
  const selectionBottom = Math.max(start2.bottom, end2.bottom);
5996
6111
  const verticalPosition = calculateVerticalPosition(
5997
6112
  selectionTop,
@@ -6005,20 +6120,21 @@ function calculatePosition(editor, toolbarEl) {
6005
6120
  } else {
6006
6121
  top2 = selectionBottom + TOOLBAR_OFFSET;
6007
6122
  }
6123
+ const horizontalPos = calculateHorizontalPosition(
6124
+ selectionLeft,
6125
+ selectionRight,
6126
+ toolbarWidth,
6127
+ "center",
6128
+ // Default to center alignment
6129
+ TOOLBAR_OFFSET
6130
+ );
6131
+ const left2 = horizontalPos.left;
6008
6132
  const viewportWidth = window.innerWidth;
6009
6133
  const viewportHeight = window.innerHeight;
6010
- const padding = 8;
6011
- if (left2 < padding) {
6012
- left2 = padding;
6013
- } else if (left2 + toolbarWidth > viewportWidth - padding) {
6014
- left2 = viewportWidth - toolbarWidth - padding;
6015
- }
6016
- if (top2 < padding) {
6017
- top2 = padding;
6018
- } else if (top2 + toolbarHeight > viewportHeight - padding) {
6019
- top2 = viewportHeight - toolbarHeight - padding;
6020
- }
6021
- return { top: top2, left: left2, visible: true };
6134
+ const padding = TOOLBAR_OFFSET;
6135
+ const clampedLeft = Math.max(padding, Math.min(left2, viewportWidth - toolbarWidth - padding));
6136
+ const clampedTop = Math.max(padding, Math.min(top2, viewportHeight - toolbarHeight - padding));
6137
+ return { top: clampedTop, left: clampedLeft, visible: true };
6022
6138
  }
6023
6139
  function BubbleToolbar({
6024
6140
  editor,
@@ -6179,6 +6295,9 @@ function BubbleToolbar({
6179
6295
  }, [shouldShow, updatePosition]);
6180
6296
  const locale = useLocale();
6181
6297
  useEffect(() => {
6298
+ if (isMobileDevice()) {
6299
+ return;
6300
+ }
6182
6301
  if (!shouldShow || !position.visible || !toolbarRef.current) {
6183
6302
  tippyInstancesRef.current.forEach((instance) => instance.destroy());
6184
6303
  tippyInstancesRef.current = [];
@@ -6263,6 +6382,7 @@ function BubbleToolbar({
6263
6382
  }
6264
6383
  );
6265
6384
  }
6385
+ const MIN_WINDOW_WIDTH = 768;
6266
6386
  function getClosestBlock(target, proseMirror, editor) {
6267
6387
  if (!target || !(target instanceof Node)) return null;
6268
6388
  try {
@@ -6308,14 +6428,16 @@ function BlockHandle({ editor }) {
6308
6428
  const [isDragging, setIsDragging] = useState(false);
6309
6429
  const [position, setPosition] = useState({ top: 0 });
6310
6430
  const [isMobile, setIsMobile] = useState(false);
6431
+ const [isWindowTooSmall, setIsWindowTooSmall] = useState(false);
6311
6432
  useEffect(() => {
6312
- const checkMobile = () => {
6433
+ const checkDeviceAndWindow = () => {
6313
6434
  setIsMobile(isMobileDevice());
6435
+ setIsWindowTooSmall(window.innerWidth < MIN_WINDOW_WIDTH);
6314
6436
  };
6315
- checkMobile();
6316
- window.addEventListener("resize", checkMobile);
6437
+ checkDeviceAndWindow();
6438
+ window.addEventListener("resize", checkDeviceAndWindow);
6317
6439
  return () => {
6318
- window.removeEventListener("resize", checkMobile);
6440
+ window.removeEventListener("resize", checkDeviceAndWindow);
6319
6441
  };
6320
6442
  }, []);
6321
6443
  const updatePosition = useCallback(() => {
@@ -6550,7 +6672,7 @@ function BlockHandle({ editor }) {
6550
6672
  }
6551
6673
  setVisible(false);
6552
6674
  }, []);
6553
- if (isMobile || !visible) return null;
6675
+ if (isMobile || isWindowTooSmall || !visible) return null;
6554
6676
  return /* @__PURE__ */ jsxs(
6555
6677
  "div",
6556
6678
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pubwave/editor",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "A Notion-level block editor built with React and Tiptap",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",