@underverse-ui/underverse 1.0.141 → 1.0.142

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@underverse-ui/underverse",
3
- "version": "1.0.141",
3
+ "version": "1.0.142",
4
4
  "sourceEntry": "src/index.ts",
5
5
  "totalExports": 232,
6
6
  "exports": [
package/dist/index.cjs CHANGED
@@ -25431,6 +25431,7 @@ var import_extension_typography = __toESM(require("@tiptap/extension-typography"
25431
25431
  var import_extension_subscript = __toESM(require("@tiptap/extension-subscript"), 1);
25432
25432
  var import_extension_superscript = __toESM(require("@tiptap/extension-superscript"), 1);
25433
25433
  var import_extension_horizontal_rule = __toESM(require("@tiptap/extension-horizontal-rule"), 1);
25434
+ var import_extension_gapcursor = __toESM(require("@tiptap/extension-gapcursor"), 1);
25434
25435
  var import_lowlight = require("lowlight");
25435
25436
 
25436
25437
  // src/components/UEditor/slash-command.tsx
@@ -26206,7 +26207,6 @@ var import_core8 = require("@tiptap/core");
26206
26207
  var import_react54 = require("@tiptap/react");
26207
26208
  var import_jsx_runtime81 = require("react/jsx-runtime");
26208
26209
  var MIN_IMAGE_SIZE_PX = 40;
26209
- var AXIS_LOCK_THRESHOLD_PX = 4;
26210
26210
  var IMAGE_LAYOUTS = /* @__PURE__ */ new Set(["block", "left", "right"]);
26211
26211
  var IMAGE_WIDTH_PRESETS = /* @__PURE__ */ new Set(["sm", "md", "lg"]);
26212
26212
  function toNullableNumber(value) {
@@ -26247,6 +26247,41 @@ function getImageLayoutStyles(layout) {
26247
26247
  }
26248
26248
  return {};
26249
26249
  }
26250
+ function getAspectRatio({
26251
+ img,
26252
+ widthAttr,
26253
+ heightAttr,
26254
+ fallbackWidth,
26255
+ fallbackHeight
26256
+ }) {
26257
+ if (widthAttr && heightAttr) return widthAttr / heightAttr;
26258
+ if (img.naturalWidth > 0 && img.naturalHeight > 0) return img.naturalWidth / img.naturalHeight;
26259
+ if (fallbackWidth > 0 && fallbackHeight > 0) return fallbackWidth / fallbackHeight;
26260
+ return 1;
26261
+ }
26262
+ function sizeFromWidth(width, aspect, maxWidth) {
26263
+ let nextW = clamp8(width, MIN_IMAGE_SIZE_PX, maxWidth);
26264
+ let nextH = nextW / aspect;
26265
+ if (nextH < MIN_IMAGE_SIZE_PX) {
26266
+ nextH = MIN_IMAGE_SIZE_PX;
26267
+ nextW = clamp8(nextH * aspect, MIN_IMAGE_SIZE_PX, maxWidth);
26268
+ nextH = nextW / aspect;
26269
+ }
26270
+ return { width: nextW, height: nextH };
26271
+ }
26272
+ function sizeFromHeight(height, aspect, maxWidth) {
26273
+ let nextH = Math.max(MIN_IMAGE_SIZE_PX, height);
26274
+ let nextW = nextH * aspect;
26275
+ if (nextW > maxWidth) {
26276
+ nextW = maxWidth;
26277
+ nextH = nextW / aspect;
26278
+ }
26279
+ if (nextW < MIN_IMAGE_SIZE_PX) {
26280
+ nextW = MIN_IMAGE_SIZE_PX;
26281
+ nextH = nextW / aspect;
26282
+ }
26283
+ return { width: nextW, height: nextH };
26284
+ }
26250
26285
  function ResizableImageNodeView(props) {
26251
26286
  const { node, selected, updateAttributes, editor, getPos } = props;
26252
26287
  const wrapperRef = (0, import_react53.useRef)(null);
@@ -26257,7 +26292,6 @@ function ResizableImageNodeView(props) {
26257
26292
  const heightAttr = toNullableNumber(node.attrs["height"]);
26258
26293
  const textAlign = String(node.attrs["textAlign"] ?? "");
26259
26294
  const imageLayout = parseImageLayout(node.attrs["imageLayout"]);
26260
- const preserveAspectByDefault = imageLayout === "left" || imageLayout === "right";
26261
26295
  const dragStateRef = (0, import_react53.useRef)(null);
26262
26296
  (0, import_react53.useEffect)(() => {
26263
26297
  const img = imgRef.current;
@@ -26281,7 +26315,13 @@ function ResizableImageNodeView(props) {
26281
26315
  const maxW = editorEl ? editorEl.getBoundingClientRect().width : Number.POSITIVE_INFINITY;
26282
26316
  const startW = Math.max(MIN_IMAGE_SIZE_PX, rect.width);
26283
26317
  const startH = Math.max(MIN_IMAGE_SIZE_PX, rect.height);
26284
- const aspect = startH > 0 ? startW / startH : 1;
26318
+ const aspect = getAspectRatio({
26319
+ img,
26320
+ widthAttr,
26321
+ heightAttr,
26322
+ fallbackWidth: startW,
26323
+ fallbackHeight: startH
26324
+ });
26285
26325
  dragStateRef.current = {
26286
26326
  pointerId: event.pointerId,
26287
26327
  startX: event.clientX,
@@ -26290,7 +26330,6 @@ function ResizableImageNodeView(props) {
26290
26330
  startH,
26291
26331
  lastW: startW,
26292
26332
  lastH: startH,
26293
- axis: null,
26294
26333
  aspect,
26295
26334
  maxW: Math.max(MIN_IMAGE_SIZE_PX, maxW)
26296
26335
  };
@@ -26304,24 +26343,9 @@ function ResizableImageNodeView(props) {
26304
26343
  if (event.pointerId !== drag.pointerId) return;
26305
26344
  const dx = event.clientX - drag.startX;
26306
26345
  const dy = event.clientY - drag.startY;
26307
- let nextW = drag.startW;
26308
- let nextH = drag.startH;
26309
- const shouldPreserveAspect = preserveAspectByDefault ? !event.ctrlKey : event.ctrlKey;
26310
- if (shouldPreserveAspect) {
26311
- if (Math.abs(dx) >= Math.abs(dy)) {
26312
- nextW = clamp8(drag.startW + dx, MIN_IMAGE_SIZE_PX, drag.maxW);
26313
- nextH = clamp8(nextW / drag.aspect, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
26314
- } else {
26315
- nextH = clamp8(drag.startH + dy, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
26316
- nextW = clamp8(nextH * drag.aspect, MIN_IMAGE_SIZE_PX, drag.maxW);
26317
- }
26318
- } else {
26319
- if (!drag.axis && (Math.abs(dx) > AXIS_LOCK_THRESHOLD_PX || Math.abs(dy) > AXIS_LOCK_THRESHOLD_PX)) {
26320
- drag.axis = Math.abs(dx) >= Math.abs(dy) ? "x" : "y";
26321
- }
26322
- if (drag.axis === "x") nextW = clamp8(drag.startW + dx, MIN_IMAGE_SIZE_PX, drag.maxW);
26323
- if (drag.axis === "y") nextH = clamp8(drag.startH + dy, MIN_IMAGE_SIZE_PX, Number.POSITIVE_INFINITY);
26324
- }
26346
+ const nextSize = Math.abs(dx) >= Math.abs(dy) ? sizeFromWidth(drag.startW + dx, drag.aspect, drag.maxW) : sizeFromHeight(drag.startH + dy, drag.aspect, drag.maxW);
26347
+ const nextW = nextSize.width;
26348
+ const nextH = nextSize.height;
26325
26349
  drag.lastW = nextW;
26326
26350
  drag.lastH = nextH;
26327
26351
  img.style.width = `${Math.round(nextW)}px`;
@@ -27244,6 +27268,7 @@ function buildUEditorExtensions({
27244
27268
  }
27245
27269
  }),
27246
27270
  import_extension_horizontal_rule.default,
27271
+ import_extension_gapcursor.default,
27247
27272
  import_extension_link.default.configure({
27248
27273
  openOnClick: false,
27249
27274
  protocols: ["http", "https", "mailto", "tel"],
@@ -27593,6 +27618,43 @@ function isSelectedImage(editor) {
27593
27618
  const { selection } = editor.state;
27594
27619
  return selection instanceof import_state6.NodeSelection && selection.node.type.name === "image";
27595
27620
  }
27621
+ function toPositiveNumber(value) {
27622
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
27623
+ if (typeof value === "string") {
27624
+ const parsed = Number.parseInt(value, 10);
27625
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
27626
+ }
27627
+ return null;
27628
+ }
27629
+ function getImageElementAtSelection(editor, pos) {
27630
+ const nodeDom = editor.view.nodeDOM(pos);
27631
+ if (!(nodeDom instanceof HTMLElement)) return null;
27632
+ if (nodeDom.tagName === "IMG") return nodeDom;
27633
+ return nodeDom.querySelector("img");
27634
+ }
27635
+ function getImageAspectRatio(editor, attrs, pos) {
27636
+ const widthAttr = toPositiveNumber(attrs.width);
27637
+ const heightAttr = toPositiveNumber(attrs.height);
27638
+ if (widthAttr && heightAttr) return widthAttr / heightAttr;
27639
+ const imageElement = typeof pos === "number" ? getImageElementAtSelection(editor, pos) : null;
27640
+ if (!imageElement) return null;
27641
+ if (imageElement.naturalWidth > 0 && imageElement.naturalHeight > 0) {
27642
+ return imageElement.naturalWidth / imageElement.naturalHeight;
27643
+ }
27644
+ const rect = imageElement.getBoundingClientRect();
27645
+ if (rect.width > 0 && rect.height > 0) return rect.width / rect.height;
27646
+ const width = toPositiveNumber(imageElement.getAttribute("width")) ?? toPositiveNumber(imageElement.style.width);
27647
+ const height = toPositiveNumber(imageElement.getAttribute("height")) ?? toPositiveNumber(imageElement.style.height);
27648
+ return width && height ? width / height : null;
27649
+ }
27650
+ function getImagePresetAttributes(editor, width, preset, attrs, pos) {
27651
+ const aspect = getImageAspectRatio(editor, attrs, pos);
27652
+ return {
27653
+ width,
27654
+ height: aspect ? Math.round(width / aspect) : toPositiveNumber(attrs.height),
27655
+ imageWidthPreset: preset
27656
+ };
27657
+ }
27596
27658
  function applyImageLayout(editor, layout) {
27597
27659
  const { state, view } = editor;
27598
27660
  const { selection, schema } = state;
@@ -27627,15 +27689,15 @@ function applyImageWidthPreset(editor, preset) {
27627
27689
  const mode = attrs.imageLayout === "left" || attrs.imageLayout === "right" ? "wrap" : "block";
27628
27690
  const width = IMAGE_WIDTHS_BY_LAYOUT[mode][preset];
27629
27691
  if (!isSelectedImage(editor)) {
27630
- editor.chain().focus().updateAttributes("image", { width, imageWidthPreset: preset }).run();
27692
+ editor.chain().focus().updateAttributes("image", getImagePresetAttributes(editor, width, preset, attrs)).run();
27631
27693
  return;
27632
27694
  }
27633
27695
  const { state, view } = editor;
27634
27696
  const selection = state.selection;
27697
+ const nextAttrs = getImagePresetAttributes(editor, width, preset, selection.node.attrs, selection.from);
27635
27698
  const transaction = state.tr.setNodeMarkup(selection.from, void 0, {
27636
27699
  ...selection.node.attrs,
27637
- width,
27638
- imageWidthPreset: preset
27700
+ ...nextAttrs
27639
27701
  });
27640
27702
  view.dispatch(transaction.scrollIntoView());
27641
27703
  view.focus();
@@ -29562,10 +29624,22 @@ var CustomBubbleMenu = ({
29562
29624
  setIsVisible(false);
29563
29625
  return;
29564
29626
  }
29565
- const start = view.coordsAtPos(from);
29566
- const end = view.coordsAtPos(to);
29567
- const left = (start.left + end.left) / 2;
29568
- const top = start.top - BUBBLE_MENU_OFFSET;
29627
+ let start;
29628
+ let end;
29629
+ try {
29630
+ start = view.coordsAtPos(from);
29631
+ end = view.coordsAtPos(to);
29632
+ } catch {
29633
+ clearShowTimeout();
29634
+ setIsVisible(false);
29635
+ return;
29636
+ }
29637
+ const viewportPadding = 8;
29638
+ const left = Math.min(
29639
+ window.innerWidth - viewportPadding,
29640
+ Math.max(viewportPadding, (start.left + end.left) / 2)
29641
+ );
29642
+ const top = Math.max(viewportPadding, start.top - BUBBLE_MENU_OFFSET);
29569
29643
  setPosition({ top, left });
29570
29644
  if (keepOpenRef.current) {
29571
29645
  clearShowTimeout();
@@ -29587,11 +29661,17 @@ var CustomBubbleMenu = ({
29587
29661
  editor.on("selectionUpdate", updatePosition);
29588
29662
  editor.on("focus", updatePosition);
29589
29663
  editor.on("blur", handleBlur);
29664
+ editor.on("transaction", updatePosition);
29665
+ editor.on("update", updatePosition);
29666
+ const animationFrameId = requestAnimationFrame(updatePosition);
29590
29667
  return () => {
29668
+ cancelAnimationFrame(animationFrameId);
29591
29669
  clearShowTimeout();
29592
29670
  editor.off("selectionUpdate", updatePosition);
29593
29671
  editor.off("focus", updatePosition);
29594
29672
  editor.off("blur", handleBlur);
29673
+ editor.off("transaction", updatePosition);
29674
+ editor.off("update", updatePosition);
29595
29675
  };
29596
29676
  }, [editor]);
29597
29677
  if (!isVisible) return null;
@@ -29601,7 +29681,7 @@ var CustomBubbleMenu = ({
29601
29681
  {
29602
29682
  ref: menuRef,
29603
29683
  "data-popover": true,
29604
- className: "fixed z-99999 flex rounded-xl border border-border/40 bg-card text-card-foreground shadow-lg backdrop-blur-sm overflow-hidden animate-in fade-in-0 zoom-in-95",
29684
+ className: "fixed z-[99999] flex rounded-xl border border-border/40 bg-card text-card-foreground shadow-lg backdrop-blur-sm overflow-hidden animate-in fade-in-0 zoom-in-95",
29605
29685
  style: {
29606
29686
  top: `${position.top}px`,
29607
29687
  left: `${position.left}px`,
@@ -35513,6 +35593,17 @@ var UEDITOR_PROSEMIRROR_CLASS_NAME = cn(
35513
35593
  "[&_.is-editor-empty]:before:float-left",
35514
35594
  "[&_.is-editor-empty]:before:pointer-events-none",
35515
35595
  "[&_.is-editor-empty]:before:h-0",
35596
+ "[&_.ProseMirror-gapcursor]:pointer-events-none",
35597
+ "[&_.ProseMirror-gapcursor]:absolute",
35598
+ "[&_.ProseMirror-gapcursor]:hidden",
35599
+ "[&_.ProseMirror-gapcursor:after]:content-['']",
35600
+ "[&_.ProseMirror-gapcursor:after]:block",
35601
+ "[&_.ProseMirror-gapcursor:after]:absolute",
35602
+ "[&_.ProseMirror-gapcursor:after]:top-[-2px]",
35603
+ "[&_.ProseMirror-gapcursor:after]:w-8",
35604
+ "[&_.ProseMirror-gapcursor:after]:border-t-2",
35605
+ "[&_.ProseMirror-gapcursor:after]:border-primary",
35606
+ "[&.ProseMirror-focused_.ProseMirror-gapcursor]:block",
35516
35607
  "[&_ul[data-type='taskList']]:list-none",
35517
35608
  "[&_ul[data-type='taskList']]:pl-0",
35518
35609
  "[&_ul[data-type='taskList']_li]:flex",