@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.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);
@@ -21310,9 +21429,62 @@ function OhhwellsBridge() {
21310
21429
  if (e.data?.type !== "ow:duplicate-section") return;
21311
21430
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
21312
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
+ }
21313
21485
  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);
21486
+ const currentEntries = getPageSectionOrderEntries(editContentRef.current[SECTION_ORDER_KEY], currentPath);
21487
+ const result = duplicateSectionInstance(instanceId, newId, currentPath, currentEntries);
21316
21488
  if (!result) return;
21317
21489
  const { entries, keyRekeys } = result;
21318
21490
  const orderJson = JSON.stringify(
@@ -22248,7 +22420,7 @@ function OhhwellsBridge() {
22248
22420
  postToParent2({
22249
22421
  type: "ow:ready",
22250
22422
  version: "1",
22251
- bridgeVersion: "0.1.103",
22423
+ bridgeVersion: "0.1.104",
22252
22424
  path: pathname,
22253
22425
  nodes: collectEditableNodes(editContentRef.current),
22254
22426
  sections