@ohhwells/bridge 0.1.36-next.46 → 0.1.36-next.48

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/index.cjs CHANGED
@@ -4464,7 +4464,7 @@ function ItemActionToolbar({
4464
4464
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
4465
4465
  ToolbarActionTooltip,
4466
4466
  {
4467
- label: "Add link",
4467
+ label: "Edit link",
4468
4468
  side: tooltipSide,
4469
4469
  buttonProps: {
4470
4470
  onMouseDown: (e) => {
@@ -6010,6 +6010,87 @@ function clearHrefKeyHover(anchor) {
6010
6010
  function isInsideNavigationItem(el) {
6011
6011
  return getNavigationItemAnchor(el) !== null;
6012
6012
  }
6013
+ function getNavigationRoot(el) {
6014
+ const explicit = el.closest("[data-ohw-nav-root]");
6015
+ if (explicit) return explicit;
6016
+ return el.closest("nav, footer, aside");
6017
+ }
6018
+ function findFooterItemGroup(item) {
6019
+ const footer = item.closest("footer");
6020
+ if (!footer) return null;
6021
+ let node = item.parentElement;
6022
+ while (node && node !== footer) {
6023
+ const hasDirectNavItems = Array.from(
6024
+ node.querySelectorAll(":scope > [data-ohw-href-key]")
6025
+ ).some(isNavigationItem);
6026
+ if (hasDirectNavItems) return node;
6027
+ node = node.parentElement;
6028
+ }
6029
+ return null;
6030
+ }
6031
+ function isNavigationRoot(el) {
6032
+ return el.hasAttribute("data-ohw-nav-root") || el.matches("nav, footer, aside");
6033
+ }
6034
+ function isInferredFooterGroup(el) {
6035
+ const footer = el.closest("footer");
6036
+ if (!footer || el === footer) return false;
6037
+ return Array.from(el.querySelectorAll(":scope > [data-ohw-href-key]")).some(isNavigationItem);
6038
+ }
6039
+ function isNavigationContainer(el) {
6040
+ return el.hasAttribute("data-ohw-nav-container") || isNavigationRoot(el) || isInferredFooterGroup(el);
6041
+ }
6042
+ function getNavigationSelectionParent(el) {
6043
+ if (isNavigationItem(el)) {
6044
+ const explicit = el.closest("[data-ohw-nav-container]");
6045
+ if (explicit) return explicit;
6046
+ const footerGroup = findFooterItemGroup(el);
6047
+ if (footerGroup) return footerGroup;
6048
+ return getNavigationRoot(el);
6049
+ }
6050
+ if (el.hasAttribute("data-ohw-nav-container") || isInferredFooterGroup(el)) {
6051
+ return getNavigationRoot(el);
6052
+ }
6053
+ return null;
6054
+ }
6055
+ function placeCaretAtPoint(el, x, y) {
6056
+ const selection = window.getSelection();
6057
+ if (!selection) return;
6058
+ if (typeof document.caretRangeFromPoint === "function") {
6059
+ const range = document.caretRangeFromPoint(x, y);
6060
+ if (range && el.contains(range.startContainer)) {
6061
+ selection.removeAllRanges();
6062
+ selection.addRange(range);
6063
+ return;
6064
+ }
6065
+ }
6066
+ const caretPositionFromPoint = document.caretPositionFromPoint;
6067
+ if (typeof caretPositionFromPoint === "function") {
6068
+ const position = caretPositionFromPoint(x, y);
6069
+ if (position && el.contains(position.offsetNode)) {
6070
+ const range = document.createRange();
6071
+ range.setStart(position.offsetNode, position.offset);
6072
+ range.collapse(true);
6073
+ selection.removeAllRanges();
6074
+ selection.addRange(range);
6075
+ }
6076
+ }
6077
+ }
6078
+ function selectAllTextInEditable(el) {
6079
+ const selection = window.getSelection();
6080
+ if (!selection) return;
6081
+ const range = document.createRange();
6082
+ range.selectNodeContents(el);
6083
+ selection.removeAllRanges();
6084
+ selection.addRange(range);
6085
+ }
6086
+ function getNavigationLabelEditable(target) {
6087
+ const editable = target.closest('[data-ohw-editable="text"]');
6088
+ if (!editable) return null;
6089
+ const hrefCtx = getHrefKeyFromElement(editable);
6090
+ const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
6091
+ if (!navAnchor) return null;
6092
+ return { editable, navAnchor };
6093
+ }
6013
6094
  function collectSections() {
6014
6095
  return collectSectionsFromDom();
6015
6096
  }
@@ -6490,6 +6571,8 @@ function OhhwellsBridge() {
6490
6571
  });
6491
6572
  const selectRef = (0, import_react6.useRef)(() => {
6492
6573
  });
6574
+ const selectFrameRef = (0, import_react6.useRef)(() => {
6575
+ });
6493
6576
  const deselectRef = (0, import_react6.useRef)(() => {
6494
6577
  });
6495
6578
  const reselectNavigationItemRef = (0, import_react6.useRef)(() => {
@@ -6780,7 +6863,24 @@ function OhhwellsBridge() {
6780
6863
  setToolbarShowEditLink(false);
6781
6864
  setActiveCommands(/* @__PURE__ */ new Set());
6782
6865
  }, [deactivate]);
6783
- const activate = (0, import_react6.useCallback)((el) => {
6866
+ const selectFrame = (0, import_react6.useCallback)((el) => {
6867
+ if (!isNavigationContainer(el)) return;
6868
+ if (activeElRef.current) deactivate();
6869
+ selectedElRef.current = el;
6870
+ clearHrefKeyHover(el);
6871
+ setHoveredItemRect(null);
6872
+ hoveredItemElRef.current = null;
6873
+ siblingHintElRef.current = null;
6874
+ setSiblingHintRect(null);
6875
+ setIsItemDragging(false);
6876
+ setReorderHrefKey(null);
6877
+ setReorderDragDisabled(false);
6878
+ setToolbarVariant("select-frame");
6879
+ setToolbarRect(el.getBoundingClientRect());
6880
+ setToolbarShowEditLink(false);
6881
+ setActiveCommands(/* @__PURE__ */ new Set());
6882
+ }, [deactivate]);
6883
+ const activate = (0, import_react6.useCallback)((el, options) => {
6784
6884
  if (activeElRef.current === el) return;
6785
6885
  selectedElRef.current = null;
6786
6886
  deactivate();
@@ -6798,6 +6898,9 @@ function OhhwellsBridge() {
6798
6898
  activeElRef.current = el;
6799
6899
  originalContentRef.current = el.innerHTML;
6800
6900
  el.focus();
6901
+ if (options?.caretX !== void 0 && options?.caretY !== void 0) {
6902
+ placeCaretAtPoint(el, options.caretX, options.caretY);
6903
+ }
6801
6904
  setToolbarShowEditLink(Boolean(getHrefKeyFromElement(el)));
6802
6905
  const navAnchor = getNavigationItemAnchor(el);
6803
6906
  if (navAnchor) {
@@ -6815,6 +6918,7 @@ function OhhwellsBridge() {
6815
6918
  activateRef.current = activate;
6816
6919
  deactivateRef.current = deactivate;
6817
6920
  selectRef.current = select;
6921
+ selectFrameRef.current = selectFrame;
6818
6922
  deselectRef.current = deselect;
6819
6923
  (0, import_react6.useLayoutEffect)(() => {
6820
6924
  if (!subdomain || isEditMode) {
@@ -7076,7 +7180,8 @@ function OhhwellsBridge() {
7076
7180
  e.preventDefault();
7077
7181
  e.stopPropagation();
7078
7182
  if (selectedElRef.current === navAnchor) {
7079
- activateRef.current(editable);
7183
+ if (e.detail >= 2) return;
7184
+ activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
7080
7185
  return;
7081
7186
  }
7082
7187
  selectRef.current(navAnchor);
@@ -7095,6 +7200,15 @@ function OhhwellsBridge() {
7095
7200
  selectRef.current(hrefAnchor);
7096
7201
  return;
7097
7202
  }
7203
+ const selectedContainer = selectedElRef.current;
7204
+ if (selectedContainer && isNavigationContainer(selectedContainer)) {
7205
+ const navItem = getNavigationItemAnchor(target);
7206
+ if (!navItem && (selectedContainer === target || selectedContainer.contains(target))) {
7207
+ e.preventDefault();
7208
+ e.stopPropagation();
7209
+ return;
7210
+ }
7211
+ }
7098
7212
  if (activeElRef.current) {
7099
7213
  const sel = window.getSelection();
7100
7214
  if (sel && !sel.isCollapsed) {
@@ -7120,6 +7234,28 @@ function OhhwellsBridge() {
7120
7234
  deselectRef.current();
7121
7235
  deactivateRef.current();
7122
7236
  };
7237
+ const handleDblClick = (e) => {
7238
+ const target = e.target;
7239
+ if (target.closest("[data-ohw-toolbar]")) return;
7240
+ if (target.closest("[data-ohw-state-toggle]")) return;
7241
+ if (target.closest("[data-ohw-max-badge]")) return;
7242
+ if (isInsideLinkEditor(target)) return;
7243
+ if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
7244
+ return;
7245
+ }
7246
+ const navLabel = getNavigationLabelEditable(target);
7247
+ if (!navLabel) return;
7248
+ const { editable } = navLabel;
7249
+ e.preventDefault();
7250
+ e.stopPropagation();
7251
+ if (activeElRef.current !== editable) {
7252
+ activateRef.current(editable);
7253
+ }
7254
+ requestAnimationFrame(() => {
7255
+ selectAllTextInEditable(editable);
7256
+ refreshActiveCommandsRef.current();
7257
+ });
7258
+ };
7123
7259
  const handleMouseOver = (e) => {
7124
7260
  const target = e.target;
7125
7261
  const navAnchor = getNavigationItemAnchor(target);
@@ -7693,12 +7829,26 @@ function OhhwellsBridge() {
7693
7829
  };
7694
7830
  window.addEventListener("message", handleDeactivate);
7695
7831
  const handleKeyDown = (e) => {
7832
+ if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
7833
+ const navAnchor = getNavigationItemAnchor(activeElRef.current);
7834
+ if (navAnchor) {
7835
+ e.preventDefault();
7836
+ selectAllTextInEditable(activeElRef.current);
7837
+ refreshActiveCommandsRef.current();
7838
+ return;
7839
+ }
7840
+ }
7696
7841
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
7697
7842
  setLinkPopoverRef.current(null);
7698
7843
  return;
7699
7844
  }
7700
7845
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
7701
- deselectRef.current();
7846
+ const parent = getNavigationSelectionParent(selectedElRef.current);
7847
+ if (parent) {
7848
+ selectFrameRef.current(parent);
7849
+ } else {
7850
+ deselectRef.current();
7851
+ }
7702
7852
  return;
7703
7853
  }
7704
7854
  if (e.key === "Escape" && activeElRef.current) {
@@ -7937,7 +8087,17 @@ function OhhwellsBridge() {
7937
8087
  return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
7938
8088
  });
7939
8089
  if (textEditable) {
7940
- activateRef.current(textEditable);
8090
+ const hrefCtx = getHrefKeyFromElement(textEditable);
8091
+ const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
8092
+ if (navAnchor) {
8093
+ if (selectedElRef.current === navAnchor) {
8094
+ activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
8095
+ } else {
8096
+ selectRef.current(navAnchor);
8097
+ }
8098
+ return;
8099
+ }
8100
+ activateRef.current(textEditable, { caretX: clientX, caretY: clientY });
7941
8101
  return;
7942
8102
  }
7943
8103
  deactivateRef.current();
@@ -7961,6 +8121,7 @@ function OhhwellsBridge() {
7961
8121
  };
7962
8122
  window.addEventListener("resize", handleViewportResize, { passive: true });
7963
8123
  document.addEventListener("click", handleClick, true);
8124
+ document.addEventListener("dblclick", handleDblClick, true);
7964
8125
  document.addEventListener("paste", handlePaste, true);
7965
8126
  document.addEventListener("input", handleInput, true);
7966
8127
  document.addEventListener("mouseover", handleMouseOver, true);
@@ -7975,6 +8136,7 @@ function OhhwellsBridge() {
7975
8136
  window.addEventListener("scroll", handleScroll, true);
7976
8137
  return () => {
7977
8138
  document.removeEventListener("click", handleClick, true);
8139
+ document.removeEventListener("dblclick", handleDblClick, true);
7978
8140
  document.removeEventListener("paste", handlePaste, true);
7979
8141
  document.removeEventListener("input", handleInput, true);
7980
8142
  document.removeEventListener("mouseover", handleMouseOver, true);
@@ -8119,25 +8281,25 @@ function OhhwellsBridge() {
8119
8281
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
8120
8282
  siblingHintRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
8121
8283
  hoveredItemRect && !siblingHintRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
8122
- toolbarRect && toolbarVariant === "link-action" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8284
+ toolbarRect && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8123
8285
  ItemInteractionLayer,
8124
8286
  {
8125
8287
  rect: toolbarRect,
8126
8288
  elRef: glowElRef,
8127
8289
  state: isItemDragging ? "dragging" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
8128
- showHandle: Boolean(reorderHrefKey),
8290
+ showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey),
8129
8291
  dragDisabled: reorderDragDisabled,
8130
8292
  dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
8131
8293
  onDragHandleDragStart: handleItemDragStart,
8132
8294
  onDragHandleDragEnd: handleItemDragEnd,
8133
- toolbar: isItemDragging ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8295
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8134
8296
  ItemActionToolbar,
8135
8297
  {
8136
8298
  onEditLink: openLinkPopoverForSelected,
8137
8299
  onAddItem: handleAddNavigationItem,
8138
8300
  addItemDisabled: false
8139
8301
  }
8140
- )
8302
+ ) : void 0
8141
8303
  }
8142
8304
  ),
8143
8305
  toolbarRect && toolbarVariant === "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [