@ohhwells/bridge 0.1.86-next.255 → 0.1.86-next.256

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
@@ -1195,6 +1195,25 @@ var FEATURE_LINE_CSS = [
1195
1195
  `background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
1196
1196
  `mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
1197
1197
  ].join("");
1198
+ function buttonShellStyle(ctx, fullWidth) {
1199
+ const bs = ctx.buttonStyle;
1200
+ if (bs) {
1201
+ return {
1202
+ borderRadius: bs.radius,
1203
+ ...bs.padding ? { padding: bs.padding } : {},
1204
+ ...bs.fontFamily ? { fontFamily: bs.fontFamily } : { fontFamily: ctx.brand.fonts.body },
1205
+ ...bs.fontSize ? { fontSize: bs.fontSize } : {},
1206
+ ...bs.fontWeight ? { fontWeight: bs.fontWeight } : {},
1207
+ ...bs.letterSpacing && bs.letterSpacing !== "normal" ? { letterSpacing: bs.letterSpacing } : {},
1208
+ ...bs.textTransform && bs.textTransform !== "none" ? { textTransform: bs.textTransform } : {}
1209
+ };
1210
+ }
1211
+ return {
1212
+ borderRadius: AI_TREE_TOKENS.radiusButton,
1213
+ padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
1214
+ ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
1215
+ };
1216
+ }
1198
1217
  function hexLuminance(color) {
1199
1218
  const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
1200
1219
  if (!m) return null;
@@ -1211,6 +1230,12 @@ function hexContrast(a, b) {
1211
1230
  const [hi, lo] = la > lb ? [la, lb] : [lb, la];
1212
1231
  return (hi + 0.05) / (lo + 0.05);
1213
1232
  }
1233
+ function primaryButtonLabel(brand) {
1234
+ const darkC = hexContrast(brand.palette.primary, brand.palette.dark);
1235
+ const lightC = hexContrast(brand.palette.primary, AI_TREE_TOKENS.textPrimaryForeground);
1236
+ if (darkC === null || lightC === null) return AI_TREE_TOKENS.textPrimaryForeground;
1237
+ return darkC > lightC ? brand.palette.dark : AI_TREE_TOKENS.textPrimaryForeground;
1238
+ }
1214
1239
  function accentBandContext(brand) {
1215
1240
  const p = brand.palette;
1216
1241
  const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
@@ -1330,12 +1355,10 @@ function ButtonEl({
1330
1355
  width: fullWidth ? "100%" : void 0,
1331
1356
  alignItems: "center",
1332
1357
  justifyContent: "center",
1333
- padding: fullWidth ? `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px` : `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
1334
- borderRadius: AI_TREE_TOKENS.radiusButton,
1335
1358
  textDecoration: "none",
1336
1359
  cursor: "pointer",
1337
- ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
1338
- ...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 }
1360
+ ...buttonShellStyle(ctx, fullWidth),
1361
+ ...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
1339
1362
  },
1340
1363
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
1341
1364
  }
@@ -2405,15 +2428,12 @@ function renderNode(node, ctx, path) {
2405
2428
  alignSelf: submitAlign,
2406
2429
  border: "none",
2407
2430
  cursor: "pointer",
2408
- padding: "12px 24px",
2409
- // Corner radius follows the host template's own buttons (measured from a template
2410
- // CTA); 8px only when the page has no template button to match.
2411
- borderRadius: ctx.buttonRadius ?? 8,
2431
+ // Shape/padding/typography follow the host template's own buttons.
2432
+ ...buttonShellStyle(ctx),
2412
2433
  // Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
2413
2434
  // reads correctly on custom palettes.
2414
2435
  background: ctx.brand.palette.primary,
2415
- color: ctx.buttonLabel ?? ctx.brand.palette.light,
2416
- ...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
2436
+ color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
2417
2437
  },
2418
2438
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
2419
2439
  },
@@ -2448,7 +2468,7 @@ function renderNode(node, ctx, path) {
2448
2468
  function AiTreeRenderer({
2449
2469
  tree,
2450
2470
  brand,
2451
- buttonRadius,
2471
+ buttonStyle,
2452
2472
  resolveMedia,
2453
2473
  editKeyPrefix
2454
2474
  }) {
@@ -2469,7 +2489,7 @@ function AiTreeRenderer({
2469
2489
  cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
2470
2490
  keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
2471
2491
  sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
2472
- buttonRadius,
2492
+ buttonStyle,
2473
2493
  ...band ? { buttonLabel: band.buttonLabel } : {}
2474
2494
  };
2475
2495
  const settings = tree.settings ?? {};
@@ -2601,13 +2621,13 @@ function deriveBrandOverride() {
2601
2621
  };
2602
2622
  }
2603
2623
  function deriveTemplateBrand() {
2604
- const dark = readRootVar("--color-dark");
2605
- const primary = readRootVar("--color-primary");
2606
- const light = readRootVar("--color-light");
2624
+ const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2625
+ const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2626
+ const light = readRootVar("--brand-background") || readRootVar("--color-light");
2607
2627
  if (!dark || !primary || !light) return null;
2608
- const accent = readRootVar("--color-accent");
2609
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2610
- const body = readRootVar("--font-body");
2628
+ const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2629
+ const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2630
+ const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
2611
2631
  return {
2612
2632
  palette: { dark, primary, accent: accent || dark, light },
2613
2633
  fonts: {
@@ -2616,12 +2636,32 @@ function deriveTemplateBrand() {
2616
2636
  }
2617
2637
  };
2618
2638
  }
2619
- function deriveTemplateButtonRadius() {
2639
+ function deriveTemplateButtonStyle() {
2620
2640
  if (typeof document === "undefined") return null;
2621
- const btn = document.querySelector('[data-ohw-role="button"]');
2641
+ const btn = Array.from(document.querySelectorAll('[data-ohw-role="button"]')).find(
2642
+ (el) => !el.closest(`[${CONTAINER_ATTR}]`)
2643
+ );
2622
2644
  if (!btn) return null;
2623
- const radius = getComputedStyle(btn).borderTopLeftRadius;
2624
- return radius || null;
2645
+ const cs = getComputedStyle(btn);
2646
+ const corners = [
2647
+ cs.borderTopLeftRadius,
2648
+ cs.borderTopRightRadius,
2649
+ cs.borderBottomRightRadius,
2650
+ cs.borderBottomLeftRadius
2651
+ ].map((v) => v || "0px");
2652
+ const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
2653
+ const px = (v) => parseFloat(v) || 0;
2654
+ const padY = Math.max(px(cs.paddingTop), px(cs.paddingBottom));
2655
+ const padX = Math.max(px(cs.paddingLeft), px(cs.paddingRight));
2656
+ return {
2657
+ radius: radius || "10px",
2658
+ padding: `${padY}px ${padX}px`,
2659
+ fontFamily: cs.fontFamily || "",
2660
+ fontSize: cs.fontSize || "",
2661
+ fontWeight: cs.fontWeight || "",
2662
+ letterSpacing: cs.letterSpacing || "",
2663
+ textTransform: cs.textTransform || ""
2664
+ };
2625
2665
  }
2626
2666
  var mounted = /* @__PURE__ */ new Map();
2627
2667
  function findTemplateSection(id) {
@@ -2791,7 +2831,7 @@ function applyAiSectionsToDom(state, options) {
2791
2831
  if (typeof document === "undefined") return;
2792
2832
  const brandOverride = deriveBrandOverride();
2793
2833
  const templateBrand = deriveTemplateBrand();
2794
- const templateButtonRadius = deriveTemplateButtonRadius();
2834
+ const templateButtonStyle = deriveTemplateButtonStyle();
2795
2835
  const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
2796
2836
  const pagePath = window.location.pathname;
2797
2837
  const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
@@ -2831,7 +2871,7 @@ function applyAiSectionsToDom(state, options) {
2831
2871
  {
2832
2872
  tree: entry.tree,
2833
2873
  brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
2834
- buttonRadius: templateButtonRadius,
2874
+ buttonStyle: templateButtonStyle,
2835
2875
  resolveMedia,
2836
2876
  editKeyPrefix: `ai.${entry.id}`
2837
2877
  }