@ohhwells/bridge 0.1.64-next.177 → 0.1.65-next.179

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
@@ -157,7 +157,12 @@ function parseAiSectionsState(raw) {
157
157
  media: entry.media && typeof entry.media === "object" ? entry.media : {}
158
158
  }));
159
159
  const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
160
- return { v: 1, sections, ...removed.length ? { removed } : {} };
160
+ return {
161
+ v: 1,
162
+ sections,
163
+ ...removed.length ? { removed } : {},
164
+ ...parsed.hideTemplate === true ? { hideTemplate: true } : {}
165
+ };
161
166
  } catch {
162
167
  return EMPTY_AI_SECTIONS;
163
168
  }
@@ -534,6 +539,36 @@ var FEATURE_LINE_CSS = [
534
539
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
535
540
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
536
541
  ].join("");
542
+ function hexLuminance(color) {
543
+ const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
544
+ if (!m) return null;
545
+ const [r2, g, b] = [0, 2, 4].map((i) => {
546
+ const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
547
+ return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
548
+ });
549
+ return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
550
+ }
551
+ function hexContrast(a, b) {
552
+ const la = hexLuminance(a);
553
+ const lb = hexLuminance(b);
554
+ if (la === null || lb === null) return null;
555
+ const [hi, lo] = la > lb ? [la, lb] : [lb, la];
556
+ return (hi + 0.05) / (lo + 0.05);
557
+ }
558
+ function accentBandContext(brand) {
559
+ const p = brand.palette;
560
+ const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
561
+ if (lightWins) {
562
+ return {
563
+ brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
564
+ buttonLabel: p.primary
565
+ };
566
+ }
567
+ return {
568
+ brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
569
+ buttonLabel: p.light
570
+ };
571
+ }
537
572
  function textAttrs(ctx, path) {
538
573
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
539
574
  }
@@ -641,7 +676,7 @@ function ButtonEl({
641
676
  textDecoration: "none",
642
677
  cursor: "pointer",
643
678
  ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
644
- ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
679
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
645
680
  },
646
681
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
647
682
  }
@@ -1543,11 +1578,14 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1543
1578
  return null;
1544
1579
  }
1545
1580
  const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
1581
+ const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
1582
+ const blockBrand = band?.brand ?? resolvedBrand;
1546
1583
  const ctx = {
1547
- brand: resolvedBrand,
1584
+ brand: blockBrand,
1548
1585
  resolveMedia: resolveMedia ?? (() => null),
1549
- cardSurface: resolvedBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${resolvedBrand.palette.light} 90%, ${resolvedBrand.palette.dark})`,
1550
- keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
1586
+ cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
1587
+ keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
1588
+ ...band ? { buttonLabel: band.buttonLabel } : {}
1551
1589
  };
1552
1590
  const settings = tree.settings ?? {};
1553
1591
  const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
@@ -1582,7 +1620,7 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1582
1620
  backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
1583
1621
  backgroundSize: "cover",
1584
1622
  backgroundPosition: "center",
1585
- color: settings.sectionBackground === "accent" ? resolvedBrand.palette.light : void 0
1623
+ color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
1586
1624
  },
1587
1625
  children: [
1588
1626
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
@@ -1639,6 +1677,8 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1639
1677
  var CONTAINER_ATTR = "data-ohw-ai-generated";
1640
1678
  var REPLACED_ATTR = "data-ohw-ai-replaced-by";
1641
1679
  var REMOVED_ATTR = "data-ohw-ai-removed";
1680
+ var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
1681
+ var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
1642
1682
  function readRootVar(name) {
1643
1683
  if (typeof document === "undefined") return "";
1644
1684
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
@@ -1738,6 +1778,24 @@ function syncRemovedSections(state) {
1738
1778
  }
1739
1779
  }
1740
1780
  }
1781
+ function syncTemplateHidden(state, pageHasSections) {
1782
+ const hide = state.hideTemplate === true && pageHasSections;
1783
+ for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
1784
+ if (!hide) {
1785
+ el.style.removeProperty("display");
1786
+ el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
1787
+ }
1788
+ }
1789
+ if (!hide) return;
1790
+ for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
1791
+ if (el.hasAttribute(CONTAINER_ATTR)) continue;
1792
+ if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
1793
+ if (el.parentElement?.closest("[data-ohw-section]")) continue;
1794
+ if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
1795
+ el.style.display = "none";
1796
+ el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
1797
+ }
1798
+ }
1741
1799
  function syncReplacedOriginals(state) {
1742
1800
  for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
1743
1801
  const byId = el.getAttribute(REPLACED_ATTR) ?? "";
@@ -1808,6 +1866,7 @@ function applyAiSectionsToDom(state, options) {
1808
1866
  }
1809
1867
  syncReplacedOriginals(state);
1810
1868
  syncRemovedSections(state);
1869
+ syncTemplateHidden(state, pageSections.length > 0);
1811
1870
  }
1812
1871
 
1813
1872
  // src/useLinkHrefGuardian.ts
@@ -7662,6 +7721,8 @@ function parseSectionsFromRoot(root) {
7662
7721
  const id = el.getAttribute("data-ohw-section") ?? "";
7663
7722
  if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
7664
7723
  if (el.parentElement?.closest("[data-ohw-section]")) continue;
7724
+ if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
7725
+ continue;
7665
7726
  seen.add(id);
7666
7727
  const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
7667
7728
  sections.push({ id, label });
@@ -16558,14 +16619,14 @@ function OhhwellsBridge() {
16558
16619
  }
16559
16620
  const applyContent = (content) => {
16560
16621
  const imageLoads = [];
16561
- if (typeof content[AI_SECTIONS_KEY] === "string") {
16562
- aiSectionsRef.current = content[AI_SECTIONS_KEY];
16563
- applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
16564
- }
16565
16622
  if (typeof content[BRAND_KIT_KEY] === "string") {
16566
16623
  brandKitRef.current = content[BRAND_KIT_KEY];
16567
16624
  applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
16568
16625
  }
16626
+ if (typeof content[AI_SECTIONS_KEY] === "string") {
16627
+ aiSectionsRef.current = content[AI_SECTIONS_KEY];
16628
+ applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
16629
+ }
16569
16630
  if (typeof content[STYLE_STORE_KEY] === "string") {
16570
16631
  stylesRef.current = content[STYLE_STORE_KEY];
16571
16632
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
@@ -18436,14 +18497,14 @@ function OhhwellsBridge() {
18436
18497
  if (e.data?.type !== "ow:hydrate") return;
18437
18498
  const content = e.data.content;
18438
18499
  if (!content) return;
18439
- if (typeof content[AI_SECTIONS_KEY] === "string") {
18440
- aiSectionsRef.current = content[AI_SECTIONS_KEY];
18441
- applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
18442
- }
18443
18500
  if (typeof content[BRAND_KIT_KEY] === "string") {
18444
18501
  brandKitRef.current = content[BRAND_KIT_KEY];
18445
18502
  applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
18446
18503
  }
18504
+ if (typeof content[AI_SECTIONS_KEY] === "string") {
18505
+ aiSectionsRef.current = content[AI_SECTIONS_KEY];
18506
+ applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
18507
+ }
18447
18508
  if (typeof content[STYLE_STORE_KEY] === "string") {
18448
18509
  stylesRef.current = content[STYLE_STORE_KEY];
18449
18510
  applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
@@ -19515,7 +19576,7 @@ function OhhwellsBridge() {
19515
19576
  postToParent2({
19516
19577
  type: "ow:ready",
19517
19578
  version: "1",
19518
- bridgeVersion: "0.1.64",
19579
+ bridgeVersion: "0.1.65",
19519
19580
  path: pathname,
19520
19581
  nodes: collectEditableNodes(editContentRef.current),
19521
19582
  sections