@ohhwells/bridge 0.1.103 → 0.1.105

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
@@ -515,14 +515,26 @@ function buttonSurfaceOf(el) {
515
515
  }
516
516
  function alignSubjectOf(el) {
517
517
  const button = el.closest('[data-ohw-role="button"]');
518
- return button?.parentElement ?? el;
518
+ if (button?.parentElement) return button.parentElement;
519
+ let subject = el;
520
+ while (subject.parentElement && !subject.parentElement.hasAttribute("data-ohw-section") && /^inline/.test(getComputedStyle(subject).display)) {
521
+ subject = subject.parentElement;
522
+ }
523
+ const row = subject.closest("li");
524
+ if (row && row !== subject && /^(inline-)?flex$/.test(getComputedStyle(row).display)) {
525
+ return row;
526
+ }
527
+ return subject;
519
528
  }
520
529
  function applyStylesToDom(store) {
521
530
  ensureStyleSheet();
522
531
  clearSectionAttrs(document);
523
532
  clearNodeProps(document);
524
533
  loadStyleFonts(
525
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
534
+ store ? [
535
+ ...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
536
+ ...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
537
+ ] : []
526
538
  );
527
539
  if (!store) return;
528
540
  for (const [sectionId, override] of Object.entries(store.sections)) {
@@ -542,6 +554,23 @@ function applyStylesToDom(store) {
542
554
  section.style.setProperty("background", override.sectionBackgroundColor, "important");
543
555
  section.setAttribute("data-ohw-style-bgcolor", "");
544
556
  }
557
+ if (override.textColor !== void 0 || override.fontFamily !== void 0) {
558
+ const textEls = marker.querySelectorAll(
559
+ '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
560
+ );
561
+ for (const el of Array.from(textEls)) {
562
+ if (override.textColor !== void 0) {
563
+ saveInline(el, "color");
564
+ el.style.setProperty("color", override.textColor, "important");
565
+ el.setAttribute(NODE_WROTE_ATTR, "");
566
+ }
567
+ if (override.fontFamily !== void 0) {
568
+ saveInline(el, "font-family");
569
+ el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
570
+ el.setAttribute(NODE_WROTE_ATTR, "");
571
+ }
572
+ }
573
+ }
545
574
  }
546
575
  }
547
576
  for (const [key, override] of Object.entries(store.nodes)) {
@@ -588,6 +617,22 @@ function applyStylesToDom(store) {
588
617
  }
589
618
  }
590
619
  }
620
+ for (const [sectionId, override] of Object.entries(store.sections)) {
621
+ if (override.headingColor === void 0) continue;
622
+ const escaped = CSS.escape(sectionId);
623
+ const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
624
+ const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
625
+ for (const marker of Array.from(sections)) {
626
+ const headings = marker.querySelectorAll(
627
+ ":is(h1, h2, h3, h4, h5, h6)[data-ohw-editable], :is(h1, h2, h3, h4, h5, h6) > [data-ohw-editable]"
628
+ );
629
+ for (const el of Array.from(headings)) {
630
+ saveInline(el, "color");
631
+ el.style.setProperty("color", override.headingColor, "important");
632
+ el.setAttribute(NODE_WROTE_ATTR, "");
633
+ }
634
+ }
635
+ }
591
636
  }
592
637
 
593
638
  // src/ui/ai-tree/aiSectionsManager.tsx
@@ -10866,9 +10911,18 @@ function getNavbarDrawerContainer() {
10866
10911
  }
10867
10912
  function isNavbarListContainerVisible(el) {
10868
10913
  if (el.hasAttribute("hidden")) return false;
10914
+ if (el.closest("[hidden]")) return false;
10869
10915
  if (el.getClientRects().length === 0) return false;
10870
10916
  const style = window.getComputedStyle(el);
10871
- 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;
10872
10926
  }
10873
10927
  function getActiveNavbarListContainer(draggedEl) {
10874
10928
  const desktop = getNavbarDesktopContainer();
@@ -10879,6 +10933,7 @@ function getActiveNavbarListContainer(draggedEl) {
10879
10933
  }
10880
10934
  if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
10881
10935
  if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
10936
+ if (drawer && !drawer.closest("[hidden]")) return drawer;
10882
10937
  return desktop ?? drawer;
10883
10938
  }
10884
10939
  function listActiveNavbarItems(draggedEl) {
@@ -10891,6 +10946,12 @@ function listActiveNavbarItems(draggedEl) {
10891
10946
  return listNavbarItems();
10892
10947
  }
10893
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
+ }
10894
10955
  const desktop = getNavbarDesktopContainer();
10895
10956
  if (desktop) {
10896
10957
  return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
@@ -10960,24 +11021,25 @@ function buildNavLink(index, href, label, template) {
10960
11021
  return anchor;
10961
11022
  }
10962
11023
  function insertNavLinkInContainer(container, anchor, afterHrefKey) {
11024
+ const listParent = resolveNavbarReorderParent(container);
10963
11025
  if (!afterHrefKey) {
10964
- const cta = container.querySelector(CTA_BUTTON_SELECTOR);
10965
- if (cta && cta.parentElement === container) {
10966
- container.insertBefore(anchor, cta);
11026
+ const cta = listParent.querySelector(CTA_BUTTON_SELECTOR);
11027
+ if (cta && cta.parentElement === listParent) {
11028
+ listParent.insertBefore(anchor, cta);
10967
11029
  return;
10968
11030
  }
10969
- container.appendChild(anchor);
11031
+ listParent.appendChild(anchor);
10970
11032
  return;
10971
11033
  }
10972
- const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
11034
+ const afterEl = findCounterpartByHrefKey(afterHrefKey, listParent);
10973
11035
  if (afterEl) {
10974
11036
  const insertAfter = resolveNavRootUnit(afterEl);
10975
- if (insertAfter.parentElement === container || insertAfter.parentElement === afterEl.parentElement) {
11037
+ if (insertAfter.parentElement === listParent || insertAfter.parentElement === afterEl.parentElement) {
10976
11038
  insertAfter.insertAdjacentElement("afterend", anchor);
10977
11039
  return;
10978
11040
  }
10979
11041
  }
10980
- container.appendChild(anchor);
11042
+ listParent.appendChild(anchor);
10981
11043
  }
10982
11044
  function insertNavbarItemDom(index, href, label, afterAnchor) {
10983
11045
  const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
@@ -11033,15 +11095,25 @@ function getNavbarRootUnitsInContainer(container) {
11033
11095
  }
11034
11096
  return result;
11035
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
+ }
11036
11107
  function applyNavOrderToContainer(container, order) {
11108
+ const listParent = resolveNavbarReorderParent(container);
11037
11109
  const desired = order.filter((key, i) => order.indexOf(key) === i);
11038
- const units = getNavbarRootUnitsInContainer(container);
11110
+ const units = getNavbarRootUnitsInContainer(listParent);
11039
11111
  const current = units.map((u) => u.key);
11040
11112
  const extras = current.filter((key) => !desired.includes(key));
11041
11113
  const expected = [...desired.filter((key) => current.includes(key)), ...extras];
11042
11114
  if (navOrderKeysEqual(current, expected)) return;
11043
11115
  const lastUnit = units[units.length - 1]?.unit ?? null;
11044
- const anchor = lastUnit?.parentElement === container ? lastUnit.nextElementSibling : null;
11116
+ const anchor = lastUnit?.parentElement === listParent ? lastUnit.nextElementSibling : null;
11045
11117
  const orderedUnits = [];
11046
11118
  const seen = /* @__PURE__ */ new Set();
11047
11119
  for (const hrefKey of desired) {
@@ -11056,9 +11128,9 @@ function applyNavOrderToContainer(container, order) {
11056
11128
  }
11057
11129
  for (const el of orderedUnits) {
11058
11130
  if (anchor) {
11059
- if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
11060
- } else if (container.lastElementChild !== el) {
11061
- container.appendChild(el);
11131
+ if (el.nextSibling !== anchor) listParent.insertBefore(el, anchor);
11132
+ } else if (listParent.lastElementChild !== el) {
11133
+ listParent.appendChild(el);
11062
11134
  }
11063
11135
  }
11064
11136
  }
@@ -12648,26 +12720,48 @@ function resolveFooterColumnForAdd(selected) {
12648
12720
  if (selected.hasAttribute("data-ohw-footer-col")) return selected;
12649
12721
  return selected.closest("[data-ohw-footer-col]") ?? (listFooterColumns().includes(selected) ? selected : null);
12650
12722
  }
12651
- function buildFooterHeading(colIndex, text) {
12652
- const heading = document.createElement("p");
12653
- heading.setAttribute("data-ohw-editable", "text");
12654
- heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
12655
- heading.textContent = text;
12656
- heading.style.cssText = [
12657
- "color: var(--espresso, #3d312b)",
12658
- "font-size: 14px",
12659
- "font-weight: 800",
12660
- "opacity: 0.82",
12661
- "margin: 0 0 6px",
12662
- "padding: 0",
12663
- "line-height: 1.2"
12664
- ].join(";");
12665
- return heading;
12666
- }
12667
12723
  var FOOTER_HEADING_CACHE_ATTR = "data-ohw-heading-cache";
12724
+ var FOOTER_HEADING_CLASS_CACHE_ATTR = "data-ohw-heading-class";
12668
12725
  function getFooterColumnHeadingEl(column) {
12669
12726
  return column.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]') ?? null;
12670
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
+ }
12671
12765
  function getFooterColumnHeadingKey(column) {
12672
12766
  const attr = column.getAttribute("data-ohw-footer-col");
12673
12767
  if (attr != null) {
@@ -12691,8 +12785,11 @@ function setFooterColumnHeadingVisible(column, visible) {
12691
12785
  if (!Number.isFinite(colIndex)) return null;
12692
12786
  const existing = getFooterColumnHeadingEl(column);
12693
12787
  if (!visible) {
12694
- 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;
12695
12789
  column.setAttribute(FOOTER_HEADING_CACHE_ATTR, text2);
12790
+ if (existing?.className) {
12791
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, existing.className);
12792
+ }
12696
12793
  existing?.remove();
12697
12794
  return { headingKey, text: "", visible: false };
12698
12795
  }
@@ -12704,7 +12801,7 @@ function setFooterColumnHeadingVisible(column, visible) {
12704
12801
  };
12705
12802
  }
12706
12803
  const text = column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12707
- const heading = buildFooterHeading(colIndex, text);
12804
+ const heading = buildFooterHeading(colIndex, text, { column });
12708
12805
  const firstLink = listFooterLinksInColumn(column)[0];
12709
12806
  if (firstLink) column.insertBefore(heading, firstLink);
12710
12807
  else column.prepend(heading);
@@ -12728,21 +12825,24 @@ function reconcileFooterHeadingVisibility(content) {
12728
12825
  if (raw === "") {
12729
12826
  const existing2 = getFooterColumnHeadingEl(column);
12730
12827
  if (existing2) {
12731
- const cached = (existing2.textContent ?? "").trim();
12828
+ const cached = existing2.innerHTML.trim() || (existing2.textContent ?? "").trim();
12732
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
+ }
12733
12833
  existing2.remove();
12734
12834
  }
12735
12835
  continue;
12736
12836
  }
12737
12837
  const existing = getFooterColumnHeadingEl(column);
12738
12838
  if (existing) {
12739
- if (existing.textContent !== raw) existing.textContent = raw;
12839
+ applyFooterHeadingContent(existing, raw);
12740
12840
  continue;
12741
12841
  }
12742
12842
  const colMatch = headingKey.match(FOOTER_HEADING_RE);
12743
12843
  const colIndex = colMatch ? parseInt(colMatch[1], 10) : NaN;
12744
12844
  if (!Number.isFinite(colIndex)) continue;
12745
- const heading = buildFooterHeading(colIndex, raw);
12845
+ const heading = buildFooterHeading(colIndex, raw, { column });
12746
12846
  const firstLink = listFooterLinksInColumn(column)[0];
12747
12847
  if (firstLink) column.insertBefore(heading, firstLink);
12748
12848
  else column.prepend(heading);
@@ -12788,9 +12888,13 @@ function insertFooterColumnDom(colIndex, heading, items) {
12788
12888
  column.style.flexDirection = "column";
12789
12889
  }
12790
12890
  if (heading != null && heading !== "") {
12791
- column.appendChild(buildFooterHeading(colIndex, heading));
12891
+ column.appendChild(buildFooterHeading(colIndex, heading, { column }));
12792
12892
  } else if (heading === "") {
12793
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
+ }
12794
12898
  }
12795
12899
  let firstLink = null;
12796
12900
  items.forEach((item, itemIndex) => {
@@ -15640,6 +15744,66 @@ function unmountSchedulingWrapper(wrapper) {
15640
15744
  function schedulingSectionId(insertAfter) {
15641
15745
  return `scheduling-${insertAfter}`;
15642
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
+ }
15643
15807
  var INSERT_BEFORE_MARKER = ":before:";
15644
15808
  function parseSchedulingInsertAfter(insertAfter) {
15645
15809
  const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
@@ -18794,6 +18958,9 @@ function OhhwellsBridge() {
18794
18958
  applySocialsDisplayFromContent(content);
18795
18959
  applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
18796
18960
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
18961
+ if (typeof content[STYLE_STORE_KEY] === "string") {
18962
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
18963
+ }
18797
18964
  enforceLinkHrefs();
18798
18965
  initSectionsFromContent(content, true);
18799
18966
  sectionsLoadedRef.current = true;
@@ -18989,6 +19156,9 @@ function OhhwellsBridge() {
18989
19156
  applySocialsDisplayFromContent(content);
18990
19157
  applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
18991
19158
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
19159
+ if (typeof content[STYLE_STORE_KEY] === "string") {
19160
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19161
+ }
18992
19162
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
18993
19163
  if (!form.querySelector("[data-ohw-form-success]")) {
18994
19164
  reconcileFieldsFromContent(form, content);
@@ -20967,6 +21137,9 @@ function OhhwellsBridge() {
20967
21137
  reconcileNavbarItemsFromContent(editContentRef.current);
20968
21138
  reconcileFooterOrderFromContent(editContentRef.current);
20969
21139
  syncNavigationDragCursorAttrs();
21140
+ if (typeof content[STYLE_STORE_KEY] === "string") {
21141
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
21142
+ }
20970
21143
  enforceLinkHrefs();
20971
21144
  const hydrateReapExclude = /* @__PURE__ */ new Set();
20972
21145
  const hydratePendingUndo = pendingDeleteUndoRef.current;
@@ -21256,9 +21429,62 @@ function OhhwellsBridge() {
21256
21429
  if (e.data?.type !== "ow:duplicate-section") return;
21257
21430
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
21258
21431
  if (!instanceId) return;
21432
+ const currentPath = window.location.pathname;
21433
+ if (instanceId.startsWith("scheduling-")) {
21434
+ const sourceInsertAfter = instanceId.slice("scheduling-".length);
21435
+ const tracker = getSectionsTracker();
21436
+ let sections = [];
21437
+ try {
21438
+ sections = JSON.parse(tracker.textContent || "[]");
21439
+ } catch {
21440
+ }
21441
+ const source = sections.find(
21442
+ (s) => s.type === "scheduling" && s.insertAfter === sourceInsertAfter && (!s.pagePath || s.pagePath === currentPath)
21443
+ );
21444
+ const duplicated = duplicateSchedulingWidget(instanceId, source?.scheduleId ?? null);
21445
+ if (!duplicated) return;
21446
+ const currentEntries2 = getPageSectionOrderEntries(
21447
+ editContentRef.current[SECTION_ORDER_KEY],
21448
+ currentPath
21449
+ );
21450
+ const byId = new Map(currentEntries2.map((entry) => [entry.instanceId, entry]));
21451
+ const entries2 = topLevelSections().map((el, order) => {
21452
+ const id = instanceIdOf(el);
21453
+ return {
21454
+ instanceId: id,
21455
+ type: el.getAttribute("data-ohw-section") ?? "",
21456
+ order,
21457
+ pagePath: currentPath,
21458
+ ...byId.get(id)?.removed ? { removed: true } : {}
21459
+ };
21460
+ });
21461
+ const orderJson2 = JSON.stringify(entries2);
21462
+ const nodes2 = [
21463
+ { key: "__ohw_sections", text: tracker.textContent ?? "[]" },
21464
+ { key: SECTION_ORDER_KEY, text: orderJson2 }
21465
+ ];
21466
+ editContentRef.current = {
21467
+ ...editContentRef.current,
21468
+ ...Object.fromEntries(nodes2.map(({ key, text }) => [key, text]))
21469
+ };
21470
+ setAiSectionOrder(orderJson2, currentPath);
21471
+ postToParentRef.current({ type: "ow:change", nodes: nodes2 });
21472
+ window.dispatchEvent(new Event("resize"));
21473
+ const duplicateHeight2 = document.body.scrollHeight;
21474
+ if (duplicateHeight2 > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight2 });
21475
+ const selectDuplicate = () => {
21476
+ const clone2 = document.querySelector(
21477
+ `[data-ohw-section-container="scheduling"][data-ohw-instance="${CSS.escape(duplicated.sectionId)}"]`
21478
+ );
21479
+ if (clone2) aiSectionApiRef.current?.selectFromElement(clone2);
21480
+ };
21481
+ selectDuplicate();
21482
+ requestAnimationFrame(selectDuplicate);
21483
+ return;
21484
+ }
21259
21485
  const newId = newInstanceId();
21260
- const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
21261
- const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
21486
+ const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], currentPath);
21487
+ const result = duplicateSectionInstance(instanceId, newId, currentPath, currentEntries);
21262
21488
  if (!result) return;
21263
21489
  const { entries, keyRekeys } = result;
21264
21490
  const orderJson = JSON.stringify(
@@ -22194,7 +22420,7 @@ function OhhwellsBridge() {
22194
22420
  postToParent2({
22195
22421
  type: "ow:ready",
22196
22422
  version: "1",
22197
- bridgeVersion: "0.1.101",
22423
+ bridgeVersion: "0.1.104",
22198
22424
  path: pathname,
22199
22425
  nodes: collectEditableNodes(editContentRef.current),
22200
22426
  sections