@ohhwells/bridge 0.1.122-next.338 → 0.1.123

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
@@ -46,7 +46,6 @@ __export(index_exports, {
46
46
  DropdownMenuItem: () => DropdownMenuItem,
47
47
  DropdownMenuSeparator: () => DropdownMenuSeparator,
48
48
  DropdownMenuTrigger: () => DropdownMenuTrigger,
49
- EmptySection: () => EmptySection,
50
49
  ItemActionToolbar: () => ItemActionToolbar,
51
50
  ItemInteractionLayer: () => ItemInteractionLayer,
52
51
  LinkEditorPanel: () => LinkEditorPanel,
@@ -1753,22 +1752,6 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
1753
1752
  function textAttrs(ctx, path) {
1754
1753
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
1755
1754
  }
1756
- var AI_RESPONSIVE_CSS = [
1757
- "@media (max-width: 960px) {",
1758
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
1759
- ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
1760
- "}",
1761
- "@media (max-width: 640px) {",
1762
- " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
1763
- " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
1764
- // Group containers flatten to a column on phones; span placements come along for free.
1765
- " [data-ai-responsive] [data-ai-group] { display: flex !important; flex-direction: column !important; }",
1766
- " [data-ai-responsive] [data-ai-group] > * { grid-column: auto !important; }",
1767
- " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
1768
- " [data-ai-responsive] { overflow-x: hidden; }",
1769
- " [data-ai-responsive] img { max-width: 100%; }",
1770
- "}"
1771
- ].join("\n");
1772
1755
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
1773
1756
  function MediaBox({
1774
1757
  refValue,
@@ -1786,9 +1769,9 @@ function MediaBox({
1786
1769
  const url = refValue ? ctx.resolveMedia(refValue) : null;
1787
1770
  const isIcon = /^(lucide|simple):/.test(refValue);
1788
1771
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
1789
- const editAttrs = ctx.keyFor && editPath ? {
1772
+ const editAttrs = ctx.keyFor && editPath && !isIcon ? {
1790
1773
  "data-ohw-key": ctx.keyFor(editPath),
1791
- ...isIcon ? { "data-ohw-editable": "icon" } : genericImageEdit ? { "data-ohw-editable": "image" } : {}
1774
+ ...genericImageEdit ? { "data-ohw-editable": "image" } : {}
1792
1775
  } : {};
1793
1776
  if (isIcon) {
1794
1777
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
@@ -1796,7 +1779,6 @@ function MediaBox({
1796
1779
  "span",
1797
1780
  {
1798
1781
  "data-ai-icon": refValue,
1799
- ...editAttrs,
1800
1782
  style: {
1801
1783
  display: "inline-flex",
1802
1784
  width: 48,
@@ -2855,7 +2837,7 @@ function CollectionBlock({ node, ctx, path }) {
2855
2837
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2856
2838
  "div",
2857
2839
  {
2858
- "data-ai-grid": String(itemsPerRow),
2840
+ "data-ai-grid": "",
2859
2841
  "data-ohw-pricing-collection": isPricing ? "" : void 0,
2860
2842
  style: {
2861
2843
  display: "grid",
@@ -3214,7 +3196,6 @@ function AiTreeRenderer({
3214
3196
  {
3215
3197
  "data-ai-section": tree.tag ?? "",
3216
3198
  ...bgAttrs,
3217
- "data-ai-responsive": "",
3218
3199
  style: {
3219
3200
  position: "relative",
3220
3201
  padding: `${pad}px 0`,
@@ -3225,13 +3206,12 @@ function AiTreeRenderer({
3225
3206
  color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
3226
3207
  },
3227
3208
  children: [
3228
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
3229
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
3230
3209
  isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
3210
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
3231
3211
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3232
3212
  "div",
3233
3213
  {
3234
- "data-ai-section-inner": "",
3214
+ "data-ai-container": "",
3235
3215
  style: {
3236
3216
  position: "relative",
3237
3217
  maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
@@ -3242,7 +3222,7 @@ function AiTreeRenderer({
3242
3222
  children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
3243
3223
  "div",
3244
3224
  {
3245
- "data-ai-columns": "",
3225
+ "data-ai-row": "",
3246
3226
  style: {
3247
3227
  display: "grid",
3248
3228
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -3646,10 +3626,9 @@ function applyAiSectionsToDom(state, options) {
3646
3626
  if (existing && existing.serialized === serialized && existing.container.isConnected) {
3647
3627
  continue;
3648
3628
  }
3629
+ const isNewMount = !existing || !existing.container.isConnected;
3649
3630
  let container = existing?.container;
3650
- let isNewMount = false;
3651
3631
  if (!container || !container.isConnected) {
3652
- isNewMount = true;
3653
3632
  existing?.root.unmount();
3654
3633
  container?.remove();
3655
3634
  container = document.createElement("div");
@@ -4038,7 +4017,6 @@ function EmptyState({ inEditor, insertAfter }) {
4038
4017
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4039
4018
  "button",
4040
4019
  {
4041
- "data-ohw-bridge": true,
4042
4020
  onClick: handleAddSchedule,
4043
4021
  className: "h-9 px-2 py-1.5 flex items-center justify-center bg-white border border-[#E7E5E4] rounded-md font-body text-sm font-medium text-(--color-dark,#200C02) cursor-pointer",
4044
4022
  children: "Add Schedule"
@@ -4456,7 +4434,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
4456
4434
  const timer = setTimeout(() => {
4457
4435
  if (!done) {
4458
4436
  done = true;
4459
- innerCleanup = loadWithId(null);
4437
+ setLoading(false);
4460
4438
  }
4461
4439
  }, 2e3);
4462
4440
  const configHandler = (e) => {
@@ -9544,7 +9522,6 @@ function MediaOverlay({
9544
9522
  (prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
9545
9523
  );
9546
9524
  }, [isVideo]);
9547
- const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
9548
9525
  const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
9549
9526
  const box = {
9550
9527
  position: "fixed",
@@ -9643,10 +9620,11 @@ function MediaOverlay({
9643
9620
  className: "flex items-center justify-center cursor-pointer",
9644
9621
  style: {
9645
9622
  ...box,
9646
- // Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
9647
- // (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
9648
- // and cueOnly also need clicks to fall through — Replace / video controls opt back in.
9649
- pointerEvents: "none",
9623
+ // When text overlays this media, let clicks fall THROUGH to the text underneath. In the
9624
+ // parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
9625
+ // in-document, pointer-events does it natively. The button below opts back in, so
9626
+ // Replace still works.
9627
+ pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
9650
9628
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
9651
9629
  // than hovered. Hover keeps the existing tinted preview.
9652
9630
  boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
@@ -9673,17 +9651,17 @@ function MediaOverlay({
9673
9651
  },
9674
9652
  children: [
9675
9653
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
9676
- replaceLabel
9654
+ isVideo ? "Replace video" : "Replace image"
9677
9655
  ]
9678
9656
  }
9679
9657
  ),
9680
- showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
9658
+ replaceMode === "none" || cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
9681
9659
  Button,
9682
9660
  {
9683
9661
  "data-ohw-media-overlay": "",
9684
9662
  variant: "outline",
9685
9663
  size: "sm",
9686
- "aria-label": replaceLabel,
9664
+ "aria-label": isVideo ? "Replace video" : "Replace image",
9687
9665
  className: "gap-1.5 cursor-pointer hover:bg-background",
9688
9666
  style: {
9689
9667
  ...OVERLAY_BUTTON_STYLE,
@@ -9706,7 +9684,7 @@ function MediaOverlay({
9706
9684
  },
9707
9685
  children: [
9708
9686
  isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
9709
- replaceMode === "full" ? replaceLabel : null
9687
+ replaceMode === "full" ? isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image" : null
9710
9688
  ]
9711
9689
  }
9712
9690
  )
@@ -16040,7 +16018,6 @@ function readLogoSizeState(content, placement) {
16040
16018
  function getLogoElement(el) {
16041
16019
  const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
16042
16020
  if (marked) return marked;
16043
- if (el.closest('[data-ohw-editable="icon"]')) return null;
16044
16021
  const root = el.closest("nav, [data-ohw-nav-root], footer");
16045
16022
  if (!root) return null;
16046
16023
  const anchor = el.closest("a");
@@ -19640,10 +19617,21 @@ function parseSchedulingInsertAfter(insertAfter) {
19640
19617
  insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
19641
19618
  };
19642
19619
  }
19643
- function resolveEntryAnchor(entry) {
19644
- if (entry.anchorId !== void 0) return { anchorId: entry.anchorId, beforeId: entry.beforeId ?? null };
19645
- const parsed = parseSchedulingInsertAfter(entry.insertAfter);
19646
- return { anchorId: parsed.anchor, beforeId: parsed.insertBefore };
19620
+ function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
19621
+ const parsed = parseSchedulingInsertAfter(insertAfter);
19622
+ const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
19623
+ const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
19624
+ return { effectiveInsertAfter, insertBefore };
19625
+ }
19626
+ function getSchedulingMountPoint(insertAfter) {
19627
+ const { anchor } = parseSchedulingInsertAfter(insertAfter);
19628
+ let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
19629
+ if (!anchorEl && anchor === "scheduling") {
19630
+ const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
19631
+ anchorEl = widgets.at(-1) ?? null;
19632
+ }
19633
+ if (!anchorEl) return null;
19634
+ return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
19647
19635
  }
19648
19636
  function schedulingMountDepth(insertAfter) {
19649
19637
  if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
@@ -19660,7 +19648,8 @@ function getPageSchedulingEntries(raw) {
19660
19648
  }
19661
19649
  }
19662
19650
  function isSchedulingWidgetMissing(entry) {
19663
- return !document.querySelector(`[data-ohw-section="${schedulingSectionId(entry.insertAfter)}"]`);
19651
+ const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
19652
+ return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
19664
19653
  }
19665
19654
  function hasMissingSchedulingWidgets(entries) {
19666
19655
  return entries.some(isSchedulingWidgetMissing);
@@ -19698,18 +19687,17 @@ function initSectionsFromContent(content, removeExisting = false, currentPath =
19698
19687
  } catch {
19699
19688
  }
19700
19689
  }
19701
- function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, beforeId, existingWidgetId) {
19702
- const widgetId = existingWidgetId ?? (beforeId ? `${anchorId}${INSERT_BEFORE_MARKER}${beforeId}` : anchorId);
19703
- const sectionId = schedulingSectionId(widgetId);
19690
+ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
19691
+ const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
19692
+ const sectionId = schedulingSectionId(effectiveInsertAfter);
19704
19693
  if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
19705
- const anchorEl = document.querySelector(`[data-ohw-section="${anchorId}"]`);
19706
- if (!anchorEl) return false;
19707
- const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
19694
+ const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
19695
+ if (!mountPoint) return false;
19708
19696
  const container = document.createElement("div");
19709
19697
  container.dataset.ohwSectionContainer = "scheduling";
19710
19698
  container.dataset.ohwInstance = sectionId;
19711
- if (beforeId) {
19712
- const beforeAnchor = document.querySelector(`[data-ohw-section="${beforeId}"]`);
19699
+ if (insertBefore) {
19700
+ const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
19713
19701
  const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
19714
19702
  if (!beforePoint) return false;
19715
19703
  beforePoint.insertAdjacentElement("beforebegin", container);
@@ -19720,26 +19708,20 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
19720
19708
  }
19721
19709
  tail.insertAdjacentElement("afterend", container);
19722
19710
  }
19723
- try {
19724
- const root = (0, import_client2.createRoot)(container);
19725
- schedulingRoots.set(container, root);
19726
- (0, import_react_dom4.flushSync)(() => {
19727
- root.render(
19728
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
19729
- SchedulingWidget,
19730
- {
19731
- notifyOnConnect,
19732
- initialScheduleId: scheduleId,
19733
- insertAfter: widgetId
19734
- }
19735
- )
19736
- );
19737
- });
19738
- } catch (err) {
19739
- console.error("[ow:scheduling] render threw", err);
19740
- container.remove();
19741
- return false;
19742
- }
19711
+ const root = (0, import_client2.createRoot)(container);
19712
+ schedulingRoots.set(container, root);
19713
+ (0, import_react_dom4.flushSync)(() => {
19714
+ root.render(
19715
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
19716
+ SchedulingWidget,
19717
+ {
19718
+ notifyOnConnect,
19719
+ initialScheduleId: scheduleId,
19720
+ insertAfter: effectiveInsertAfter
19721
+ }
19722
+ )
19723
+ );
19724
+ });
19743
19725
  const tracker = getSectionsTracker();
19744
19726
  let sections = [];
19745
19727
  try {
@@ -19747,12 +19729,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
19747
19729
  } catch {
19748
19730
  }
19749
19731
  const inEditor = typeof window !== "undefined" && window.self !== window.top;
19750
- if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === widgetId)) {
19732
+ if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
19751
19733
  sections.push({
19752
19734
  type: "scheduling",
19753
- insertAfter: widgetId,
19754
- anchorId,
19755
- beforeId: beforeId ?? null,
19735
+ insertAfter: effectiveInsertAfter,
19756
19736
  pagePath: window.location.pathname,
19757
19737
  ...scheduleId ? { scheduleId } : {}
19758
19738
  });
@@ -19766,8 +19746,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
19766
19746
  for (let i = pending.length - 1; i >= 0; i--) {
19767
19747
  const entry = pending[i];
19768
19748
  const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
19769
- const { anchorId, beforeId } = resolveEntryAnchor(entry);
19770
- if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
19749
+ if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId ?? null)) {
19771
19750
  pending.splice(i, 1);
19772
19751
  }
19773
19752
  }
@@ -19944,11 +19923,6 @@ function applyLinkByKey(key, val) {
19944
19923
  hrefAnchors.forEach((el) => applyLinkHref(el, val));
19945
19924
  }
19946
19925
  }
19947
- function isInsideLinkEditor(target) {
19948
- return Boolean(
19949
- target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
19950
- );
19951
- }
19952
19926
  function isInsideFloatingPanel(target) {
19953
19927
  return Boolean(target.closest("[data-ohw-floating-panel]"));
19954
19928
  }
@@ -19956,6 +19930,11 @@ function isPointOverFloatingPanel(clientX, clientY) {
19956
19930
  const el = document.elementFromPoint(clientX, clientY);
19957
19931
  return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
19958
19932
  }
19933
+ function isInsideLinkEditor(target) {
19934
+ return Boolean(
19935
+ target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
19936
+ );
19937
+ }
19959
19938
  function getHrefKeyFromElement(el) {
19960
19939
  if (!el) return null;
19961
19940
  const anchor = el.closest("[data-ohw-href-key]");
@@ -20234,7 +20213,7 @@ function getNavigationSelectionParent(el) {
20234
20213
  if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
20235
20214
  return getFooterLinksContainer();
20236
20215
  }
20237
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
20216
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
20238
20217
  return getNavigationRoot(el);
20239
20218
  }
20240
20219
  return null;
@@ -20456,6 +20435,7 @@ var ICONS = {
20456
20435
  insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
20457
20436
  insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
20458
20437
  };
20438
+ var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
20459
20439
  var SELECTION_CHROME_GAP2 = 4;
20460
20440
  var TOOLBAR_STROKE_GAP2 = 4;
20461
20441
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
@@ -20829,7 +20809,6 @@ function StateToggle({
20829
20809
  );
20830
20810
  }
20831
20811
  var contentCache = /* @__PURE__ */ new Map();
20832
- var fetchedContentPaths = /* @__PURE__ */ new Set();
20833
20812
  var brandingCache = /* @__PURE__ */ new Map();
20834
20813
  var OHW_LOADER_STYLE = {
20835
20814
  position: "fixed",
@@ -21433,6 +21412,21 @@ function OhhwellsBridge() {
21433
21412
  const [isItemDragging, setIsItemDragging] = (0, import_react19.useState)(false);
21434
21413
  const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react19.useState)(false);
21435
21414
  isFooterFrameSelectionRef.current = isFooterFrameSelection;
21415
+ const [floatingPanel, setFloatingPanel] = (0, import_react19.useState)(null);
21416
+ const floatingPanelOpenRef = (0, import_react19.useRef)(false);
21417
+ floatingPanelOpenRef.current = floatingPanel !== null;
21418
+ const floatingPanelRef = (0, import_react19.useRef)(null);
21419
+ floatingPanelRef.current = floatingPanel;
21420
+ const [floatingPanelPos, setFloatingPanelPos] = (0, import_react19.useState)(null);
21421
+ const buttonCollectionDragRef = (0, import_react19.useRef)(null);
21422
+ const buttonDropInsertIndexRef = (0, import_react19.useRef)(null);
21423
+ const [buttonDropSlots, setButtonDropSlots] = (0, import_react19.useState)([]);
21424
+ const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react19.useState)(null);
21425
+ const buttonPointerDragRef = (0, import_react19.useRef)(null);
21426
+ const [buttonStyleTick, setButtonStyleTick] = (0, import_react19.useState)(0);
21427
+ const [logoSizeDraft, setLogoSizeDraft] = (0, import_react19.useState)(null);
21428
+ const [editorViewport, setEditorViewport] = (0, import_react19.useState)("desktop");
21429
+ const [parentScrollSnap, setParentScrollSnap] = (0, import_react19.useState)(null);
21436
21430
  const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react19.useState)(null);
21437
21431
  const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react19.useState)(null);
21438
21432
  const footerDragRef = (0, import_react19.useRef)(null);
@@ -21456,21 +21450,6 @@ function OhhwellsBridge() {
21456
21450
  const stylesRef = (0, import_react19.useRef)("");
21457
21451
  const appliedDrawerRef = (0, import_react19.useRef)(null);
21458
21452
  const pendingDeleteUndoRef = (0, import_react19.useRef)(null);
21459
- const [floatingPanel, setFloatingPanel] = (0, import_react19.useState)(null);
21460
- const floatingPanelOpenRef = (0, import_react19.useRef)(false);
21461
- const floatingPanelRef = (0, import_react19.useRef)(null);
21462
- floatingPanelRef.current = floatingPanel;
21463
- const setFloatingPanelRef = (0, import_react19.useRef)(setFloatingPanel);
21464
- const [floatingPanelPos, setFloatingPanelPos] = (0, import_react19.useState)(null);
21465
- const buttonCollectionDragRef = (0, import_react19.useRef)(null);
21466
- const buttonDropInsertIndexRef = (0, import_react19.useRef)(null);
21467
- const [buttonDropSlots, setButtonDropSlots] = (0, import_react19.useState)([]);
21468
- const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react19.useState)(null);
21469
- const buttonPointerDragRef = (0, import_react19.useRef)(null);
21470
- const [buttonStyleTick, setButtonStyleTick] = (0, import_react19.useState)(0);
21471
- const [logoSizeDraft, setLogoSizeDraft] = (0, import_react19.useState)(null);
21472
- const [editorViewport, setEditorViewport] = (0, import_react19.useState)("desktop");
21473
- const [parentScrollSnap, setParentScrollSnap] = (0, import_react19.useState)(null);
21474
21453
  const [sitePages, setSitePages] = (0, import_react19.useState)([]);
21475
21454
  const [sectionsByPath, setSectionsByPath] = (0, import_react19.useState)({});
21476
21455
  const sectionsPrefetchGenRef = (0, import_react19.useRef)(0);
@@ -21479,18 +21458,7 @@ function OhhwellsBridge() {
21479
21458
  const linkPopoverOpenRef = (0, import_react19.useRef)(false);
21480
21459
  const linkPopoverGraceUntilRef = (0, import_react19.useRef)(0);
21481
21460
  setLinkPopoverRef.current = setLinkPopover;
21482
- setFloatingPanelRef.current = setFloatingPanel;
21483
21461
  linkPopoverSessionRef.current = linkPopover;
21484
- floatingPanelOpenRef.current = Boolean(floatingPanel);
21485
- (0, import_react19.useEffect)(() => {
21486
- const syncViewport = () => {
21487
- const next = window.innerWidth <= 480 ? "mobile" : "desktop";
21488
- setEditorViewport((prev) => prev === next ? prev : next);
21489
- };
21490
- syncViewport();
21491
- window.addEventListener("resize", syncViewport);
21492
- return () => window.removeEventListener("resize", syncViewport);
21493
- }, []);
21494
21462
  (0, import_react19.useEffect)(() => {
21495
21463
  setSectionOrderPersistHandler((entries) => {
21496
21464
  const currentPath = window.location.pathname;
@@ -23008,7 +22976,6 @@ function OhhwellsBridge() {
23008
22976
  }
23009
22977
  if (typeof content[STYLE_STORE_KEY] === "string") {
23010
22978
  stylesRef.current = content[STYLE_STORE_KEY];
23011
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
23012
22979
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
23013
22980
  }
23014
22981
  applyBrandChrome(content);
@@ -23017,12 +22984,12 @@ function OhhwellsBridge() {
23017
22984
  for (const [key, val] of Object.entries(content)) {
23018
22985
  if (key === "__ohw_sections") continue;
23019
22986
  if (key === AI_SECTIONS_KEY) continue;
23020
- if (key === LOGO_PLACEHOLDER_KEY) continue;
23021
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
23022
22987
  if (key === BRAND_KIT_KEY) continue;
23023
22988
  if (key === STYLE_STORE_KEY) continue;
23024
22989
  if (BRAND_CHROME_KEYS.has(key)) continue;
22990
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
23025
22991
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
22992
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
23026
22993
  if (applyVideoSettingNode(key, val)) continue;
23027
22994
  if (applyCarouselNode(key, val)) continue;
23028
22995
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -23094,9 +23061,7 @@ function OhhwellsBridge() {
23094
23061
  let cancelled = false;
23095
23062
  setFetchState("loading");
23096
23063
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
23097
- const initialPath = pathname;
23098
- fetchedContentPaths.add(`${subdomain}::${initialPath}`);
23099
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
23064
+ fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
23100
23065
  if (cancelled) return;
23101
23066
  const content = data?.content ?? {};
23102
23067
  const branding = Boolean(data?.showBranding);
@@ -23232,17 +23197,16 @@ function OhhwellsBridge() {
23232
23197
  applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
23233
23198
  }
23234
23199
  if (typeof content[STYLE_STORE_KEY] === "string") {
23235
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
23236
23200
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
23237
23201
  }
23238
23202
  for (const [key, val] of Object.entries(content)) {
23239
23203
  if (key === "__ohw_sections") continue;
23240
23204
  if (key === AI_SECTIONS_KEY) continue;
23241
- if (key === LOGO_PLACEHOLDER_KEY) continue;
23242
- if (LOGO_IMAGE_KEYS.includes(key)) continue;
23243
23205
  if (key === BRAND_KIT_KEY) continue;
23244
23206
  if (key === STYLE_STORE_KEY) continue;
23245
23207
  if (BRAND_CHROME_KEYS.has(key)) continue;
23208
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
23209
+ if (LOGO_IMAGE_KEYS.includes(key)) continue;
23246
23210
  if (applyVideoSettingNode(key, val)) continue;
23247
23211
  if (applyCarouselNode(key, val)) continue;
23248
23212
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -23294,17 +23258,6 @@ function OhhwellsBridge() {
23294
23258
  debounceTimer = setTimeout(applyFromCache, 150);
23295
23259
  };
23296
23260
  applyFromCache();
23297
- const pathCacheKey = `${subdomain}::${pathname}`;
23298
- if (!fetchedContentPaths.has(pathCacheKey)) {
23299
- fetchedContentPaths.add(pathCacheKey);
23300
- const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
23301
- fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
23302
- if (!data?.content) return;
23303
- contentCache.set(subdomain, data.content);
23304
- applyFromCache();
23305
- }).catch(() => {
23306
- });
23307
- }
23308
23261
  observer = new MutationObserver(scheduleApply);
23309
23262
  observer.observe(document.body, { childList: true, subtree: true });
23310
23263
  return () => {
@@ -23493,11 +23446,26 @@ function OhhwellsBridge() {
23493
23446
  const t2 = setTimeout(measure, 500);
23494
23447
  const ro = new ResizeObserver(schedule);
23495
23448
  ro.observe(document.body);
23449
+ let lastWidth = window.innerWidth;
23450
+ let resizeTimers = [];
23451
+ const clearResizeTimers = () => {
23452
+ resizeTimers.forEach(clearTimeout);
23453
+ resizeTimers = [];
23454
+ };
23455
+ const handleResize = () => {
23456
+ if (window.innerWidth === lastWidth) return;
23457
+ lastWidth = window.innerWidth;
23458
+ clearResizeTimers();
23459
+ resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
23460
+ };
23461
+ window.addEventListener("resize", handleResize);
23496
23462
  return () => {
23497
23463
  clearTimeout(t1);
23498
23464
  clearTimeout(t2);
23499
23465
  if (raf != null) cancelAnimationFrame(raf);
23500
23466
  ro.disconnect();
23467
+ clearResizeTimers();
23468
+ window.removeEventListener("resize", handleResize);
23501
23469
  };
23502
23470
  }, [pathname, isEditMode, postToParent2]);
23503
23471
  (0, import_react19.useEffect)(() => {
@@ -23792,13 +23760,6 @@ function OhhwellsBridge() {
23792
23760
  if (target.closest("[data-ohw-state-toggle]")) return;
23793
23761
  if (target.closest("[data-ohw-max-badge]")) return;
23794
23762
  if (isInsideLinkEditor(target)) return;
23795
- if (isInsideFloatingPanel(target)) return;
23796
- if (target.closest("[data-ohw-form-toolbar]")) return;
23797
- if (target.closest(
23798
- '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
23799
- )) {
23800
- return;
23801
- }
23802
23763
  if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
23803
23764
  clearMediaSelectionRef.current();
23804
23765
  }
@@ -23819,6 +23780,13 @@ function OhhwellsBridge() {
23819
23780
  return;
23820
23781
  }
23821
23782
  }
23783
+ if (isInsideFloatingPanel(target)) return;
23784
+ if (target.closest("[data-ohw-form-toolbar]")) return;
23785
+ if (target.closest(
23786
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
23787
+ )) {
23788
+ return;
23789
+ }
23822
23790
  {
23823
23791
  const formEl = getFormElement(target);
23824
23792
  const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
@@ -24198,9 +24166,6 @@ function OhhwellsBridge() {
24198
24166
  setHoveredItemRect(null);
24199
24167
  hoveredNavContainerRef.current = null;
24200
24168
  setHoveredNavContainerRect(null);
24201
- siblingHintElRef.current = null;
24202
- setSiblingHintRect(null);
24203
- setSiblingHintRects([]);
24204
24169
  return;
24205
24170
  }
24206
24171
  {
@@ -24321,6 +24286,7 @@ function OhhwellsBridge() {
24321
24286
  hoveredNavContainerRef.current = null;
24322
24287
  setHoveredNavContainerRect(null);
24323
24288
  hoveredItemElRef.current = editable;
24289
+ setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
24324
24290
  }
24325
24291
  }
24326
24292
  }
@@ -24638,7 +24604,7 @@ function OhhwellsBridge() {
24638
24604
  };
24639
24605
  const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
24640
24606
  syncSelectedMediaPointerRelease(true);
24641
- if (linkPopoverOpenRef.current || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
24607
+ if (linkPopoverOpenRef.current) {
24642
24608
  if (hoveredImageRef.current) {
24643
24609
  hoveredImageRef.current = null;
24644
24610
  hoveredImageHasTextOverlapRef.current = false;
@@ -25030,11 +24996,7 @@ function OhhwellsBridge() {
25030
24996
  };
25031
24997
  const handleMouseMove = (e) => {
25032
24998
  const { clientX, clientY } = e;
25033
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
25034
- dismissImageHover();
25035
- clearImageHover();
25036
- return;
25037
- }
24999
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
25038
25000
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
25039
25001
  document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
25040
25002
  formHoverElRef.current = null;
@@ -25063,12 +25025,7 @@ function OhhwellsBridge() {
25063
25025
  setHoveredItemRect(null);
25064
25026
  hoveredNavContainerRef.current = null;
25065
25027
  setHoveredNavContainerRect(null);
25066
- siblingHintElRef.current = null;
25067
- setSiblingHintRect(null);
25068
- setSiblingHintRects([]);
25069
25028
  dismissImageHover();
25070
- clearImageHover();
25071
- setSectionGap(null);
25072
25029
  return;
25073
25030
  }
25074
25031
  if (probeSocialsRowAt(clientX, clientY)) return;
@@ -25080,11 +25037,7 @@ function OhhwellsBridge() {
25080
25037
  if (e.data?.type !== "ow:pointer-sync") return;
25081
25038
  const { clientX, clientY } = e.data;
25082
25039
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
25083
- if (pointOwnedByFloatingPanel(clientX, clientY)) {
25084
- dismissImageHover();
25085
- clearImageHover();
25086
- return;
25087
- }
25040
+ if (pointOwnedByFloatingPanel(clientX, clientY)) return;
25088
25041
  if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
25089
25042
  if (probeSocialsRowAt(clientX, clientY)) return;
25090
25043
  probeSectionGapAt(clientX, clientY);
@@ -25430,7 +25383,6 @@ function OhhwellsBridge() {
25430
25383
  }
25431
25384
  if (typeof content[STYLE_STORE_KEY] === "string") {
25432
25385
  stylesRef.current = content[STYLE_STORE_KEY];
25433
- document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
25434
25386
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
25435
25387
  }
25436
25388
  applyBrandChrome(content);
@@ -25443,12 +25395,12 @@ function OhhwellsBridge() {
25443
25395
  continue;
25444
25396
  }
25445
25397
  if (key === AI_SECTIONS_KEY) continue;
25446
- if (key === LOGO_PLACEHOLDER_KEY) continue;
25447
- if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
25448
25398
  if (key === BRAND_KIT_KEY) continue;
25449
25399
  if (key === STYLE_STORE_KEY) continue;
25450
25400
  if (BRAND_CHROME_KEYS.has(key)) continue;
25401
+ if (key === LOGO_PLACEHOLDER_KEY) continue;
25451
25402
  if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
25403
+ if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
25452
25404
  if (applyVideoSettingNode(key, val)) continue;
25453
25405
  if (applyCarouselNode(key, val)) continue;
25454
25406
  document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
@@ -25894,12 +25846,6 @@ function OhhwellsBridge() {
25894
25846
  closeLinkPopoverRef.current();
25895
25847
  return;
25896
25848
  }
25897
- if (floatingPanelOpenRef.current) {
25898
- setFloatingPanelRef.current(null);
25899
- deselectRef.current();
25900
- deactivateRef.current();
25901
- return;
25902
- }
25903
25849
  deselectRef.current();
25904
25850
  deactivateRef.current();
25905
25851
  clearMediaSelectionRef.current();
@@ -26198,12 +26144,8 @@ function OhhwellsBridge() {
26198
26144
  if (inserted) {
26199
26145
  const tracker = getSectionsTracker();
26200
26146
  postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
26201
- const reportHeight = () => {
26202
- const h = document.body.scrollHeight;
26203
- if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
26204
- };
26205
- reportHeight();
26206
- setTimeout(reportHeight, 500);
26147
+ const h = document.body.scrollHeight;
26148
+ if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
26207
26149
  }
26208
26150
  };
26209
26151
  const handleSwitchSchedule = (e) => {
@@ -26632,10 +26574,10 @@ function OhhwellsBridge() {
26632
26574
  window.removeEventListener("message", handleDeleteSection);
26633
26575
  window.removeEventListener("message", handleDuplicateSection);
26634
26576
  window.removeEventListener("message", handleDeactivate);
26577
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
26635
26578
  window.removeEventListener("message", handleToastAction);
26636
26579
  window.removeEventListener("message", handleFormCount);
26637
26580
  window.removeEventListener("message", handleUiEscape);
26638
- document.documentElement.removeAttribute("data-ohw-panel-dragging");
26639
26581
  autoSaveTimers.current.forEach(clearTimeout);
26640
26582
  autoSaveTimers.current.clear();
26641
26583
  if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
@@ -28016,59 +27958,6 @@ function OhhwellsBridge() {
28016
27958
  ) : null
28017
27959
  ] });
28018
27960
  }
28019
-
28020
- // src/ui/EmptySection.tsx
28021
- var import_link = __toESM(require("next/link"), 1);
28022
- var import_jsx_runtime37 = require("react/jsx-runtime");
28023
- function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
28024
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
28025
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
28026
- "p",
28027
- {
28028
- style: {
28029
- fontFamily: "var(--brand-font-body)",
28030
- fontSize: "0.75rem",
28031
- fontWeight: 500,
28032
- letterSpacing: "0.15em",
28033
- textTransform: "uppercase",
28034
- color: "var(--brand-accent)",
28035
- marginBottom: "1.5rem"
28036
- },
28037
- children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
28038
- }
28039
- ),
28040
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
28041
- "h1",
28042
- {
28043
- style: {
28044
- fontFamily: "var(--brand-font-heading)",
28045
- fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
28046
- lineHeight: 1.1,
28047
- letterSpacing: "-0.025em",
28048
- color: "var(--brand-text)",
28049
- marginBottom: "1rem"
28050
- },
28051
- ...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
28052
- children: title
28053
- }
28054
- ),
28055
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
28056
- "p",
28057
- {
28058
- style: {
28059
- fontFamily: "var(--brand-font-body)",
28060
- fontSize: "1rem",
28061
- lineHeight: 1.7,
28062
- fontWeight: 300,
28063
- color: "var(--brand-text-muted)",
28064
- maxWidth: "340px"
28065
- },
28066
- ...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
28067
- children: "This page doesn't have any content yet."
28068
- }
28069
- )
28070
- ] });
28071
- }
28072
27961
  // Annotate the CommonJS export names for ESM import in node:
28073
27962
  0 && (module.exports = {
28074
27963
  AI_DEFAULT_BRAND,
@@ -28086,7 +27975,6 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
28086
27975
  DropdownMenuItem,
28087
27976
  DropdownMenuSeparator,
28088
27977
  DropdownMenuTrigger,
28089
- EmptySection,
28090
27978
  ItemActionToolbar,
28091
27979
  ItemInteractionLayer,
28092
27980
  LinkEditorPanel,