@ohhwells/bridge 0.1.93-next.277 → 0.1.93-next.281

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
@@ -556,7 +556,9 @@ function styleSheetCss() {
556
556
  }
557
557
  rules.push(
558
558
  `[data-ohw-style-corners="sharp"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: 0 !important; }`,
559
- `[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`
559
+ `[data-ohw-style-corners="sharp"] :has(> img) { border-radius: 0 !important; }`,
560
+ `[data-ohw-style-corners="rounded"] :is(.card, [data-ohw-card], img, picture, figure, [data-ohw-editable="bg-image"]) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`,
561
+ `[data-ohw-style-corners="rounded"] :has(> img) { border-radius: max(0.75rem, var(--radius, 0px)) !important; }`
560
562
  );
561
563
  for (const align of ["left", "center", "right"]) {
562
564
  rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
@@ -651,14 +653,39 @@ function buttonSurfaceOf(el) {
651
653
  }
652
654
  function alignSubjectOf(el) {
653
655
  const button = el.closest('[data-ohw-role="button"]');
654
- return button?.parentElement ?? el;
656
+ if (button?.parentElement) return button.parentElement;
657
+ let subject = el;
658
+ while (subject.parentElement && !subject.parentElement.hasAttribute("data-ohw-section") && /^inline/.test(getComputedStyle(subject).display)) {
659
+ subject = subject.parentElement;
660
+ }
661
+ const TEXT_ROW = /^(P|LI|H[1-6]|BLOCKQUOTE|FIGCAPTION|DT|DD)$/;
662
+ const parent = subject.parentElement;
663
+ if (parent && TEXT_ROW.test(parent.tagName) && /^(inline-)?flex$/.test(getComputedStyle(parent).display)) {
664
+ return parent;
665
+ }
666
+ if (parent && !parent.hasAttribute("data-ohw-section")) {
667
+ const pcs = getComputedStyle(parent);
668
+ const children = Array.from(parent.children);
669
+ const textRowChild = (c) => c.hasAttribute("data-ohw-editable") || (c.textContent ?? "").trim().length === 0 || c.getAttribute("aria-hidden") === "true";
670
+ if (/^(inline-)?flex$/.test(pcs.display) && pcs.flexDirection.startsWith("row") && children.length > 0 && children.some((c) => c.hasAttribute("data-ohw-editable")) && children.every(textRowChild)) {
671
+ return parent;
672
+ }
673
+ }
674
+ const row = subject.closest("li");
675
+ if (row && row !== subject && /^(inline-)?flex$/.test(getComputedStyle(row).display)) {
676
+ return row;
677
+ }
678
+ return subject;
655
679
  }
656
680
  function applyStylesToDom(store) {
657
681
  ensureStyleSheet();
658
682
  clearSectionAttrs(document);
659
683
  clearNodeProps(document);
660
684
  loadStyleFonts(
661
- store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
685
+ store ? [
686
+ ...Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []),
687
+ ...Object.values(store.sections).flatMap((s) => s.fontFamily ? [s.fontFamily] : [])
688
+ ] : []
662
689
  );
663
690
  if (!store) return;
664
691
  for (const [sectionId, override] of Object.entries(store.sections)) {
@@ -678,6 +705,23 @@ function applyStylesToDom(store) {
678
705
  section.style.setProperty("background", override.sectionBackgroundColor, "important");
679
706
  section.setAttribute("data-ohw-style-bgcolor", "");
680
707
  }
708
+ if (override.textColor !== void 0 || override.fontFamily !== void 0) {
709
+ const textEls = marker.querySelectorAll(
710
+ '[data-ohw-editable="text"], [data-ohw-editable="plain"], [data-ohw-field-label]'
711
+ );
712
+ for (const el of Array.from(textEls)) {
713
+ if (override.textColor !== void 0) {
714
+ saveInline(el, "color");
715
+ el.style.setProperty("color", override.textColor, "important");
716
+ el.setAttribute(NODE_WROTE_ATTR, "");
717
+ }
718
+ if (override.fontFamily !== void 0) {
719
+ saveInline(el, "font-family");
720
+ el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
721
+ el.setAttribute(NODE_WROTE_ATTR, "");
722
+ }
723
+ }
724
+ }
681
725
  }
682
726
  }
683
727
  for (const [key, override] of Object.entries(store.nodes)) {
@@ -724,6 +768,22 @@ function applyStylesToDom(store) {
724
768
  }
725
769
  }
726
770
  }
771
+ for (const [sectionId, override] of Object.entries(store.sections)) {
772
+ if (override.headingColor === void 0) continue;
773
+ const escaped = CSS.escape(sectionId);
774
+ const byInstance = document.querySelectorAll(`[data-ohw-instance="${escaped}"]`);
775
+ const sections = byInstance.length ? byInstance : document.querySelectorAll(`[data-ohw-section="${escaped}"]`);
776
+ for (const marker of Array.from(sections)) {
777
+ const headings = marker.querySelectorAll(
778
+ ":is(h1, h2, h3, h4, h5, h6)[data-ohw-editable], :is(h1, h2, h3, h4, h5, h6) > [data-ohw-editable]"
779
+ );
780
+ for (const el of Array.from(headings)) {
781
+ saveInline(el, "color");
782
+ el.style.setProperty("color", override.headingColor, "important");
783
+ el.setAttribute(NODE_WROTE_ATTR, "");
784
+ }
785
+ }
786
+ }
727
787
  }
728
788
 
729
789
  // src/ui/ai-tree/aiSectionsManager.tsx
@@ -2826,7 +2886,12 @@ function deriveTemplateButtonStyle() {
2826
2886
  if (typeof document === "undefined") return null;
2827
2887
  const candidates = Array.from(
2828
2888
  document.querySelectorAll('[data-ohw-role="button"]')
2829
- ).filter((el) => !el.closest(`[${CONTAINER_ATTR}]`));
2889
+ ).filter(
2890
+ (el) => !el.closest(`[${CONTAINER_ATTR}]`) && // Whole-card links legitimately carry the button role (serene's clickable treatment
2891
+ // cards) but must never donate the "button look" — a real button holds at most its
2892
+ // one editable label, a card holds a headline, copy and prices.
2893
+ el.querySelectorAll("[data-ohw-editable]").length <= 1
2894
+ );
2830
2895
  const isFilled = (el) => {
2831
2896
  const bg = getComputedStyle(el).backgroundColor;
2832
2897
  if (!bg || bg === "transparent") return false;
@@ -15298,7 +15363,9 @@ function collectEditableNodes(extraContent, root = document) {
15298
15363
  return {
15299
15364
  key: el.dataset.ohwKey ?? "",
15300
15365
  type: el.dataset.ohwEditable ?? "text",
15301
- text: el.dataset.ohwEditable === "plain" ? el.innerText ?? "" : el.innerHTML
15366
+ // innerText does not exist on SVG elements (a circular-badge <textPath> is a legitimate
15367
+ // plain editable) — textContent is the value there.
15368
+ text: el.dataset.ohwEditable === "plain" ? el.innerText ?? el.textContent ?? "" : el.innerHTML
15302
15369
  };
15303
15370
  });
15304
15371
  const hrefEls = Array.from(root.querySelectorAll("[data-ohw-href-key]"));
@@ -18993,6 +19060,9 @@ function OhhwellsBridge() {
18993
19060
  applySocialsDisplayFromContent(content);
18994
19061
  applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
18995
19062
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
19063
+ if (typeof content[STYLE_STORE_KEY] === "string") {
19064
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19065
+ }
18996
19066
  enforceLinkHrefs();
18997
19067
  initSectionsFromContent(content, true);
18998
19068
  sectionsLoadedRef.current = true;
@@ -19193,6 +19263,9 @@ function OhhwellsBridge() {
19193
19263
  applySocialsDisplayFromContent(content);
19194
19264
  applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
19195
19265
  if (isEditModeRef.current) requestMissingSocialIconsRef.current();
19266
+ if (typeof content[STYLE_STORE_KEY] === "string") {
19267
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
19268
+ }
19196
19269
  document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
19197
19270
  if (!form.querySelector("[data-ohw-form-success]")) {
19198
19271
  reconcileFieldsFromContent(form, content);
@@ -19555,6 +19628,10 @@ function OhhwellsBridge() {
19555
19628
  [data-ohw-editable-state], [data-ohw-editable-state] * { pointer-events: none !important; }
19556
19629
  [data-ohw-editable-state][data-ohw-active-state] [data-ohw-editable] { pointer-events: auto !important; }
19557
19630
  [data-ohw-editable-state][data-ohw-active-state][data-ohw-editable] { pointer-events: auto !important; }
19631
+ /* SVG hit-tests painted glyphs only, so an editable curved-text badge answered clicks
19632
+ on its letter strokes alone (and a spinning one barely at all). In edit mode the
19633
+ whole box takes the click; the handler resolves it to the editable inside. */
19634
+ svg:has([data-ohw-editable]) { pointer-events: bounding-box !important; }
19558
19635
  `;
19559
19636
  if (!existing) {
19560
19637
  const base = document.createElement("style");
@@ -19725,7 +19802,19 @@ function OhhwellsBridge() {
19725
19802
  openLogoSizePanelRef.current(logoEl);
19726
19803
  return;
19727
19804
  }
19728
- const editable = target.closest("[data-ohw-editable]");
19805
+ let editable = target.closest("[data-ohw-editable]");
19806
+ if (!editable && target instanceof SVGElement) {
19807
+ const inner = target.closest("svg")?.querySelectorAll("[data-ohw-editable]");
19808
+ if (inner && inner.length === 1) editable = inner[0];
19809
+ }
19810
+ if (editable && !(editable instanceof HTMLElement)) {
19811
+ e.preventDefault();
19812
+ e.stopPropagation();
19813
+ deselectRef.current();
19814
+ deactivateRef.current();
19815
+ aiSectionApiRef.current?.selectFromElement(editable);
19816
+ return;
19817
+ }
19729
19818
  if (editable) {
19730
19819
  if (editable.dataset.ohwEditable === "link") {
19731
19820
  e.preventDefault();
@@ -20455,6 +20544,15 @@ function OhhwellsBridge() {
20455
20544
  }
20456
20545
  return;
20457
20546
  }
20547
+ const cardHit = !isDragOver && Array.from(document.querySelectorAll(".card, [data-ohw-card]")).some((card) => {
20548
+ if (card.contains(imgEl)) return false;
20549
+ const r2 = card.getBoundingClientRect();
20550
+ return x2 >= r2.left && x2 <= r2.right && y2 >= r2.top && y2 <= r2.bottom;
20551
+ });
20552
+ if (cardHit) {
20553
+ dismissImageHover();
20554
+ return;
20555
+ }
20458
20556
  const topEl = document.elementFromPoint(x2, y2);
20459
20557
  if (topEl?.closest('[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-more-menu], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]')) {
20460
20558
  if (hoveredImageRef.current) {
@@ -21151,6 +21249,9 @@ function OhhwellsBridge() {
21151
21249
  reconcileNavbarItemsFromContent(editContentRef.current);
21152
21250
  reconcileFooterOrderFromContent(editContentRef.current);
21153
21251
  syncNavigationDragCursorAttrs();
21252
+ if (typeof content[STYLE_STORE_KEY] === "string") {
21253
+ applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
21254
+ }
21154
21255
  enforceLinkHrefs();
21155
21256
  const hydrateReapExclude = /* @__PURE__ */ new Set();
21156
21257
  const hydratePendingUndo = pendingDeleteUndoRef.current;