@ohhwells/bridge 0.1.95 → 0.1.96

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
@@ -952,6 +952,25 @@ var FEATURE_LINE_CSS = [
952
952
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
953
953
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
954
954
  ].join("");
955
+ function buttonShellStyle(ctx, fullWidth) {
956
+ const bs = ctx.buttonStyle;
957
+ if (bs) {
958
+ return {
959
+ borderRadius: bs.radius,
960
+ ...bs.padding ? { padding: bs.padding } : {},
961
+ ...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
962
+ ...bs.fontSize ? { fontSize: bs.fontSize } : {},
963
+ ...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
964
+ ...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
965
+ ...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
966
+ };
967
+ }
968
+ return {
969
+ borderRadius: AI_TREE_TOKENS.radiusButton,
970
+ padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
971
+ ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
972
+ };
973
+ }
955
974
  function hexLuminance(color) {
956
975
  const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
957
976
  if (!m) return null;
@@ -968,6 +987,12 @@ function hexContrast(a, b) {
968
987
  const [hi, lo] = la > lb ? [la, lb] : [lb, la];
969
988
  return (hi + 0.05) / (lo + 0.05);
970
989
  }
990
+ function primaryButtonLabel(brand) {
991
+ const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
992
+ const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
993
+ if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
994
+ return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
995
+ }
971
996
  function accentBandContext(brand) {
972
997
  const p = brand.palette;
973
998
  const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
@@ -1067,12 +1092,10 @@ function ButtonEl({
1067
1092
  width: fullWidth ? "100%" : void 0,
1068
1093
  alignItems: "center",
1069
1094
  justifyContent: "center",
1070
- padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
1071
- borderRadius: AI_TREE_TOKENS.radiusButton,
1072
1095
  textDecoration: "none",
1073
1096
  cursor: "pointer",
1074
- ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
1075
- ...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 }
1097
+ ...buttonShellStyle(ctx, fullWidth),
1098
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
1076
1099
  },
1077
1100
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
1078
1101
  }
@@ -2112,15 +2135,12 @@ function renderNode(node, ctx, path) {
2112
2135
  alignSelf: submitAlign,
2113
2136
  border: "none",
2114
2137
  cursor: "pointer",
2115
- padding: "12px 24px",
2116
- // Corner radius follows the host template's own buttons (measured from a template
2117
- // CTA); 8px only when the page has no template button to match.
2118
- borderRadius: ctx.buttonRadius ?? 8,
2138
+ // Shape/padding/typography follow the host template's own buttons.
2139
+ ...buttonShellStyle(ctx),
2119
2140
  // Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
2120
2141
  // reads correctly on custom palettes.
2121
2142
  background: ctx.brand.palette.primary,
2122
- color: ctx.buttonLabel ?? ctx.brand.palette.light,
2123
- ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
2143
+ color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
2124
2144
  },
2125
2145
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
2126
2146
  },
@@ -2155,7 +2175,7 @@ function renderNode(node, ctx, path) {
2155
2175
  function AiTreeRenderer({
2156
2176
  tree,
2157
2177
  brand,
2158
- buttonRadius,
2178
+ buttonStyle,
2159
2179
  resolveMedia,
2160
2180
  editKeyPrefix
2161
2181
  }) {
@@ -2171,7 +2191,7 @@ function AiTreeRenderer({
2171
2191
  cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
2172
2192
  keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
2173
2193
  sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
2174
- buttonRadius,
2194
+ buttonStyle,
2175
2195
  ...band ? { buttonLabel: band.buttonLabel } : {}
2176
2196
  };
2177
2197
  const settings = tree.settings ?? {};
@@ -2301,13 +2321,13 @@ function deriveBrandOverride() {
2301
2321
  };
2302
2322
  }
2303
2323
  function deriveTemplateBrand() {
2304
- const dark = readRootVar("--color-dark");
2305
- const primary = readRootVar("--color-primary");
2306
- const light = readRootVar("--color-light");
2324
+ const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2325
+ const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2326
+ const light = readRootVar("--brand-background") || readRootVar("--color-light");
2307
2327
  if (!dark || !primary || !light) return null;
2308
- const accent = readRootVar("--color-accent");
2309
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2310
- const body = readRootVar("--font-body");
2328
+ const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2329
+ const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2330
+ const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
2311
2331
  return {
2312
2332
  palette: { dark, primary, accent: accent || dark, light },
2313
2333
  fonts: {
@@ -2316,12 +2336,32 @@ function deriveTemplateBrand() {
2316
2336
  }
2317
2337
  };
2318
2338
  }
2319
- function deriveTemplateButtonRadius() {
2339
+ function deriveTemplateButtonStyle() {
2320
2340
  if (typeof document === "undefined") return null;
2321
- const btn = document.querySelector('[data-ohw-role="button"]');
2341
+ const btn = Array.from(document.querySelectorAll('[data-ohw-role="button"]')).find(
2342
+ (el) => !el.closest(`[${CONTAINER_ATTR}]`)
2343
+ );
2322
2344
  if (!btn) return null;
2323
- const radius = getComputedStyle(btn).borderTopLeftRadius;
2324
- return radius || null;
2345
+ const cs = getComputedStyle(btn);
2346
+ const corners = [
2347
+ cs.borderTopLeftRadius,
2348
+ cs.borderTopRightRadius,
2349
+ cs.borderBottomRightRadius,
2350
+ cs.borderBottomLeftRadius
2351
+ ].map((v) => v || "0px");
2352
+ const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
2353
+ const px = (v) => parseFloat(v) || 0;
2354
+ const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom));
2355
+ const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
2356
+ return {
2357
+ radius: radius || "10px",
2358
+ padding: `${padY}px ${padX}px`,
2359
+ fontFamily: cs.fontFamily || "",
2360
+ fontSize: cs.fontSize || "",
2361
+ fontWeight: cs.fontWeight || "",
2362
+ letterSpacing: cs.letterSpacing || "",
2363
+ textTransform: cs.textTransform || ""
2364
+ };
2325
2365
  }
2326
2366
  var mounted = /* @__PURE__ */ new Map();
2327
2367
  function findTemplateSection(id) {
@@ -2492,7 +2532,7 @@ function applyAiSectionsToDom(state, options) {
2492
2532
  if (typeof document === "undefined") return;
2493
2533
  const brandOverride = deriveBrandOverride();
2494
2534
  const templateBrand = deriveTemplateBrand();
2495
- const templateButtonRadius = deriveTemplateButtonRadius();
2535
+ const templateButtonStyle = deriveTemplateButtonStyle();
2496
2536
  const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
2497
2537
  const pagePath = window.location.pathname;
2498
2538
  const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
@@ -2532,7 +2572,7 @@ function applyAiSectionsToDom(state, options) {
2532
2572
  {
2533
2573
  tree: entry.tree,
2534
2574
  brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
2535
- buttonRadius: templateButtonRadius,
2575
+ buttonStyle: templateButtonStyle,
2536
2576
  resolveMedia,
2537
2577
  editKeyPrefix: `ai.${entry.id}`
2538
2578
  }
@@ -21669,7 +21709,7 @@ function OhhwellsBridge() {
21669
21709
  postToParent2({
21670
21710
  type: "ow:ready",
21671
21711
  version: "1",
21672
- bridgeVersion: "0.1.94",
21712
+ bridgeVersion: "0.1.95",
21673
21713
  path: pathname,
21674
21714
  nodes: collectEditableNodes(editContentRef.current),
21675
21715
  sections