@ohhwells/bridge 0.1.104 → 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
@@ -10984,9 +10984,18 @@ function getNavbarDrawerContainer() {
10984
10984
  }
10985
10985
  function isNavbarListContainerVisible(el) {
10986
10986
  if (el.hasAttribute("hidden")) return false;
10987
+ if (el.closest("[hidden]")) return false;
10987
10988
  if (el.getClientRects().length === 0) return false;
10988
10989
  const style = window.getComputedStyle(el);
10989
- 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;
10990
10999
  }
10991
11000
  function getActiveNavbarListContainer(draggedEl) {
10992
11001
  const desktop = getNavbarDesktopContainer();
@@ -10997,6 +11006,7 @@ function getActiveNavbarListContainer(draggedEl) {
10997
11006
  }
10998
11007
  if (desktop && isNavbarListContainerVisible(desktop)) return desktop;
10999
11008
  if (drawer && isNavbarListContainerVisible(drawer)) return drawer;
11009
+ if (drawer && !drawer.closest("[hidden]")) return drawer;
11000
11010
  return desktop ?? drawer;
11001
11011
  }
11002
11012
  function listActiveNavbarItems(draggedEl) {
@@ -11009,6 +11019,12 @@ function listActiveNavbarItems(draggedEl) {
11009
11019
  return listNavbarItems();
11010
11020
  }
11011
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
+ }
11012
11028
  const desktop = getNavbarDesktopContainer();
11013
11029
  if (desktop) {
11014
11030
  return Array.from(desktop.querySelectorAll("[data-ohw-href-key]")).filter(isNavbarLinkItem);
@@ -11078,24 +11094,25 @@ function buildNavLink(index, href, label, template) {
11078
11094
  return anchor;
11079
11095
  }
11080
11096
  function insertNavLinkInContainer(container, anchor, afterHrefKey) {
11097
+ const listParent = resolveNavbarReorderParent(container);
11081
11098
  if (!afterHrefKey) {
11082
- const cta = container.querySelector(CTA_BUTTON_SELECTOR);
11083
- if (cta && cta.parentElement === container) {
11084
- container.insertBefore(anchor, cta);
11099
+ const cta = listParent.querySelector(CTA_BUTTON_SELECTOR);
11100
+ if (cta && cta.parentElement === listParent) {
11101
+ listParent.insertBefore(anchor, cta);
11085
11102
  return;
11086
11103
  }
11087
- container.appendChild(anchor);
11104
+ listParent.appendChild(anchor);
11088
11105
  return;
11089
11106
  }
11090
- const afterEl = findCounterpartByHrefKey(afterHrefKey, container);
11107
+ const afterEl = findCounterpartByHrefKey(afterHrefKey, listParent);
11091
11108
  if (afterEl) {
11092
11109
  const insertAfter = resolveNavRootUnit(afterEl);
11093
- if (insertAfter.parentElement === container || insertAfter.parentElement === afterEl.parentElement) {
11110
+ if (insertAfter.parentElement === listParent || insertAfter.parentElement === afterEl.parentElement) {
11094
11111
  insertAfter.insertAdjacentElement("afterend", anchor);
11095
11112
  return;
11096
11113
  }
11097
11114
  }
11098
- container.appendChild(anchor);
11115
+ listParent.appendChild(anchor);
11099
11116
  }
11100
11117
  function insertNavbarItemDom(index, href, label, afterAnchor) {
11101
11118
  const afterHrefKey = afterAnchor?.getAttribute("data-ohw-href-key") ?? null;
@@ -11151,15 +11168,25 @@ function getNavbarRootUnitsInContainer(container) {
11151
11168
  }
11152
11169
  return result;
11153
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
+ }
11154
11180
  function applyNavOrderToContainer(container, order) {
11181
+ const listParent = resolveNavbarReorderParent(container);
11155
11182
  const desired = order.filter((key, i) => order.indexOf(key) === i);
11156
- const units = getNavbarRootUnitsInContainer(container);
11183
+ const units = getNavbarRootUnitsInContainer(listParent);
11157
11184
  const current = units.map((u) => u.key);
11158
11185
  const extras = current.filter((key) => !desired.includes(key));
11159
11186
  const expected = [...desired.filter((key) => current.includes(key)), ...extras];
11160
11187
  if (navOrderKeysEqual(current, expected)) return;
11161
11188
  const lastUnit = units[units.length - 1]?.unit ?? null;
11162
- const anchor = lastUnit?.parentElement === container ? lastUnit.nextElementSibling : null;
11189
+ const anchor = lastUnit?.parentElement === listParent ? lastUnit.nextElementSibling : null;
11163
11190
  const orderedUnits = [];
11164
11191
  const seen = /* @__PURE__ */ new Set();
11165
11192
  for (const hrefKey of desired) {
@@ -11174,9 +11201,9 @@ function applyNavOrderToContainer(container, order) {
11174
11201
  }
11175
11202
  for (const el of orderedUnits) {
11176
11203
  if (anchor) {
11177
- if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
11178
- } else if (container.lastElementChild !== el) {
11179
- container.appendChild(el);
11204
+ if (el.nextSibling !== anchor) listParent.insertBefore(el, anchor);
11205
+ } else if (listParent.lastElementChild !== el) {
11206
+ listParent.appendChild(el);
11180
11207
  }
11181
11208
  }
11182
11209
  }
@@ -12766,26 +12793,48 @@ function resolveFooterColumnForAdd(selected) {
12766
12793
  if (selected.hasAttribute("data-ohw-footer-col")) return selected;
12767
12794
  return selected.closest("[data-ohw-footer-col]") ?? (listFooterColumns().includes(selected) ? selected : null);
12768
12795
  }
12769
- function buildFooterHeading(colIndex, text) {
12770
- const heading = document.createElement("p");
12771
- heading.setAttribute("data-ohw-editable", "text");
12772
- heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
12773
- heading.textContent = text;
12774
- heading.style.cssText = [
12775
- "color: var(--espresso, #3d312b)",
12776
- "font-size: 14px",
12777
- "font-weight: 800",
12778
- "opacity: 0.82",
12779
- "margin: 0 0 6px",
12780
- "padding: 0",
12781
- "line-height: 1.2"
12782
- ].join(";");
12783
- return heading;
12784
- }
12785
12796
  var FOOTER_HEADING_CACHE_ATTR = "data-ohw-heading-cache";
12797
+ var FOOTER_HEADING_CLASS_CACHE_ATTR = "data-ohw-heading-class";
12786
12798
  function getFooterColumnHeadingEl(column) {
12787
12799
  return column.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]') ?? null;
12788
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
+ }
12789
12838
  function getFooterColumnHeadingKey(column) {
12790
12839
  const attr = column.getAttribute("data-ohw-footer-col");
12791
12840
  if (attr != null) {
@@ -12809,8 +12858,11 @@ function setFooterColumnHeadingVisible(column, visible) {
12809
12858
  if (!Number.isFinite(colIndex)) return null;
12810
12859
  const existing = getFooterColumnHeadingEl(column);
12811
12860
  if (!visible) {
12812
- 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;
12813
12862
  column.setAttribute(FOOTER_HEADING_CACHE_ATTR, text2);
12863
+ if (existing?.className) {
12864
+ column.setAttribute(FOOTER_HEADING_CLASS_CACHE_ATTR, existing.className);
12865
+ }
12814
12866
  existing?.remove();
12815
12867
  return { headingKey, text: "", visible: false };
12816
12868
  }
@@ -12822,7 +12874,7 @@ function setFooterColumnHeadingVisible(column, visible) {
12822
12874
  };
12823
12875
  }
12824
12876
  const text = column.getAttribute(FOOTER_HEADING_CACHE_ATTR) || DEFAULT_FOOTER_COLUMN_HEADING;
12825
- const heading = buildFooterHeading(colIndex, text);
12877
+ const heading = buildFooterHeading(colIndex, text, { column });
12826
12878
  const firstLink = listFooterLinksInColumn(column)[0];
12827
12879
  if (firstLink) column.insertBefore(heading, firstLink);
12828
12880
  else column.prepend(heading);
@@ -12846,21 +12898,24 @@ function reconcileFooterHeadingVisibility(content) {
12846
12898
  if (raw === "") {
12847
12899
  const existing2 = getFooterColumnHeadingEl(column);
12848
12900
  if (existing2) {
12849
- const cached = (existing2.textContent ?? "").trim();
12901
+ const cached = existing2.innerHTML.trim() || (existing2.textContent ?? "").trim();
12850
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
+ }
12851
12906
  existing2.remove();
12852
12907
  }
12853
12908
  continue;
12854
12909
  }
12855
12910
  const existing = getFooterColumnHeadingEl(column);
12856
12911
  if (existing) {
12857
- if (existing.textContent !== raw) existing.textContent = raw;
12912
+ applyFooterHeadingContent(existing, raw);
12858
12913
  continue;
12859
12914
  }
12860
12915
  const colMatch = headingKey.match(FOOTER_HEADING_RE);
12861
12916
  const colIndex = colMatch ? parseInt(colMatch[1], 10) : NaN;
12862
12917
  if (!Number.isFinite(colIndex)) continue;
12863
- const heading = buildFooterHeading(colIndex, raw);
12918
+ const heading = buildFooterHeading(colIndex, raw, { column });
12864
12919
  const firstLink = listFooterLinksInColumn(column)[0];
12865
12920
  if (firstLink) column.insertBefore(heading, firstLink);
12866
12921
  else column.prepend(heading);
@@ -12906,9 +12961,13 @@ function insertFooterColumnDom(colIndex, heading, items) {
12906
12961
  column.style.flexDirection = "column";
12907
12962
  }
12908
12963
  if (heading != null && heading !== "") {
12909
- column.appendChild(buildFooterHeading(colIndex, heading));
12964
+ column.appendChild(buildFooterHeading(colIndex, heading, { column }));
12910
12965
  } else if (heading === "") {
12911
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
+ }
12912
12971
  }
12913
12972
  let firstLink = null;
12914
12973
  items.forEach((item, itemIndex) => {
@@ -15752,6 +15811,66 @@ function unmountSchedulingWrapper(wrapper) {
15752
15811
  function schedulingSectionId(insertAfter) {
15753
15812
  return `scheduling-${insertAfter}`;
15754
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
+ }
15755
15874
  var INSERT_BEFORE_MARKER = ":before:";
15756
15875
  function parseSchedulingInsertAfter(insertAfter) {
15757
15876
  const idx = insertAfter.indexOf(INSERT_BEFORE_MARKER);
@@ -21377,9 +21496,62 @@ function OhhwellsBridge() {
21377
21496
  if (e.data?.type !== "ow:duplicate-section") return;
21378
21497
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
21379
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
+ }
21380
21552
  const newId = newInstanceId();
21381
- const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], window.location.pathname);
21382
- 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);
21383
21555
  if (!result) return;
21384
21556
  const { entries, keyRekeys } = result;
21385
21557
  const orderJson = JSON.stringify(
@@ -22315,7 +22487,7 @@ function OhhwellsBridge() {
22315
22487
  postToParent2({
22316
22488
  type: "ow:ready",
22317
22489
  version: "1",
22318
- bridgeVersion: "0.1.103",
22490
+ bridgeVersion: "0.1.104",
22319
22491
  path: pathname,
22320
22492
  nodes: collectEditableNodes(editContentRef.current),
22321
22493
  sections