@ohhwells/bridge 0.1.115 → 0.1.116

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
@@ -352,16 +352,17 @@ var LEGACY_BRAND_VAR_NAMES = [
352
352
  "text-muted",
353
353
  "surface",
354
354
  "border",
355
- "on-primary",
356
- "navbar-background"
355
+ "on-primary"
357
356
  ].map((role) => `--brand-${role}`);
358
357
  var FONT_VARS = {
359
358
  heading: ["--font-heading", "--font-display", "--brand-font-heading"],
360
359
  body: ["--font-body", "--brand-font-body"]
361
360
  };
362
361
  var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
363
- function brandColorVars(kit) {
364
- const { dark, primary, accent, light } = kit.palette;
362
+ var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
363
+ var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
364
+ function brandColorVars(palette) {
365
+ const { dark, primary, accent, light } = palette;
365
366
  const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
366
367
  const surface = mix(light, 95, dark);
367
368
  const border = mix(light, 85, dark);
@@ -384,22 +385,42 @@ function brandColorVars(kit) {
384
385
  "--brand-border": border,
385
386
  // Buttons/bands painted in the primary colour assume it's dark/saturated enough to need
386
387
  // light text on top — the same assumption LOGO_IMAGE's light-on-dark navbar mark makes.
387
- "--brand-on-primary": light,
388
- "--brand-navbar-background": dark
388
+ "--brand-on-primary": light
389
389
  };
390
390
  }
391
+ function parseCustomFontWeight(raw) {
392
+ if (typeof raw !== "object" || raw === null) return null;
393
+ const w = raw;
394
+ if (typeof w.weight !== "number" || !Number.isFinite(w.weight)) return null;
395
+ if (typeof w.url !== "string" || !w.url) return null;
396
+ if (typeof w.format !== "string" || !CUSTOM_FONT_FORMATS.has(w.format)) return null;
397
+ const weightEnd = typeof w.weightEnd === "number" && Number.isFinite(w.weightEnd) && w.weightEnd > w.weight ? w.weightEnd : void 0;
398
+ return { weight: w.weight, ...weightEnd !== void 0 ? { weightEnd } : {}, url: w.url, format: w.format };
399
+ }
400
+ function parseCustomFont(raw) {
401
+ if (typeof raw !== "object" || raw === null) return null;
402
+ const f = raw;
403
+ if (typeof f.family !== "string" || !f.family) return null;
404
+ if (typeof f.label !== "string" || !f.label) return null;
405
+ if (!Array.isArray(f.weights)) return null;
406
+ const weights = f.weights.map(parseCustomFontWeight).filter((w) => w !== null);
407
+ if (weights.length === 0) return null;
408
+ return { family: f.family, label: f.label, weights };
409
+ }
391
410
  function parseBrandKit(raw) {
392
411
  if (!raw) return null;
393
412
  try {
394
413
  const parsed = JSON.parse(raw);
395
414
  const p = parsed?.palette;
396
415
  const f = parsed?.fonts;
397
- if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
398
- return null;
399
- }
416
+ const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
417
+ const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
418
+ const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
419
+ if (!palette && !fonts && !customFonts) return null;
400
420
  return {
401
- palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
402
- fonts: { heading: f.heading, body: f.body }
421
+ ...palette ? { palette } : {},
422
+ ...fonts ? { fonts } : {},
423
+ ...customFonts ? { customFonts } : {}
403
424
  };
404
425
  } catch {
405
426
  return null;
@@ -409,11 +430,16 @@ function familyOf(stack) {
409
430
  const first = stack.split(",")[0]?.trim() ?? "";
410
431
  return first.replace(/^['"]|['"]$/g, "");
411
432
  }
433
+ function quoteFamily(family) {
434
+ return `'${family.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
435
+ }
436
+ var WEIGHT_SCALE = [100, 200, 300, 400, 500, 600, 700, 800, 900];
412
437
  function loadBrandFonts(families) {
413
438
  const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
414
439
  if (unique.length === 0) return;
415
- const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
416
- const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
440
+ const weights = WEIGHT_SCALE.join(";");
441
+ const spec = unique.map((f) => `family=${f.replace(/ /g, "+")}:wght@${weights}`).join("&");
442
+ const href = `https://fonts.googleapis.com/css2?${spec}&display=swap`;
417
443
  let link = document.getElementById(BRAND_FONT_LINK_ID);
418
444
  if (!link) {
419
445
  link = document.createElement("link");
@@ -423,18 +449,54 @@ function loadBrandFonts(families) {
423
449
  }
424
450
  if (link.href !== href) link.href = href;
425
451
  }
452
+ function escapeCssString(value) {
453
+ return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
454
+ }
455
+ function loadCustomFonts(fonts) {
456
+ const list = fonts ?? [];
457
+ let style = document.getElementById(CUSTOM_FONT_STYLE_ID);
458
+ if (list.length === 0) {
459
+ style?.remove();
460
+ return;
461
+ }
462
+ if (!style) {
463
+ style = document.createElement("style");
464
+ style.id = CUSTOM_FONT_STYLE_ID;
465
+ document.head.appendChild(style);
466
+ }
467
+ style.textContent = list.flatMap(
468
+ (font) => font.weights.map((w) => {
469
+ const weightDescriptor = w.weightEnd ? `${w.weight} ${w.weightEnd}` : `${w.weight}`;
470
+ return `@font-face { font-family: '${escapeCssString(font.family)}'; src: url('${escapeCssString(w.url)}') format('${w.format}'); font-weight: ${weightDescriptor}; font-display: swap; }`;
471
+ })
472
+ ).join("\n");
473
+ }
426
474
  function applyBrandToDom(kit) {
427
475
  const root = document.documentElement;
428
476
  if (!kit) {
429
477
  for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES]) root.style.removeProperty(name);
430
478
  for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
431
479
  document.getElementById(BRAND_FONT_LINK_ID)?.remove();
480
+ document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
432
481
  return;
433
482
  }
434
- for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
435
- for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
436
- for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
437
- loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
483
+ if (kit.palette) {
484
+ for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
485
+ }
486
+ if (kit.customFonts) {
487
+ loadCustomFonts(kit.customFonts);
488
+ }
489
+ if (kit.fonts) {
490
+ const heading = quoteFamily(kit.fonts.heading);
491
+ const body = quoteFamily(kit.fonts.body);
492
+ for (const name of FONT_VARS.heading) root.style.setProperty(name, heading);
493
+ for (const name of FONT_VARS.body) root.style.setProperty(name, body);
494
+ const customFamilies = new Set((kit.customFonts ?? []).map((f) => f.family));
495
+ const googleFamilies = [familyOf(kit.fonts.heading), familyOf(kit.fonts.body)].filter(
496
+ (f) => !customFamilies.has(f)
497
+ );
498
+ loadBrandFonts(googleFamilies);
499
+ }
438
500
  }
439
501
 
440
502
  // src/lib/section-styles.ts
@@ -2723,14 +2785,52 @@ function readRootVar(name) {
2723
2785
  if (typeof document === "undefined") return "";
2724
2786
  return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
2725
2787
  }
2788
+ function normalizeColorToHex(value) {
2789
+ if (!value || typeof document === "undefined") return value;
2790
+ const canvas = document.createElement("canvas");
2791
+ canvas.width = 1;
2792
+ canvas.height = 1;
2793
+ const ctx = canvas.getContext("2d");
2794
+ if (!ctx) return value;
2795
+ ctx.fillStyle = value;
2796
+ ctx.fillRect(0, 0, 1, 1);
2797
+ const [r2, g, b] = ctx.getImageData(0, 0, 1, 1).data;
2798
+ const toHex = (n) => n.toString(16).padStart(2, "0");
2799
+ return `#${toHex(r2)}${toHex(g)}${toHex(b)}`;
2800
+ }
2801
+ var GENERIC_FONT_KEYWORDS = /* @__PURE__ */ new Set([
2802
+ "serif",
2803
+ "sans-serif",
2804
+ "monospace",
2805
+ "cursive",
2806
+ "fantasy",
2807
+ "system-ui",
2808
+ "ui-serif",
2809
+ "ui-sans-serif",
2810
+ "ui-monospace",
2811
+ "ui-rounded",
2812
+ "math",
2813
+ "emoji",
2814
+ "fangsong"
2815
+ ]);
2816
+ function primaryFontFamily(stack) {
2817
+ const first = stack.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !GENERIC_FONT_KEYWORDS.has(part.toLowerCase()));
2818
+ return first ?? "";
2819
+ }
2820
+ function humanizeFontFamily(name) {
2821
+ return name.replace(/^__/, "").replace(/_[0-9a-f]{6}$/i, "").replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").trim().replace(/\s+/g, " ").replace(/(^|\s)([a-z])/g, (_, sep, c) => sep + c.toUpperCase());
2822
+ }
2823
+ function readFontVar(name) {
2824
+ return humanizeFontFamily(primaryFontFamily(readRootVar(name)));
2825
+ }
2726
2826
  function deriveBrandOverride() {
2727
2827
  const dark = readRootVar("--ohw-brand-dark");
2728
2828
  const primary = readRootVar("--ohw-brand-primary");
2729
2829
  const light = readRootVar("--ohw-brand-light");
2730
2830
  if (!dark || !primary || !light) return null;
2731
2831
  const accent = readRootVar("--ohw-brand-accent");
2732
- const heading = readRootVar("--font-heading") || readRootVar("--font-display");
2733
- const body = readRootVar("--font-body");
2832
+ const heading = readFontVar("--font-heading") || readFontVar("--font-display");
2833
+ const body = readFontVar("--font-body");
2734
2834
  return {
2735
2835
  palette: { dark, primary, accent: accent || dark, light },
2736
2836
  fonts: {
@@ -2739,22 +2839,55 @@ function deriveBrandOverride() {
2739
2839
  }
2740
2840
  };
2741
2841
  }
2742
- function deriveTemplateBrand() {
2842
+ function deriveTemplateBrandLive() {
2743
2843
  const primary = readRootVar("--brand-primary") || readRootVar("--color-primary");
2744
2844
  const dark = readRootVar("--brand-text") || readRootVar("--color-dark");
2745
2845
  const light = readRootVar("--brand-background") || readRootVar("--color-light");
2746
2846
  if (!dark || !primary || !light) return null;
2747
2847
  const accent = readRootVar("--brand-accent") || readRootVar("--color-accent");
2748
- const heading = readRootVar("--brand-font-heading") || readRootVar("--font-heading") || readRootVar("--font-display");
2749
- const body = readRootVar("--brand-font-body") || readRootVar("--font-body");
2848
+ const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2849
+ const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2750
2850
  return {
2751
- palette: { dark, primary, accent: accent || dark, light },
2851
+ palette: {
2852
+ dark: normalizeColorToHex(dark),
2853
+ primary: normalizeColorToHex(primary),
2854
+ accent: normalizeColorToHex(accent || dark),
2855
+ light: normalizeColorToHex(light)
2856
+ },
2752
2857
  fonts: {
2753
2858
  heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2754
2859
  body: body || AI_DEFAULT_BRAND.fonts.body
2755
2860
  }
2756
2861
  };
2757
2862
  }
2863
+ function deriveTemplateFontsLive() {
2864
+ const heading = readFontVar("--brand-font-heading") || readFontVar("--font-heading") || readFontVar("--font-display");
2865
+ const body = readFontVar("--brand-font-body") || readFontVar("--font-body");
2866
+ if (!heading && !body) return null;
2867
+ return {
2868
+ heading: heading || AI_DEFAULT_BRAND.fonts.heading,
2869
+ body: body || AI_DEFAULT_BRAND.fonts.body
2870
+ };
2871
+ }
2872
+ var OVERRIDE_VAR_NAMES = [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...FONT_VARS.heading, ...FONT_VARS.body];
2873
+ function withOverrideStripped(read) {
2874
+ const root = document.documentElement;
2875
+ const restore = OVERRIDE_VAR_NAMES.map((name) => [name, root.style.getPropertyValue(name)]);
2876
+ for (const name of OVERRIDE_VAR_NAMES) root.style.removeProperty(name);
2877
+ try {
2878
+ return read();
2879
+ } finally {
2880
+ for (const [name, value] of restore) if (value) root.style.setProperty(name, value);
2881
+ }
2882
+ }
2883
+ var TEMPLATE_BRAND_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateBrandLive);
2884
+ var TEMPLATE_FONTS_SNAPSHOT = typeof document === "undefined" ? null : withOverrideStripped(deriveTemplateFontsLive);
2885
+ function deriveTemplateBrand() {
2886
+ return TEMPLATE_BRAND_SNAPSHOT;
2887
+ }
2888
+ function deriveTemplateFonts() {
2889
+ return TEMPLATE_FONTS_SNAPSHOT;
2890
+ }
2758
2891
  function deriveTemplateButtonStyle() {
2759
2892
  if (typeof document === "undefined") return null;
2760
2893
  const candidates = Array.from(
@@ -7252,12 +7385,12 @@ var cva = (base, config) => (props) => {
7252
7385
  var import_radix_ui2 = require("radix-ui");
7253
7386
  var import_jsx_runtime5 = require("react/jsx-runtime");
7254
7387
  var toggleVariants = cva(
7255
- "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7388
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=on]:bg-bridge-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7256
7389
  {
7257
7390
  variants: {
7258
7391
  variant: {
7259
7392
  default: "bg-transparent border-0",
7260
- outline: "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground"
7393
+ outline: "border border-input bg-transparent shadow-xs hover:bg-bridge-accent hover:text-accent-foreground"
7261
7394
  },
7262
7395
  size: {
7263
7396
  default: "px-2 py-1",
@@ -7350,10 +7483,10 @@ var DragHandle = React4.forwardRef(
7350
7483
  type,
7351
7484
  "data-slot": "drag-handle",
7352
7485
  className: cn(
7353
- "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-[30px]",
7486
+ "inline-flex h-7 w-4 shrink-0 items-center justify-center rounded-md transition-all duration-200 max-h-7.5",
7354
7487
  "bg-white border border-transparent text-stone-500 shadow-md cursor-grab",
7355
7488
  "enabled:hover:border enabled:hover:border-stone-200 enabled:hover:text-stone-950",
7356
- "enabled:active:border enabled:active:border-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
7489
+ "enabled:active:border enabled:active:border-bridge-primary enabled:active:bg-primary-50 enabled:active:text-stone-950 enabled:active:shadow enabled:active:cursor-grabbing",
7357
7490
  "disabled:cursor-not-allowed disabled:opacity-40 disabled:text-stone-950 disabled:pointer-events-none",
7358
7491
  className
7359
7492
  ),
@@ -7375,7 +7508,7 @@ var CustomToolbar = React5.forwardRef(({ className, onMouseDown, ...props }, ref
7375
7508
  "data-ohw-toolbar": "",
7376
7509
  className: cn(
7377
7510
  // Figma: bg background, radius 8, gap-1, p-0.5, shadow-md — no border
7378
- "inline-flex h-8 items-center gap-1 rounded-[var(--radius,0.5rem)] bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7511
+ "inline-flex h-8 items-center gap-1 rounded-(--radius,0.5rem) bg-background p-0.5 font-sans whitespace-nowrap shadow-md",
7379
7512
  className
7380
7513
  ),
7381
7514
  onMouseDown: (e) => {
@@ -7404,7 +7537,7 @@ var CustomToolbarButton = React5.forwardRef(
7404
7537
  type,
7405
7538
  className: cn(
7406
7539
  "inline-flex size-7 shrink-0 items-center justify-center rounded-[calc(var(--radius,0.5rem)-2px)] text-foreground transition-colors",
7407
- active ? "bg-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7540
+ active ? "bg-bridge-primary text-primary-foreground" : "bg-transparent hover:bg-muted disabled:cursor-not-allowed disabled:text-muted-foreground disabled:opacity-60",
7408
7541
  className
7409
7542
  ),
7410
7543
  ...props
@@ -8668,13 +8801,13 @@ function FormFieldToolbar({
8668
8801
  ]
8669
8802
  }
8670
8803
  ) }),
8671
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
8804
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-47.5 p-1", children: FIELD_TYPES.map((entry) => {
8672
8805
  const Icon = TYPE_ICONS[entry.type];
8673
8806
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
8674
8807
  DropdownMenuItem,
8675
8808
  {
8676
8809
  onSelect: () => onTypeChange(entry.type),
8677
- className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
8810
+ className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-bridge-primary/10" : ""),
8678
8811
  children: [
8679
8812
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8680
8813
  entry.label
@@ -8691,7 +8824,7 @@ function FormFieldToolbar({
8691
8824
  type: "button",
8692
8825
  "aria-pressed": required,
8693
8826
  onClick: onRequiredToggle,
8694
- className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-primary/10 text-primary" : "text-foreground hover:bg-muted/70"),
8827
+ className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-bridge-primary/10 text-bridge-primary" : "text-foreground hover:bg-muted/70"),
8695
8828
  "data-ohw-field-required-toggle": "",
8696
8829
  children: [
8697
8830
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
@@ -8711,7 +8844,7 @@ function FormFieldToolbar({
8711
8844
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
8712
8845
  }
8713
8846
  ) }),
8714
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
8847
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-42.5 p-1", children: [
8715
8848
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
8716
8849
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
8717
8850
  "Duplicate"
@@ -8739,7 +8872,7 @@ function FieldTypePicker({ onPick }) {
8739
8872
  {
8740
8873
  type: "button",
8741
8874
  onClick: () => onPick(entry.type),
8742
- className: "flex h-[76px] flex-col items-center justify-center gap-2 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-primary hover:bg-primary/5",
8875
+ className: "flex h-[76px] flex-col items-center justify-center gap-2 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-bridge-primary hover:bg-bridge-primary/5",
8743
8876
  children: [
8744
8877
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
8745
8878
  entry.label
@@ -8765,7 +8898,7 @@ var buttonVariants = cva(
8765
8898
  {
8766
8899
  variants: {
8767
8900
  variant: {
8768
- default: "bg-primary text-primary-foreground hover:opacity-90",
8901
+ default: "bg-bridge-primary text-primary-foreground hover:opacity-90",
8769
8902
  outline: "border border-border bg-background text-foreground shadow-sm hover:bg-muted/80",
8770
8903
  ghost: "min-w-0 px-3 py-2 text-foreground hover:bg-muted/50"
8771
8904
  },
@@ -8965,8 +9098,8 @@ function MediaOverlay({
8965
9098
  pointerEvents: hover.hasTextOverlap ? "none" : "auto",
8966
9099
  // Selected: a firm component ring with no wash, so the image reads as chosen rather
8967
9100
  // than hovered. Hover keeps the existing tinted preview.
8968
- boxShadow: selected ? "inset 0 0 0 2px var(--color-primary)" : "inset 0 0 0 1.5px var(--color-primary)",
8969
- background: selected ? "transparent" : "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9101
+ boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
9102
+ background: selected ? "transparent" : "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
8970
9103
  },
8971
9104
  onClick: () => onSelect && !selected ? onSelect(hover.key) : onReplace(hover.key),
8972
9105
  children: [
@@ -9060,8 +9193,8 @@ function CarouselOverlay({
9060
9193
  height: rect.height,
9061
9194
  zIndex: 2147483646,
9062
9195
  pointerEvents: "auto",
9063
- boxShadow: "inset 0 0 0 1.5px var(--color-primary)",
9064
- background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
9196
+ boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
9197
+ background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
9065
9198
  },
9066
9199
  onClick: () => onEdit(hover.key),
9067
9200
  children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
@@ -9983,7 +10116,7 @@ function SectionTreeItem({
9983
10116
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
9984
10117
  "div",
9985
10118
  {
9986
- className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
10119
+ className: "-mr-px h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
9987
10120
  "aria-hidden": true
9988
10121
  }
9989
10122
  ),
@@ -10002,7 +10135,7 @@ function SectionTreeItem({
10002
10135
  className: cn(
10003
10136
  "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md border border-border bg-background p-3",
10004
10137
  interactive && "cursor-pointer hover:bg-muted/30",
10005
- interactive && selected && "border-primary"
10138
+ interactive && selected && "border-bridge-primary"
10006
10139
  ),
10007
10140
  children: [
10008
10141
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
@@ -10132,7 +10265,7 @@ function UrlOrPageInput({
10132
10265
  };
10133
10266
  const fieldClassName = cn(
10134
10267
  "data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
10135
- urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
10268
+ urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-bridge-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
10136
10269
  );
10137
10270
  return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
10138
10271
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
@@ -14335,7 +14468,7 @@ function DisplaySwitch({
14335
14468
  onClick: () => onChange(!checked),
14336
14469
  className: cn(
14337
14470
  "relative h-5 w-9 shrink-0 rounded-full transition-colors",
14338
- checked ? "bg-primary" : "bg-primary-50",
14471
+ checked ? "bg-bridge-primary" : "bg-primary-50",
14339
14472
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
14340
14473
  ),
14341
14474
  children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
@@ -14343,7 +14476,7 @@ function DisplaySwitch({
14343
14476
  {
14344
14477
  className: cn(
14345
14478
  "absolute top-0.5 h-4 w-4 rounded-full bg-white transition-all",
14346
- checked ? "left-[1.125rem]" : "left-0.5"
14479
+ checked ? "left-4.5" : "left-0.5"
14347
14480
  )
14348
14481
  }
14349
14482
  )
@@ -15978,7 +16111,7 @@ var badgeVariants = cva(
15978
16111
  {
15979
16112
  variants: {
15980
16113
  variant: {
15981
- default: "border-transparent bg-primary text-primary-foreground",
16114
+ default: "border-transparent bg-bridge-primary text-primary-foreground",
15982
16115
  secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15983
16116
  destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
15984
16117
  outline: "text-foreground"
@@ -19448,7 +19581,9 @@ function OhhwellsBridge() {
19448
19581
  }, [isEditMode]);
19449
19582
  (0, import_react17.useEffect)(() => {
19450
19583
  if (isEditMode || fetchState !== "done") return;
19584
+ console.log("env", process.env.NEXT_PUBLIC_FLOWOPS_API_URL);
19451
19585
  const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
19586
+ console.log({ apiUrl, subdomain });
19452
19587
  bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
19453
19588
  }, [isEditMode, fetchState, subdomain]);
19454
19589
  (0, import_react17.useEffect)(() => {
@@ -21798,10 +21933,26 @@ function OhhwellsBridge() {
21798
21933
  const handleGetBrand = (e) => {
21799
21934
  if (e.data?.type !== "ow:get-brand") return;
21800
21935
  const template = deriveTemplateBrand();
21801
- const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
21936
+ const fallback = template ?? (() => {
21937
+ const fonts = deriveTemplateFonts();
21938
+ return fonts ? { palette: AI_DEFAULT_BRAND.palette, fonts } : null;
21939
+ })();
21940
+ const value = brandKitRef.current || (fallback ? JSON.stringify(fallback) : "");
21802
21941
  postToParentRef.current({ type: "ow:brand-value", value });
21803
21942
  };
21804
21943
  window.addEventListener("message", handleGetBrand);
21944
+ const handleGetTemplateFonts = (e) => {
21945
+ if (e.data?.type !== "ow:get-template-fonts") return;
21946
+ const fonts = deriveTemplateFonts();
21947
+ postToParentRef.current({ type: "ow:template-fonts-value", value: fonts ? JSON.stringify(fonts) : "" });
21948
+ };
21949
+ window.addEventListener("message", handleGetTemplateFonts);
21950
+ const handleGetTemplateBrand = (e) => {
21951
+ if (e.data?.type !== "ow:get-template-brand") return;
21952
+ const brand = deriveTemplateBrand();
21953
+ postToParentRef.current({ type: "ow:template-brand-value", value: brand ? JSON.stringify(brand) : "" });
21954
+ };
21955
+ window.addEventListener("message", handleGetTemplateBrand);
21805
21956
  const handleMoveSection = (e) => {
21806
21957
  if (e.data?.type !== "ow:move-section") return;
21807
21958
  const instanceId = typeof e.data.instanceId === "string" ? e.data.instanceId : "";
@@ -22704,6 +22855,8 @@ function OhhwellsBridge() {
22704
22855
  window.removeEventListener("message", handleAiSetBrand);
22705
22856
  window.removeEventListener("message", handleAiSetStyles);
22706
22857
  window.removeEventListener("message", handleGetBrand);
22858
+ window.removeEventListener("message", handleGetTemplateFonts);
22859
+ window.removeEventListener("message", handleGetTemplateBrand);
22707
22860
  window.removeEventListener("message", handleMoveSection);
22708
22861
  window.removeEventListener("message", handlePanelDragging);
22709
22862
  window.removeEventListener("message", handleDeleteSection);
@@ -22915,7 +23068,7 @@ function OhhwellsBridge() {
22915
23068
  postToParent2({
22916
23069
  type: "ow:ready",
22917
23070
  version: "1",
22918
- bridgeVersion: "0.1.114",
23071
+ bridgeVersion: "0.1.115",
22919
23072
  path: pathname,
22920
23073
  nodes: collectEditableNodes(editContentRef.current),
22921
23074
  sections
@@ -23531,7 +23684,7 @@ function OhhwellsBridge() {
23531
23684
  "span",
23532
23685
  {
23533
23686
  "data-ohw-form-count": "",
23534
- className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
23687
+ className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-bridge-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
23535
23688
  children: formPickCount
23536
23689
  }
23537
23690
  )
@@ -23769,11 +23922,11 @@ function OhhwellsBridge() {
23769
23922
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
23770
23923
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
23771
23924
  children: [
23772
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
23925
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
23773
23926
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
23774
23927
  Badge,
23775
23928
  {
23776
- className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
23929
+ className: "px-8 py-1 bg-bridge-primary hover:bg-bridge-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
23777
23930
  onClick: () => {
23778
23931
  window.parent.postMessage(
23779
23932
  {
@@ -23787,7 +23940,7 @@ function OhhwellsBridge() {
23787
23940
  children: "Add Section"
23788
23941
  }
23789
23942
  ),
23790
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
23943
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
23791
23944
  ]
23792
23945
  }
23793
23946
  ),