@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.cjs CHANGED
@@ -588,14 +588,26 @@ function buttonSurfaceOf(el) {
588
588
  }
589
589
  function alignSubjectOf(el) {
590
590
  const button = el.closest('[data-ohw-role="button"]');
591
- return button?.parentElement ?? el;
591
+ if (button?.parentElement) return button.parentElement;
592
+ let subject = el;
593
+ while (subject.parentElement && !subject.parentElement.hasAttribute("data-ohw-section") && /^inline/.test(getComputedStyle(subject).display)) {
594
+ subject = subject.parentElement;
595
+ }
596
+ const row = subject.closest("li");
597
+ if (row && row !== subject && /^(inline-)?flex$/.test(getComputedStyle(row).display)) {
598
+ return row;
599
+ }
600
+ return subject;
592
601
  }
593
602
  function applyStylesToDom(store) {
594
603
  ensureStyleSheet();
595
604
  clearSectionAttrs(document);
596
605
  clearNodeProps(document);
597
606
  loadStyleFonts(
598
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
607
+ store ? [
608
+ ...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
609
+ ...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
610
+ ] : []
599
611
  );
600
612
  if (!store) return;
601
613
  for (const [sectionId, override] of Object.entries(store.sections)) {
@@ -615,6 +627,23 @@ function applyStylesToDom(store) {
615
627
  section.style.setProperty("background", override.sectionBackgroundColor, "important");
616
628
  section.setAttribute("data-ohw-style-bgcolor", "");
617
629
  }
630
+ if (override.textColor !== void 0 || override.fontFamily !== void 0) {
631
+ const textEls = marker.querySelectorAll(
632
+ '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
633
+ );
634
+ for (const el of Array.from(textEls)) {
635
+ if (override.textColor !== void 0) {
636
+ saveInline(el, "color");
637
+ el.style.setProperty("color", override.textColor, "important");
638
+ el.setAttribute(NODE_WROTE_ATTR, "");
639
+ }
640
+ if (override.fontFamily !== void 0) {
641
+ saveInline(el, "font-family");
642
+ el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
643
+ el.setAttribute(NODE_WROTE_ATTR, "");
644
+ }
645
+ }
646
+ }
618
647
  }
619
648
  }
620
649
  for (const [key, override] of Object.entries(store.nodes)) {
@@ -661,6 +690,22 @@ function applyStylesToDom(store) {
661
690
  }
662
691
  }
663
692
  }
693
+ for (const [sectionId, override] of Object.entries(store.sections)) {
694
+ if (override.headingColor === void 0) continue;
695
+ const escaped = CSS.escape(sectionId);
696
+ const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
697
+ const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
698
+ for (const marker of Array.from(sections)) {
699
+ const headings = marker.querySelectorAll(
700
+ ":is(h1, h2, h3, h4, h5, h6)[data-ohw-editable], :is(h1, h2, h3, h4, h5, h6) > [data-ohw-editable]"
701
+ );
702
+ for (const el of Array.from(headings)) {
703
+ saveInline(el, "color");
704
+ el.style.setProperty("color", override.headingColor, "important");
705
+ el.setAttribute(NODE_WROTE_ATTR, "");
706
+ }
707
+ }
708
+ }
664
709
  }
665
710
 
666
711
  // src/ui/ai-tree/aiSectionsManager.tsx
@@ -10939,9 +10984,18 @@ function getNavbarDrawerContainer() {
10939
10984
  }
10940
10985
  function isNavbarListContainerVisible(el) {
10941
10986
  if (el.hasAttribute("hidden")) return false;
10987
+ if (el.closest("[hidden]")) return false;
10942
10988
  if (el.getClientRects().length === 0) return false;
10943
10989
  const style = window.getComputedStyle(el);
10944
- return style.display !== "none" && style.visibility !== "hidden";
10990
+ if (style.display === "none" || style.visibility === "hidden") return false;
10991
+ let parent = el.parentElement;
10992
+ while (parent && parent !== document.documentElement) {
10993
+ if (parent.hasAttribute("hidden")) return false;
10994
+ const ps = window.getComputedStyle(parent);
10995
+ if (ps.display === "none" || ps.visibility === "hidden") return false;
10996
+ parent = parent.parentElement;
10997
+ }
10998
+ return true;
10945
10999
  }
10946
11000
  function getActiveNavbarListContainer(draggedEl) {
10947
11001
  const desktop = getNavbarDesktopContainer();
@@ -10952,6 +11006,7 @@ function getActiveNavbarListContainer(draggedEl) {
10952
11006
  }
10953
11007
  if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
10954
11008
  if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
11009
+ if (drawer && !drawer.closest("[hidden]")) return drawer;
10955
11010
  return desktop ?? drawer;
10956
11011
  }
10957
11012
  function listActiveNavbarItems(draggedEl) {
@@ -10964,6 +11019,12 @@ function listActiveNavbarItems(draggedEl) {
10964
11019
  return listNavbarItems();
10965
11020
  }
10966
11021
  function listNavbarItems() {
11022
+ const active = getActiveNavbarListContainer();
11023
+ if (active) {
11024
+ return Array.from(active.querySelectorAll("[data-ohw-href-key]")).filter(
11025
+ isNavbarLinkItem
11026
+ );
11027
+ }
10967
11028
  const desktop = getNavbarDesktopContainer();
10968
11029
  if (desktop) {
10969
11030
  return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
@@ -11033,24 +11094,25 @@ function buildNavLink(index, href, label, template) {
11033
11094
  return anchor;
11034
11095
  }
11035
11096
  function insertNavLinkInContainer(container, anchor, afterHrefKey) {
11097
+ const listParent = resolveNavbarReorderParent(container);
11036
11098
  if (!afterHrefKey) {
11037
- const cta = container.querySelector(CTA_BUTTON_SELECTOR);
11038
- if (cta && cta.parentElement === container) {
11039
- container.insertBefore(anchor, cta);
11099
+ const cta = listParent.querySelector(CTA_BUTTON_SELECTOR);
11100
+ if (cta && cta.parentElement === listParent) {
11101
+ listParent.insertBefore(anchor, cta);
11040
11102
  return;
11041
11103
  }
11042
- container.appendChild(anchor);
11104
+ listParent.appendChild(anchor);
11043
11105
  return;
11044
11106
  }
11045
- const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
11107
+ const afterEl = findCounterpartByHrefKey(afterHrefKey, listParent);
11046
11108
  if (afterEl) {
11047
11109
  const insertAfter = resolveNavRootUnit(afterEl);
11048
- if (insertAfter.parentElement === container || insertAfter.parentElement === afterEl.parentElement) {
11110
+ if (insertAfter.parentElement === listParent || insertAfter.parentElement === afterEl.parentElement) {
11049
11111
  insertAfter.insertAdjacentElement("afterend", anchor);
11050
11112
  return;
11051
11113
  }
11052
11114
  }
11053
- container.appendChild(anchor);
11115
+ listParent.appendChild(anchor);
11054
11116
  }
11055
11117
  function insertNavbarItemDom(index, href, label, afterAnchor) {
11056
11118
  const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
@@ -11106,15 +11168,25 @@ function getNavbarRootUnitsInContainer(container) {
11106
11168
  }
11107
11169
  return result;
11108
11170
  }
11171
+ function resolveNavbarReorderParent(container) {
11172
+ if (getNavbarRootUnitsInContainer(container).length > 0) return container;
11173
+ for (const child of Array.from(container.children)) {
11174
+ if (!(child instanceof HTMLElement)) continue;
11175
+ if (child.hasAttribute("data-ohw-nav-dropdown-template")) continue;
11176
+ if (getNavbarRootUnitsInContainer(child).length > 0) return child;
11177
+ }
11178
+ return container;
11179
+ }
11109
11180
  function applyNavOrderToContainer(container, order) {
11181
+ const listParent = resolveNavbarReorderParent(container);
11110
11182
  const desired = order.filter((key, i) => order.indexOf(key) === i);
11111
- const units = getNavbarRootUnitsInContainer(container);
11183
+ const units = getNavbarRootUnitsInContainer(listParent);
11112
11184
  const current = units.map((u) => u.key);
11113
11185
  const extras = current.filter((key) => !desired.includes(key));
11114
11186
  const expected = [...desired.filter((key) => current.includes(key)), ...extras];
11115
11187
  if (navOrderKeysEqual(current, expected)) return;
11116
11188
  const lastUnit = units[units.length - 1]?.unit ?? null;
11117
- const anchor = lastUnit?.parentElement === container ? lastUnit.nextElementSibling : null;
11189
+ const anchor = lastUnit?.parentElement === listParent ? lastUnit.nextElementSibling : null;
11118
11190
  const orderedUnits = [];
11119
11191
  const seen = /* @__PURE__ */ new Set();
11120
11192
  for (const hrefKey of desired) {
@@ -11129,9 +11201,9 @@ function applyNavOrderToContainer(container, order) {
11129
11201
  }
11130
11202
  for (const el of orderedUnits) {
11131
11203
  if (anchor) {
11132
- if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
11133
- } else if (container.lastElementChild !== el) {
11134
- container.appendChild(el);
11204
+ if (el.nextSibling !== anchor) listParent.insertBefore(el, anchor);
11205
+ } else if (listParent.lastElementChild !== el) {
11206
+ listParent.appendChild(el);
11135
11207
  }
11136
11208
  }
11137
11209
  }
@@ -12721,26 +12793,48 @@ function resolveFooterColumnForAdd(selected) {
12721
12793
  if (selected.hasAttribute("data-ohw-footer-col")) return selected;
12722
12794
  return selected.closest("[data-ohw-footer-col]") ?? (listFooterColumns().includes(selected) ? selected : null);
12723
12795
  }
12724
- function buildFooterHeading(colIndex, text) {
12725
- const heading = document.createElement("p");
12726
- heading.setAttribute("data-ohw-editable", "text");
12727
- heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
12728
- heading.textContent = text;
12729
- heading.style.cssText = [
12730
- "color: var(--espresso, #3d312b)",
12731
- "font-size: 14px",
12732
- "font-weight: 800",
12733
- "opacity: 0.82",
12734
- "margin: 0 0 6px",
12735
- "padding: 0",
12736
- "line-height: 1.2"
12737
- ].join(";");
12738
- return heading;
12739
- }
12740
12796
  var FOOTER_HEADING_CACHE_ATTR = "data-ohw-heading-cache";
12797
+ var FOOTER_HEADING_CLASS_CACHE_ATTR = "data-ohw-heading-class";
12741
12798
  function getFooterColumnHeadingEl(column) {
12742
12799
  return column.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]') ?? null;
12743
12800
  }
12801
+ function getFooterHeadingTemplate(excludeColumn) {
12802
+ for (const col of listFooterColumns()) {
12803
+ if (excludeColumn && col === excludeColumn) continue;
12804
+ const heading = getFooterColumnHeadingEl(col);
12805
+ if (heading) return heading;
12806
+ }
12807
+ return null;
12808
+ }
12809
+ function footerHeadingLooksLikeHtml(value) {
12810
+ return /<[a-z][\s\S]*>/i.test(value);
12811
+ }
12812
+ function applyFooterHeadingContent(el, value) {
12813
+ if (footerHeadingLooksLikeHtml(value)) {
12814
+ if (el.innerHTML !== value) el.innerHTML = value;
12815
+ return;
12816
+ }
12817
+ const plain = (el.textContent ?? "").trim();
12818
+ if (plain !== value.trim() || footerHeadingLooksLikeHtml(el.innerHTML)) {
12819
+ el.textContent = value;
12820
+ }
12821
+ }
12822
+ function buildFooterHeading(colIndex, text, opts) {
12823
+ const column = opts?.column ?? null;
12824
+ const template = opts?.template ?? getFooterHeadingTemplate(column) ?? null;
12825
+ const tagName = template?.tagName?.toLowerCase() || "p";
12826
+ const heading = document.createElement(tagName);
12827
+ heading.setAttribute("data-ohw-editable", "text");
12828
+ heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
12829
+ applyFooterHeadingContent(heading, text);
12830
+ const cachedClass = column?.getAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR);
12831
+ if (template?.className) {
12832
+ heading.className = template.className;
12833
+ } else if (cachedClass) {
12834
+ heading.className = cachedClass;
12835
+ }
12836
+ return heading;
12837
+ }
12744
12838
  function getFooterColumnHeadingKey(column) {
12745
12839
  const attr = column.getAttribute("data-ohw-footer-col");
12746
12840
  if (attr != null) {
@@ -12764,8 +12858,11 @@ function setFooterColumnHeadingVisible(column, visible) {
12764
12858
  if (!Number.isFinite(colIndex)) return null;
12765
12859
  const existing = getFooterColumnHeadingEl(column);
12766
12860
  if (!visible) {
12767
- const text2 = (existing?.textContent ?? "").trim() || column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12861
+ const text2 = (existing ? existing.innerHTML.trim() || (existing.textContent ?? "").trim() : "") || column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12768
12862
  column.setAttribute(FOOTER_HEADING_CACHE_ATTR, text2);
12863
+ if (existing?.className) {
12864
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, existing.className);
12865
+ }
12769
12866
  existing?.remove();
12770
12867
  return { headingKey, text: "", visible: false };
12771
12868
  }
@@ -12777,7 +12874,7 @@ function setFooterColumnHeadingVisible(column, visible) {
12777
12874
  };
12778
12875
  }
12779
12876
  const text = column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12780
- const heading = buildFooterHeading(colIndex, text);
12877
+ const heading = buildFooterHeading(colIndex, text, { column });
12781
12878
  const firstLink = listFooterLinksInColumn(column)[0];
12782
12879
  if (firstLink) column.insertBefore(heading, firstLink);
12783
12880
  else column.prepend(heading);
@@ -12801,21 +12898,24 @@ function reconcileFooterHeadingVisibility(content) {
12801
12898
  if (raw === "") {
12802
12899
  const existing2 = getFooterColumnHeadingEl(column);
12803
12900
  if (existing2) {
12804
- const cached = (existing2.textContent ?? "").trim();
12901
+ const cached = existing2.innerHTML.trim() || (existing2.textContent ?? "").trim();
12805
12902
  if (cached) column.setAttribute(FOOTER_HEADING_CACHE_ATTR, cached);
12903
+ if (existing2.className) {
12904
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, existing2.className);
12905
+ }
12806
12906
  existing2.remove();
12807
12907
  }
12808
12908
  continue;
12809
12909
  }
12810
12910
  const existing = getFooterColumnHeadingEl(column);
12811
12911
  if (existing) {
12812
- if (existing.textContent !== raw) existing.textContent = raw;
12912
+ applyFooterHeadingContent(existing, raw);
12813
12913
  continue;
12814
12914
  }
12815
12915
  const colMatch = headingKey.match(FOOTER_HEADING_RE);
12816
12916
  const colIndex = colMatch ? parseInt(colMatch[1], 10) : NaN;
12817
12917
  if (!Number.isFinite(colIndex)) continue;
12818
- const heading = buildFooterHeading(colIndex, raw);
12918
+ const heading = buildFooterHeading(colIndex, raw, { column });
12819
12919
  const firstLink = listFooterLinksInColumn(column)[0];
12820
12920
  if (firstLink) column.insertBefore(heading, firstLink);
12821
12921
  else column.prepend(heading);
@@ -12861,9 +12961,13 @@ function insertFooterColumnDom(colIndex, heading, items) {
12861
12961
  column.style.flexDirection = "column";
12862
12962
  }
12863
12963
  if (heading != null && heading !== "") {
12864
- column.appendChild(buildFooterHeading(colIndex, heading));
12964
+ column.appendChild(buildFooterHeading(colIndex, heading, { column }));
12865
12965
  } else if (heading === "") {
12866
12966
  column.setAttribute(FOOTER_HEADING_CACHE_ATTR, DEFAULT_FOOTER_COLUMN_HEADING);
12967
+ const classFromSibling = getFooterHeadingTemplate()?.className;
12968
+ if (classFromSibling) {
12969
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, classFromSibling);
12970
+ }
12867
12971
  }
12868
12972
  let firstLink = null;
12869
12973
  items.forEach((item, itemIndex) => {
@@ -15707,6 +15811,66 @@ function unmountSchedulingWrapper(wrapper) {
15707
15811
  function schedulingSectionId(insertAfter) {
15708
15812
  return `scheduling-${insertAfter}`;
15709
15813
  }
15814
+ function duplicateSchedulingWidget(instanceId, scheduleId) {
15815
+ const escaped = CSS.escape(instanceId);
15816
+ const sourceEl = document.querySelector(
15817
+ `[data-ohw-section-container="scheduling"][data-ohw-instance="${escaped}"]`
15818
+ ) ?? document.querySelector(
15819
+ `[data-ohw-section-container="scheduling"][data-ohw-section="${escaped}"]`
15820
+ ) ?? document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]`);
15821
+ if (!sourceEl) return null;
15822
+ const sourceWrapper = sourceEl.closest('[data-ohw-section-container="scheduling"]') ?? sourceEl;
15823
+ let insertAfter = instanceId;
15824
+ let sectionId = schedulingSectionId(insertAfter);
15825
+ for (let n = 0; n < 20 && document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`); n++) {
15826
+ insertAfter = `${instanceId}--${n + 1}`;
15827
+ sectionId = schedulingSectionId(insertAfter);
15828
+ }
15829
+ if (document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)) return null;
15830
+ const container = document.createElement("div");
15831
+ container.dataset.ohwSectionContainer = "scheduling";
15832
+ container.dataset.ohwSection = sectionId;
15833
+ container.dataset.ohwInstance = sectionId;
15834
+ sourceWrapper.insertAdjacentElement("afterend", container);
15835
+ try {
15836
+ const root = (0, import_client2.createRoot)(container);
15837
+ schedulingRoots.set(container, root);
15838
+ (0, import_react_dom3.flushSync)(() => {
15839
+ root.render(
15840
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
15841
+ SchedulingWidget,
15842
+ {
15843
+ notifyOnConnect: false,
15844
+ initialScheduleId: scheduleId ?? null,
15845
+ insertAfter
15846
+ }
15847
+ )
15848
+ );
15849
+ });
15850
+ } catch {
15851
+ container.remove();
15852
+ return null;
15853
+ }
15854
+ const tracker = getSectionsTracker();
15855
+ let sections = [];
15856
+ try {
15857
+ sections = JSON.parse(tracker.textContent || "[]");
15858
+ } catch {
15859
+ }
15860
+ const currentPath = window.location.pathname;
15861
+ if (!sections.find(
15862
+ (s) => s.type === "scheduling" && s.insertAfter === insertAfter && (!s.pagePath || s.pagePath === currentPath)
15863
+ )) {
15864
+ sections.push({
15865
+ type: "scheduling",
15866
+ insertAfter,
15867
+ pagePath: currentPath,
15868
+ ...scheduleId ? { scheduleId } : {}
15869
+ });
15870
+ tracker.textContent = JSON.stringify(sections);
15871
+ }
15872
+ return { sectionId, insertAfter };
15873
+ }
15710
15874
  var INSERT_BEFORE_MARKER = ":before:";
15711
15875
  function parseSchedulingInsertAfter(insertAfter) {
15712
15876
  const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
@@ -18861,6 +19025,9 @@ function OhhwellsBridge() {
18861
19025
  applySocialsDisplayFromContent(content);
18862
19026
  applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
18863
19027
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
19028
+ if (typeof content[STYLE_STORE_KEY] === "string") {
19029
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19030
+ }
18864
19031
  enforceLinkHrefs();
18865
19032
  initSectionsFromContent(content, true);
18866
19033
  sectionsLoadedRef.current = true;
@@ -19056,6 +19223,9 @@ function OhhwellsBridge() {
19056
19223
  applySocialsDisplayFromContent(content);
19057
19224
  applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
19058
19225
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
19226
+ if (typeof content[STYLE_STORE_KEY] === "string") {
19227
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19228
+ }
19059
19229
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19060
19230
  if (!form.querySelector("[data-ohw-form-success]")) {
19061
19231
  reconcileFieldsFromContent(form, content);
@@ -21034,6 +21204,9 @@ function OhhwellsBridge() {
21034
21204
  reconcileNavbarItemsFromContent(editContentRef.current);
21035
21205
  reconcileFooterOrderFromContent(editContentRef.current);
21036
21206
  syncNavigationDragCursorAttrs();
21207
+ if (typeof content[STYLE_STORE_KEY] === "string") {
21208
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
21209
+ }
21037
21210
  enforceLinkHrefs();
21038
21211
  const hydrateReapExclude = /* @__PURE__ */ new Set();
21039
21212
  const hydratePendingUndo = pendingDeleteUndoRef.current;
@@ -21323,9 +21496,62 @@ function OhhwellsBridge() {
21323
21496
  if (e.data?.type !== "ow:duplicate-section") return;
21324
21497
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
21325
21498
  if (!instanceId) return;
21499
+ const currentPath = window.location.pathname;
21500
+ if (instanceId.startsWith("scheduling-")) {
21501
+ const sourceInsertAfter = instanceId.slice("scheduling-".length);
21502
+ const tracker = getSectionsTracker();
21503
+ let sections = [];
21504
+ try {
21505
+ sections = JSON.parse(tracker.textContent || "[]");
21506
+ } catch {
21507
+ }
21508
+ const source = sections.find(
21509
+ (s) => s.type === "scheduling" && s.insertAfter === sourceInsertAfter && (!s.pagePath || s.pagePath === currentPath)
21510
+ );
21511
+ const duplicated = duplicateSchedulingWidget(instanceId, source?.scheduleId ?? null);
21512
+ if (!duplicated) return;
21513
+ const currentEntries2 = getPageSectionOrderEntries(
21514
+ editContentRef.current[SECTION_ORDER_KEY],
21515
+ currentPath
21516
+ );
21517
+ const byId = new Map(currentEntries2.map((entry) => [entry.instanceId, entry]));
21518
+ const entries2 = topLevelSections().map((el, order) => {
21519
+ const id = instanceIdOf(el);
21520
+ return {
21521
+ instanceId: id,
21522
+ type: el.getAttribute("data-ohw-section") ?? "",
21523
+ order,
21524
+ pagePath: currentPath,
21525
+ ...byId.get(id)?.removed ? { removed: true } : {}
21526
+ };
21527
+ });
21528
+ const orderJson2 = JSON.stringify(entries2);
21529
+ const nodes2 = [
21530
+ { key: "__ohw_sections", text: tracker.textContent ?? "[]" },
21531
+ { key: SECTION_ORDER_KEY, text: orderJson2 }
21532
+ ];
21533
+ editContentRef.current = {
21534
+ ...editContentRef.current,
21535
+ ...Object.fromEntries(nodes2.map(({ key, text }) => [key, text]))
21536
+ };
21537
+ setAiSectionOrder(orderJson2, currentPath);
21538
+ postToParentRef.current({ type: "ow:change", nodes: nodes2 });
21539
+ window.dispatchEvent(new Event("resize"));
21540
+ const duplicateHeight2 = document.body.scrollHeight;
21541
+ if (duplicateHeight2 > 50) postToParentRef.current({ type: "ow:height", height: duplicateHeight2 });
21542
+ const selectDuplicate = () => {
21543
+ const clone2 = document.querySelector(
21544
+ `[data-ohw-section-container="scheduling"][data-ohw-instance="${CSS.escape(duplicated.sectionId)}"]`
21545
+ );
21546
+ if (clone2) aiSectionApiRef.current?.selectFromElement(clone2);
21547
+ };
21548
+ selectDuplicate();
21549
+ requestAnimationFrame(selectDuplicate);
21550
+ return;
21551
+ }
21326
21552
  const newId = newInstanceId();
21327
- const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
21328
- const result = duplicateSectionInstance(instanceId, newId, window.location.pathname, currentEntries);
21553
+ const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], currentPath);
21554
+ const result = duplicateSectionInstance(instanceId, newId, currentPath, currentEntries);
21329
21555
  if (!result) return;
21330
21556
  const { entries, keyRekeys } = result;
21331
21557
  const orderJson = JSON.stringify(
@@ -22261,7 +22487,7 @@ function OhhwellsBridge() {
22261
22487
  postToParent2({
22262
22488
  type: "ow:ready",
22263
22489
  version: "1",
22264
- bridgeVersion: "0.1.101",
22490
+ bridgeVersion: "0.1.104",
22265
22491
  path: pathname,
22266
22492
  nodes: collectEditableNodes(editContentRef.current),
22267
22493
  sections