@ohhwells/bridge 0.1.104 → 0.1.106

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.js CHANGED
@@ -10911,9 +10911,18 @@ function getNavbarDrawerContainer() {
10911
10911
  }
10912
10912
  function isNavbarListContainerVisible(el) {
10913
10913
  if (el.hasAttribute("hidden")) return false;
10914
+ if (el.closest("[hidden]")) return false;
10914
10915
  if (el.getClientRects().length === 0) return false;
10915
10916
  const style = window.getComputedStyle(el);
10916
- return style.display !== "none" && style.visibility !== "hidden";
10917
+ if (style.display === "none" || style.visibility === "hidden") return false;
10918
+ let parent = el.parentElement;
10919
+ while (parent && parent !== document.documentElement) {
10920
+ if (parent.hasAttribute("hidden")) return false;
10921
+ const ps = window.getComputedStyle(parent);
10922
+ if (ps.display === "none" || ps.visibility === "hidden") return false;
10923
+ parent = parent.parentElement;
10924
+ }
10925
+ return true;
10917
10926
  }
10918
10927
  function getActiveNavbarListContainer(draggedEl) {
10919
10928
  const desktop = getNavbarDesktopContainer();
@@ -10924,6 +10933,7 @@ function getActiveNavbarListContainer(draggedEl) {
10924
10933
  }
10925
10934
  if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
10926
10935
  if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
10936
+ if (drawer && !drawer.closest("[hidden]")) return drawer;
10927
10937
  return desktop ?? drawer;
10928
10938
  }
10929
10939
  function listActiveNavbarItems(draggedEl) {
@@ -10936,6 +10946,12 @@ function listActiveNavbarItems(draggedEl) {
10936
10946
  return listNavbarItems();
10937
10947
  }
10938
10948
  function listNavbarItems() {
10949
+ const active = getActiveNavbarListContainer();
10950
+ if (active) {
10951
+ return Array.from(active.querySelectorAll("[data-ohw-href-key]")).filter(
10952
+ isNavbarLinkItem
10953
+ );
10954
+ }
10939
10955
  const desktop = getNavbarDesktopContainer();
10940
10956
  if (desktop) {
10941
10957
  return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
@@ -11005,24 +11021,25 @@ function buildNavLink(index, href, label, template) {
11005
11021
  return anchor;
11006
11022
  }
11007
11023
  function insertNavLinkInContainer(container, anchor, afterHrefKey) {
11024
+ const listParent = resolveNavbarReorderParent(container);
11008
11025
  if (!afterHrefKey) {
11009
- const cta = container.querySelector(CTA_BUTTON_SELECTOR);
11010
- if (cta && cta.parentElement === container) {
11011
- container.insertBefore(anchor, cta);
11026
+ const cta = listParent.querySelector(CTA_BUTTON_SELECTOR);
11027
+ if (cta && cta.parentElement === listParent) {
11028
+ listParent.insertBefore(anchor, cta);
11012
11029
  return;
11013
11030
  }
11014
- container.appendChild(anchor);
11031
+ listParent.appendChild(anchor);
11015
11032
  return;
11016
11033
  }
11017
- const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
11034
+ const afterEl = findCounterpartByHrefKey(afterHrefKey, listParent);
11018
11035
  if (afterEl) {
11019
11036
  const insertAfter = resolveNavRootUnit(afterEl);
11020
- if (insertAfter.parentElement === container || insertAfter.parentElement === afterEl.parentElement) {
11037
+ if (insertAfter.parentElement === listParent || insertAfter.parentElement === afterEl.parentElement) {
11021
11038
  insertAfter.insertAdjacentElement("afterend", anchor);
11022
11039
  return;
11023
11040
  }
11024
11041
  }
11025
- container.appendChild(anchor);
11042
+ listParent.appendChild(anchor);
11026
11043
  }
11027
11044
  function insertNavbarItemDom(index, href, label, afterAnchor) {
11028
11045
  const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
@@ -11078,15 +11095,25 @@ function getNavbarRootUnitsInContainer(container) {
11078
11095
  }
11079
11096
  return result;
11080
11097
  }
11098
+ function resolveNavbarReorderParent(container) {
11099
+ if (getNavbarRootUnitsInContainer(container).length > 0) return container;
11100
+ for (const child of Array.from(container.children)) {
11101
+ if (!(child instanceof HTMLElement)) continue;
11102
+ if (child.hasAttribute("data-ohw-nav-dropdown-template")) continue;
11103
+ if (getNavbarRootUnitsInContainer(child).length > 0) return child;
11104
+ }
11105
+ return container;
11106
+ }
11081
11107
  function applyNavOrderToContainer(container, order) {
11108
+ const listParent = resolveNavbarReorderParent(container);
11082
11109
  const desired = order.filter((key, i) => order.indexOf(key) === i);
11083
- const units = getNavbarRootUnitsInContainer(container);
11110
+ const units = getNavbarRootUnitsInContainer(listParent);
11084
11111
  const current = units.map((u) => u.key);
11085
11112
  const extras = current.filter((key) => !desired.includes(key));
11086
11113
  const expected = [...desired.filter((key) => current.includes(key)), ...extras];
11087
11114
  if (navOrderKeysEqual(current, expected)) return;
11088
11115
  const lastUnit = units[units.length - 1]?.unit ?? null;
11089
- const anchor = lastUnit?.parentElement === container ? lastUnit.nextElementSibling : null;
11116
+ const anchor = lastUnit?.parentElement === listParent ? lastUnit.nextElementSibling : null;
11090
11117
  const orderedUnits = [];
11091
11118
  const seen = /* @__PURE__ */ new Set();
11092
11119
  for (const hrefKey of desired) {
@@ -11101,9 +11128,9 @@ function applyNavOrderToContainer(container, order) {
11101
11128
  }
11102
11129
  for (const el of orderedUnits) {
11103
11130
  if (anchor) {
11104
- if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
11105
- } else if (container.lastElementChild !== el) {
11106
- container.appendChild(el);
11131
+ if (el.nextSibling !== anchor) listParent.insertBefore(el, anchor);
11132
+ } else if (listParent.lastElementChild !== el) {
11133
+ listParent.appendChild(el);
11107
11134
  }
11108
11135
  }
11109
11136
  }
@@ -12693,26 +12720,48 @@ function resolveFooterColumnForAdd(selected) {
12693
12720
  if (selected.hasAttribute("data-ohw-footer-col")) return selected;
12694
12721
  return selected.closest("[data-ohw-footer-col]") ?? (listFooterColumns().includes(selected) ? selected : null);
12695
12722
  }
12696
- function buildFooterHeading(colIndex, text) {
12697
- const heading = document.createElement("p");
12698
- heading.setAttribute("data-ohw-editable", "text");
12699
- heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
12700
- heading.textContent = text;
12701
- heading.style.cssText = [
12702
- "color: var(--espresso, #3d312b)",
12703
- "font-size: 14px",
12704
- "font-weight: 800",
12705
- "opacity: 0.82",
12706
- "margin: 0 0 6px",
12707
- "padding: 0",
12708
- "line-height: 1.2"
12709
- ].join(";");
12710
- return heading;
12711
- }
12712
12723
  var FOOTER_HEADING_CACHE_ATTR = "data-ohw-heading-cache";
12724
+ var FOOTER_HEADING_CLASS_CACHE_ATTR = "data-ohw-heading-class";
12713
12725
  function getFooterColumnHeadingEl(column) {
12714
12726
  return column.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]') ?? null;
12715
12727
  }
12728
+ function getFooterHeadingTemplate(excludeColumn) {
12729
+ for (const col of listFooterColumns()) {
12730
+ if (excludeColumn && col === excludeColumn) continue;
12731
+ const heading = getFooterColumnHeadingEl(col);
12732
+ if (heading) return heading;
12733
+ }
12734
+ return null;
12735
+ }
12736
+ function footerHeadingLooksLikeHtml(value) {
12737
+ return /<[a-z][\s\S]*>/i.test(value);
12738
+ }
12739
+ function applyFooterHeadingContent(el, value) {
12740
+ if (footerHeadingLooksLikeHtml(value)) {
12741
+ if (el.innerHTML !== value) el.innerHTML = value;
12742
+ return;
12743
+ }
12744
+ const plain = (el.textContent ?? "").trim();
12745
+ if (plain !== value.trim() || footerHeadingLooksLikeHtml(el.innerHTML)) {
12746
+ el.textContent = value;
12747
+ }
12748
+ }
12749
+ function buildFooterHeading(colIndex, text, opts) {
12750
+ const column = opts?.column ?? null;
12751
+ const template = opts?.template ?? getFooterHeadingTemplate(column) ?? null;
12752
+ const tagName = template?.tagName?.toLowerCase() || "p";
12753
+ const heading = document.createElement(tagName);
12754
+ heading.setAttribute("data-ohw-editable", "text");
12755
+ heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
12756
+ applyFooterHeadingContent(heading, text);
12757
+ const cachedClass = column?.getAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR);
12758
+ if (template?.className) {
12759
+ heading.className = template.className;
12760
+ } else if (cachedClass) {
12761
+ heading.className = cachedClass;
12762
+ }
12763
+ return heading;
12764
+ }
12716
12765
  function getFooterColumnHeadingKey(column) {
12717
12766
  const attr = column.getAttribute("data-ohw-footer-col");
12718
12767
  if (attr != null) {
@@ -12736,8 +12785,11 @@ function setFooterColumnHeadingVisible(column, visible) {
12736
12785
  if (!Number.isFinite(colIndex)) return null;
12737
12786
  const existing = getFooterColumnHeadingEl(column);
12738
12787
  if (!visible) {
12739
- const text2 = (existing?.textContent ?? "").trim() || column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12788
+ const text2 = (existing ? existing.innerHTML.trim() || (existing.textContent ?? "").trim() : "") || column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12740
12789
  column.setAttribute(FOOTER_HEADING_CACHE_ATTR, text2);
12790
+ if (existing?.className) {
12791
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, existing.className);
12792
+ }
12741
12793
  existing?.remove();
12742
12794
  return { headingKey, text: "", visible: false };
12743
12795
  }
@@ -12749,7 +12801,7 @@ function setFooterColumnHeadingVisible(column, visible) {
12749
12801
  };
12750
12802
  }
12751
12803
  const text = column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12752
- const heading = buildFooterHeading(colIndex, text);
12804
+ const heading = buildFooterHeading(colIndex, text, { column });
12753
12805
  const firstLink = listFooterLinksInColumn(column)[0];
12754
12806
  if (firstLink) column.insertBefore(heading, firstLink);
12755
12807
  else column.prepend(heading);
@@ -12773,21 +12825,24 @@ function reconcileFooterHeadingVisibility(content) {
12773
12825
  if (raw === "") {
12774
12826
  const existing2 = getFooterColumnHeadingEl(column);
12775
12827
  if (existing2) {
12776
- const cached = (existing2.textContent ?? "").trim();
12828
+ const cached = existing2.innerHTML.trim() || (existing2.textContent ?? "").trim();
12777
12829
  if (cached) column.setAttribute(FOOTER_HEADING_CACHE_ATTR, cached);
12830
+ if (existing2.className) {
12831
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, existing2.className);
12832
+ }
12778
12833
  existing2.remove();
12779
12834
  }
12780
12835
  continue;
12781
12836
  }
12782
12837
  const existing = getFooterColumnHeadingEl(column);
12783
12838
  if (existing) {
12784
- if (existing.textContent !== raw) existing.textContent = raw;
12839
+ applyFooterHeadingContent(existing, raw);
12785
12840
  continue;
12786
12841
  }
12787
12842
  const colMatch = headingKey.match(FOOTER_HEADING_RE);
12788
12843
  const colIndex = colMatch ? parseInt(colMatch[1], 10) : NaN;
12789
12844
  if (!Number.isFinite(colIndex)) continue;
12790
- const heading = buildFooterHeading(colIndex, raw);
12845
+ const heading = buildFooterHeading(colIndex, raw, { column });
12791
12846
  const firstLink = listFooterLinksInColumn(column)[0];
12792
12847
  if (firstLink) column.insertBefore(heading, firstLink);
12793
12848
  else column.prepend(heading);
@@ -12833,9 +12888,13 @@ function insertFooterColumnDom(colIndex, heading, items) {
12833
12888
  column.style.flexDirection = "column";
12834
12889
  }
12835
12890
  if (heading != null && heading !== "") {
12836
- column.appendChild(buildFooterHeading(colIndex, heading));
12891
+ column.appendChild(buildFooterHeading(colIndex, heading, { column }));
12837
12892
  } else if (heading === "") {
12838
12893
  column.setAttribute(FOOTER_HEADING_CACHE_ATTR, DEFAULT_FOOTER_COLUMN_HEADING);
12894
+ const classFromSibling = getFooterHeadingTemplate()?.className;
12895
+ if (classFromSibling) {
12896
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, classFromSibling);
12897
+ }
12839
12898
  }
12840
12899
  let firstLink = null;
12841
12900
  items.forEach((item, itemIndex) => {
@@ -15685,6 +15744,66 @@ function unmountSchedulingWrapper(wrapper) {
15685
15744
  function schedulingSectionId(insertAfter) {
15686
15745
  return `scheduling-${insertAfter}`;
15687
15746
  }
15747
+ function duplicateSchedulingWidget(instanceId, scheduleId) {
15748
+ const escaped = CSS.escape(instanceId);
15749
+ const sourceEl = document.querySelector(
15750
+ `[data-ohw-section-container="scheduling"][data-ohw-instance="${escaped}"]`
15751
+ ) ?? document.querySelector(
15752
+ `[data-ohw-section-container="scheduling"][data-ohw-section="${escaped}"]`
15753
+ ) ?? document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]`);
15754
+ if (!sourceEl) return null;
15755
+ const sourceWrapper = sourceEl.closest('[data-ohw-section-container="scheduling"]') ?? sourceEl;
15756
+ let insertAfter = instanceId;
15757
+ let sectionId = schedulingSectionId(insertAfter);
15758
+ for (let n = 0; n < 20 && document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`); n++) {
15759
+ insertAfter = `${instanceId}--${n + 1}`;
15760
+ sectionId = schedulingSectionId(insertAfter);
15761
+ }
15762
+ if (document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)) return null;
15763
+ const container = document.createElement("div");
15764
+ container.dataset.ohwSectionContainer = "scheduling";
15765
+ container.dataset.ohwSection = sectionId;
15766
+ container.dataset.ohwInstance = sectionId;
15767
+ sourceWrapper.insertAdjacentElement("afterend", container);
15768
+ try {
15769
+ const root = createRoot2(container);
15770
+ schedulingRoots.set(container, root);
15771
+ flushSync2(() => {
15772
+ root.render(
15773
+ /* @__PURE__ */ jsx33(
15774
+ SchedulingWidget,
15775
+ {
15776
+ notifyOnConnect: false,
15777
+ initialScheduleId: scheduleId ?? null,
15778
+ insertAfter
15779
+ }
15780
+ )
15781
+ );
15782
+ });
15783
+ } catch {
15784
+ container.remove();
15785
+ return null;
15786
+ }
15787
+ const tracker = getSectionsTracker();
15788
+ let sections = [];
15789
+ try {
15790
+ sections = JSON.parse(tracker.textContent || "[]");
15791
+ } catch {
15792
+ }
15793
+ const currentPath = window.location.pathname;
15794
+ if (!sections.find(
15795
+ (s) => s.type === "scheduling" && s.insertAfter === insertAfter && (!s.pagePath || s.pagePath === currentPath)
15796
+ )) {
15797
+ sections.push({
15798
+ type: "scheduling",
15799
+ insertAfter,
15800
+ pagePath: currentPath,
15801
+ ...scheduleId ? { scheduleId } : {}
15802
+ });
15803
+ tracker.textContent = JSON.stringify(sections);
15804
+ }
15805
+ return { sectionId, insertAfter };
15806
+ }
15688
15807
  var INSERT_BEFORE_MARKER = ":before:";
15689
15808
  function parseSchedulingInsertAfter(insertAfter) {
15690
15809
  const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
@@ -19315,10 +19434,21 @@ function OhhwellsBridge() {
19315
19434
  gap: 6px;
19316
19435
  }
19317
19436
  /* Not the form: it is a layout container (flex/grid with gaps), and forcing block
19318
- crushed its fields together (OHH-490). */
19319
- [data-ohw-editable]:not([data-ohw-editable="form"]) {
19437
+ crushed its fields together (OHH-490). Not media (image/bg-image/video/icon/map)
19438
+ either: those can be their own flex containers centering fallback content (a
19439
+ placeholder label, a mascot emoji) \u2014 forcing block broke that centering while the
19440
+ image was unset (OHH-758-ish). */
19441
+ [data-ohw-editable]:not([data-ohw-editable="form"]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="map"]) {
19320
19442
  display: block;
19321
19443
  }
19444
+ /* The block-force above is an author rule, so it beats the browser's own
19445
+ details-not-open child-display-none UA rule \u2014 origin always wins over specificity.
19446
+ Left alone, a closed FAQ's answer became a real, hoverable box that overflowed past
19447
+ the collapsed <details> into the gap before the next item. Restore the native
19448
+ collapse for editable content once it isn't the summary. */
19449
+ details:not([open]) > [data-ohw-editable]:not(summary) {
19450
+ display: none !important;
19451
+ }
19322
19452
  /* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
19323
19453
  Exclude select-first nav/footer labels so grab/default on [data-ohw-href-key] can win. */
19324
19454
  [data-ohw-editable]:not([contenteditable]):not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="link"]):not(:is([data-ohw-href-key] *)) {
@@ -19342,6 +19472,14 @@ function OhhwellsBridge() {
19342
19472
  [data-ohw-editable="video"], [data-ohw-editable="video"] *,
19343
19473
  [data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
19344
19474
  [data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
19475
+ /* A text/plain editable nested inside a media editable (e.g. a placeholder's fallback
19476
+ label inside its bg-image box) is its own click target, not the media picker \u2014 the
19477
+ blanket media cursor rule above would otherwise show pointer where a click actually
19478
+ opens text edit. */
19479
+ [data-ohw-editable="bg-image"] [data-ohw-editable="text"],
19480
+ [data-ohw-editable="bg-image"] [data-ohw-editable="text"] *,
19481
+ [data-ohw-editable="image"] [data-ohw-editable="text"],
19482
+ [data-ohw-editable="image"] [data-ohw-editable="text"] * { cursor: text !important; }
19345
19483
  /* A form field is a design surface in the editor: its input takes the pointer so the
19346
19484
  field can be picked and hovered from anywhere inside it (OHH-642). */
19347
19485
  [data-ohw-editable="form"] [data-ohw-form-field] input,
@@ -19928,6 +20066,8 @@ function OhhwellsBridge() {
19928
20066
  setFormHoverRect(null);
19929
20067
  }
19930
20068
  if (!editable) return;
20069
+ const editableRect = editable.getBoundingClientRect();
20070
+ if (editableRect.width <= 0 || editableRect.height <= 0) return;
19931
20071
  const selected = selectedElRef.current;
19932
20072
  if (selected && (selected === editable || selected.contains(editable))) return;
19933
20073
  if (!isMediaEditable(editable) && !editable.hasAttribute("contenteditable")) {
@@ -21310,9 +21450,62 @@ function OhhwellsBridge() {
21310
21450
  if (e.data?.type !== "ow:duplicate-section") return;
21311
21451
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
21312
21452
  if (!instanceId) return;
21453
+ const currentPath = window.location.pathname;
21454
+ if (instanceId.startsWith("scheduling-")) {
21455
+ const sourceInsertAfter = instanceId.slice("scheduling-".length);
21456
+ const tracker = getSectionsTracker();
21457
+ let sections = [];
21458
+ try {
21459
+ sections = JSON.parse(tracker.textContent || "[]");
21460
+ } catch {
21461
+ }
21462
+ const source = sections.find(
21463
+ (s) => s.type === "scheduling" && s.insertAfter === sourceInsertAfter && (!s.pagePath || s.pagePath === currentPath)
21464
+ );
21465
+ const duplicated = duplicateSchedulingWidget(instanceId, source?.scheduleId ?? null);
21466
+ if (!duplicated) return;
21467
+ const currentEntries2 = getPageSectionOrderEntries(
21468
+ editContentRef.current[SECTION_ORDER_KEY],
21469
+ currentPath
21470
+ );
21471
+ const byId = new Map(currentEntries2.map((entry) => [entry.instanceId, entry]));
21472
+ const entries2 = topLevelSections().map((el, order) => {
21473
+ const id = instanceIdOf(el);
21474
+ return {
21475
+ instanceId: id,
21476
+ type: el.getAttribute("data-ohw-section") ?? "",
21477
+ order,
21478
+ pagePath: currentPath,
21479
+ ...byId.get(id)?.removed ? { removed: true } : {}
21480
+ };
21481
+ });
21482
+ const orderJson2 = JSON.stringify(entries2);
21483
+ const nodes2 = [
21484
+ { key: "__ohw_sections", text: tracker.textContent ?? "[]" },
21485
+ { key: SECTION_ORDER_KEY, text: orderJson2 }
21486
+ ];
21487
+ editContentRef.current = {
21488
+ ...editContentRef.current,
21489
+ ...Object.fromEntries(nodes2.map(({ key, text }) => [key, text]))
21490
+ };
21491
+ setAiSectionOrder(orderJson2, currentPath);
21492
+ postToParentRef.current({ type: "ow:change", nodes: nodes2 });
21493
+ window.dispatchEvent(new Event("resize"));
21494
+ const duplicateHeight2 = document.body.scrollHeight;
21495
+ if (duplicateHeight2 > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight2 });
21496
+ const selectDuplicate = () => {
21497
+ const clone2 = document.querySelector(
21498
+ `[data-ohw-section-container="scheduling"][data-ohw-instance="${CSS.escape(duplicated.sectionId)}"]`
21499
+ );
21500
+ if (clone2) aiSectionApiRef.current?.selectFromElement(clone2);
21501
+ };
21502
+ selectDuplicate();
21503
+ requestAnimationFrame(selectDuplicate);
21504
+ return;
21505
+ }
21313
21506
  const newId = newInstanceId();
21314
- const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
21315
- const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
21507
+ const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], currentPath);
21508
+ const result = duplicateSectionInstance(instanceId, newId, currentPath, currentEntries);
21316
21509
  if (!result) return;
21317
21510
  const { entries, keyRekeys } = result;
21318
21511
  const orderJson = JSON.stringify(
@@ -21978,6 +22171,18 @@ function OhhwellsBridge() {
21978
22171
  hoveredNavContainerRef.current = null;
21979
22172
  setHoveredNavContainerRect(null);
21980
22173
  };
22174
+ const handleDetailsToggle = (e) => {
22175
+ if (e.target?.tagName !== "DETAILS") return;
22176
+ document.querySelectorAll("[data-ohw-hovered]").forEach((hovered) => {
22177
+ hovered.removeAttribute("data-ohw-hovered");
22178
+ });
22179
+ setHoveredTextRect(null);
22180
+ hoveredItemElRef.current = null;
22181
+ setHoveredItemRect(null);
22182
+ hoveredNavContainerRef.current = null;
22183
+ setHoveredNavContainerRect(null);
22184
+ };
22185
+ document.addEventListener("toggle", handleDetailsToggle, true);
21981
22186
  window.addEventListener("resize", handleViewportResize, { passive: true });
21982
22187
  document.addEventListener("click", handleClick, true);
21983
22188
  document.addEventListener("dblclick", handleDblClick, true);
@@ -21995,6 +22200,7 @@ function OhhwellsBridge() {
21995
22200
  document.addEventListener("selectionchange", handleSelectionChange);
21996
22201
  window.addEventListener("scroll", handleScroll, true);
21997
22202
  return () => {
22203
+ document.removeEventListener("toggle", handleDetailsToggle, true);
21998
22204
  document.removeEventListener("click", handleClick, true);
21999
22205
  document.removeEventListener("dblclick", handleDblClick, true);
22000
22206
  document.removeEventListener("paste", handlePaste, true);
@@ -22248,7 +22454,7 @@ function OhhwellsBridge() {
22248
22454
  postToParent2({
22249
22455
  type: "ow:ready",
22250
22456
  version: "1",
22251
- bridgeVersion: "0.1.103",
22457
+ bridgeVersion: "0.1.105",
22252
22458
  path: pathname,
22253
22459
  nodes: collectEditableNodes(editContentRef.current),
22254
22460
  sections