@ohhwells/bridge 0.1.113-next.294 → 0.1.113-next.295
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 +134 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -19
- package/dist/index.d.ts +17 -19
- package/dist/index.js +134 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -105,6 +105,10 @@ function enforceLinkHrefs() {
|
|
|
105
105
|
|
|
106
106
|
// src/lib/ai-tree.ts
|
|
107
107
|
var AI_TREE_SCHEMA_VERSIONS = [1];
|
|
108
|
+
var BUTTON_FILL_TOKENS = ["dark", "primary", "accent", "light"];
|
|
109
|
+
var BUTTON_STYLES = ["solid", "outline", "ghost"];
|
|
110
|
+
var BUTTON_RADII = ["square", "rounded", "pill"];
|
|
111
|
+
var BUTTON_SIZES = ["s", "m", "l"];
|
|
108
112
|
var AI_DEFAULT_BRAND = {
|
|
109
113
|
palette: { dark: "#0C0A09", primary: "#0078E5", accent: "#747271", light: "#ECECEB" },
|
|
110
114
|
fonts: {
|
|
@@ -362,6 +366,59 @@ var FONT_VARS = {
|
|
|
362
366
|
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
363
367
|
var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
|
|
364
368
|
var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
|
|
369
|
+
var BUTTON_FILL_VAR = {
|
|
370
|
+
dark: "var(--brand-text)",
|
|
371
|
+
primary: "var(--brand-primary)",
|
|
372
|
+
accent: "var(--brand-accent)",
|
|
373
|
+
light: "var(--brand-background)"
|
|
374
|
+
};
|
|
375
|
+
var BUTTON_RADIUS_PX = {
|
|
376
|
+
square: 0,
|
|
377
|
+
rounded: AI_TREE_TOKENS.radiusButton,
|
|
378
|
+
pill: 999
|
|
379
|
+
};
|
|
380
|
+
var BUTTON_SIZE_SPEC = {
|
|
381
|
+
s: {
|
|
382
|
+
paddingX: `${AI_TREE_TOKENS.spacing4}px`,
|
|
383
|
+
paddingY: `${AI_TREE_TOKENS.spacing2}px`,
|
|
384
|
+
fontSize: "14px"
|
|
385
|
+
},
|
|
386
|
+
m: {
|
|
387
|
+
paddingX: `${AI_TREE_TOKENS.spacing6}px`,
|
|
388
|
+
paddingY: `${AI_TREE_TOKENS.spacing3}px`,
|
|
389
|
+
fontSize: `${AI_TREE_TOKENS.type.button.size}px`
|
|
390
|
+
},
|
|
391
|
+
l: {
|
|
392
|
+
paddingX: `${AI_TREE_TOKENS.spacing8}px`,
|
|
393
|
+
paddingY: `${AI_TREE_TOKENS.spacing4}px`,
|
|
394
|
+
fontSize: "18px"
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var BUTTON_VAR_ROLES = ["bg", "text", "border", "radius", "padding-x", "padding-y", "font-size"];
|
|
398
|
+
var BUTTON_VAR_NAMES = ["primary", "secondary"].flatMap(
|
|
399
|
+
(variant) => BUTTON_VAR_ROLES.map((role) => `--brand-button-${variant}-${role}`)
|
|
400
|
+
);
|
|
401
|
+
function buttonVariantVars(variant, style) {
|
|
402
|
+
const fill = BUTTON_FILL_VAR[style.fill];
|
|
403
|
+
const text = BUTTON_FILL_VAR[style.textColor];
|
|
404
|
+
const size = BUTTON_SIZE_SPEC[style.size];
|
|
405
|
+
const { bg, border } = style.style === "outline" ? { bg: "transparent", border: fill } : style.style === "ghost" ? { bg: "transparent", border: "transparent" } : { bg: fill, border: "transparent" };
|
|
406
|
+
return {
|
|
407
|
+
[`--brand-button-${variant}-bg`]: bg,
|
|
408
|
+
[`--brand-button-${variant}-text`]: text,
|
|
409
|
+
[`--brand-button-${variant}-border`]: border,
|
|
410
|
+
[`--brand-button-${variant}-radius`]: `${BUTTON_RADIUS_PX[style.radius]}px`,
|
|
411
|
+
[`--brand-button-${variant}-padding-x`]: size.paddingX,
|
|
412
|
+
[`--brand-button-${variant}-padding-y`]: size.paddingY,
|
|
413
|
+
[`--brand-button-${variant}-font-size`]: size.fontSize
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function buttonStyleVars(buttons) {
|
|
417
|
+
return {
|
|
418
|
+
...buttonVariantVars("primary", buttons.primary),
|
|
419
|
+
...buttonVariantVars("secondary", buttons.secondary)
|
|
420
|
+
};
|
|
421
|
+
}
|
|
365
422
|
function brandColorVars(palette) {
|
|
366
423
|
const { dark, primary, accent, light } = palette;
|
|
367
424
|
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
@@ -389,6 +446,11 @@ function brandColorVars(palette) {
|
|
|
389
446
|
"--brand-on-primary": light
|
|
390
447
|
};
|
|
391
448
|
}
|
|
449
|
+
function isButtonStyle(value) {
|
|
450
|
+
if (!value || typeof value !== "object") return false;
|
|
451
|
+
const v = value;
|
|
452
|
+
return BUTTON_FILL_TOKENS.includes(v.fill) && BUTTON_FILL_TOKENS.includes(v.textColor) && BUTTON_STYLES.includes(v.style) && BUTTON_RADII.includes(v.radius) && BUTTON_SIZES.includes(v.size);
|
|
453
|
+
}
|
|
392
454
|
function parseCustomFontWeight(raw) {
|
|
393
455
|
if (typeof raw !== "object" || raw === null) return null;
|
|
394
456
|
const w = raw;
|
|
@@ -417,11 +479,14 @@ function parseBrandKit(raw) {
|
|
|
417
479
|
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;
|
|
418
480
|
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
419
481
|
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
420
|
-
|
|
482
|
+
const b = parsed?.buttons;
|
|
483
|
+
const buttons = b && isButtonStyle(b.primary) && isButtonStyle(b.secondary) ? { primary: b.primary, secondary: b.secondary } : void 0;
|
|
484
|
+
if (!palette && !fonts && !customFonts && !buttons) return null;
|
|
421
485
|
return {
|
|
422
486
|
...palette ? { palette } : {},
|
|
423
487
|
...fonts ? { fonts } : {},
|
|
424
|
-
...customFonts ? { customFonts } : {}
|
|
488
|
+
...customFonts ? { customFonts } : {},
|
|
489
|
+
...buttons ? { buttons } : {}
|
|
425
490
|
};
|
|
426
491
|
} catch {
|
|
427
492
|
return null;
|
|
@@ -475,7 +540,9 @@ function loadCustomFonts(fonts) {
|
|
|
475
540
|
function applyBrandToDom(kit) {
|
|
476
541
|
const root = document.documentElement;
|
|
477
542
|
if (!kit) {
|
|
478
|
-
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES])
|
|
543
|
+
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...BUTTON_VAR_NAMES]) {
|
|
544
|
+
root.style.removeProperty(name);
|
|
545
|
+
}
|
|
479
546
|
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
480
547
|
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
481
548
|
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
@@ -484,6 +551,9 @@ function applyBrandToDom(kit) {
|
|
|
484
551
|
if (kit.palette) {
|
|
485
552
|
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
486
553
|
}
|
|
554
|
+
if (kit.buttons) {
|
|
555
|
+
for (const [name, value] of Object.entries(buttonStyleVars(kit.buttons))) root.style.setProperty(name, value);
|
|
556
|
+
}
|
|
487
557
|
if (kit.customFonts) {
|
|
488
558
|
loadCustomFonts(kit.customFonts);
|
|
489
559
|
}
|
|
@@ -612,7 +682,6 @@ var NODE_PROPS = [
|
|
|
612
682
|
"color",
|
|
613
683
|
"font-family",
|
|
614
684
|
"font-size",
|
|
615
|
-
"background",
|
|
616
685
|
"text-align",
|
|
617
686
|
"justify-content",
|
|
618
687
|
"align-items"
|
|
@@ -662,9 +731,6 @@ function clearNodeProps(root) {
|
|
|
662
731
|
h.removeAttribute(NODE_WROTE_ATTR);
|
|
663
732
|
}
|
|
664
733
|
}
|
|
665
|
-
function buttonSurfaceOf(el) {
|
|
666
|
-
return el.closest("a, button") ?? el;
|
|
667
|
-
}
|
|
668
734
|
function alignSubjectOf(el) {
|
|
669
735
|
const button = el.closest('[data-ohw-role="button"]');
|
|
670
736
|
if (button?.parentElement) return button.parentElement;
|
|
@@ -780,18 +846,6 @@ function applyStylesToDom(store) {
|
|
|
780
846
|
);
|
|
781
847
|
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
782
848
|
}
|
|
783
|
-
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
784
|
-
const surface = buttonSurfaceOf(el);
|
|
785
|
-
if (override.buttonBackground !== void 0) {
|
|
786
|
-
saveInline(surface, "background");
|
|
787
|
-
surface.style.setProperty("background", override.buttonBackground, "important");
|
|
788
|
-
}
|
|
789
|
-
if (override.buttonText !== void 0) {
|
|
790
|
-
saveInline(surface, "color");
|
|
791
|
-
surface.style.setProperty("color", override.buttonText, "important");
|
|
792
|
-
}
|
|
793
|
-
surface.setAttribute(NODE_WROTE_ATTR, "");
|
|
794
|
-
}
|
|
795
849
|
}
|
|
796
850
|
}
|
|
797
851
|
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
@@ -1386,7 +1440,59 @@ var FEATURE_LINE_CSS = [
|
|
|
1386
1440
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
1387
1441
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
1388
1442
|
].join("");
|
|
1389
|
-
function
|
|
1443
|
+
function buttonSizeSpec(size) {
|
|
1444
|
+
switch (size) {
|
|
1445
|
+
case "s":
|
|
1446
|
+
return { padding: `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px`, fontSize: 14 };
|
|
1447
|
+
case "l":
|
|
1448
|
+
return { padding: `${AI_TREE_TOKENS.spacing4}px ${AI_TREE_TOKENS.spacing8}px`, fontSize: 18 };
|
|
1449
|
+
case "m":
|
|
1450
|
+
default:
|
|
1451
|
+
return { padding: `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`, fontSize: AI_TREE_TOKENS.type.button.size };
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
function buttonRadiusPx(radius) {
|
|
1455
|
+
switch (radius) {
|
|
1456
|
+
case "square":
|
|
1457
|
+
return 0;
|
|
1458
|
+
case "pill":
|
|
1459
|
+
return 999;
|
|
1460
|
+
case "rounded":
|
|
1461
|
+
default:
|
|
1462
|
+
return AI_TREE_TOKENS.radiusButton;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
function resolveButtonToken(brand, token) {
|
|
1466
|
+
return brand.palette[token];
|
|
1467
|
+
}
|
|
1468
|
+
function buttonColorStyle(ctx, variant) {
|
|
1469
|
+
const token = ctx.brand.buttons?.[variant];
|
|
1470
|
+
if (!token) return null;
|
|
1471
|
+
const fill = resolveButtonToken(ctx.brand, token.fill);
|
|
1472
|
+
const text = resolveButtonToken(ctx.brand, token.textColor);
|
|
1473
|
+
switch (token.style) {
|
|
1474
|
+
case "outline":
|
|
1475
|
+
return { background: "transparent", border: `1px solid ${fill}`, color: text };
|
|
1476
|
+
case "ghost":
|
|
1477
|
+
return { background: "transparent", border: "1px solid transparent", color: text };
|
|
1478
|
+
case "solid":
|
|
1479
|
+
default:
|
|
1480
|
+
return { background: fill, color: text };
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
function buttonShellStyle(ctx, variant, fullWidth) {
|
|
1484
|
+
const buttonToken = ctx.brand.buttons?.[variant];
|
|
1485
|
+
if (buttonToken) {
|
|
1486
|
+
const { padding, fontSize } = buttonSizeSpec(buttonToken.size);
|
|
1487
|
+
return {
|
|
1488
|
+
borderRadius: buttonRadiusPx(buttonToken.radius),
|
|
1489
|
+
padding,
|
|
1490
|
+
fontFamily: ctx.brand.fonts.body,
|
|
1491
|
+
fontSize,
|
|
1492
|
+
lineHeight: AI_TREE_TOKENS.type.button.line,
|
|
1493
|
+
fontWeight: AI_TREE_TOKENS.type.button.weight
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1390
1496
|
const bs = ctx.buttonStyle;
|
|
1391
1497
|
if (bs) {
|
|
1392
1498
|
return {
|
|
@@ -1534,6 +1640,8 @@ function ButtonEl({
|
|
|
1534
1640
|
fullWidth
|
|
1535
1641
|
}) {
|
|
1536
1642
|
const secondary = slots.variant === "secondary";
|
|
1643
|
+
const variant = secondary ? "secondary" : "primary";
|
|
1644
|
+
const tokenColorStyle = buttonColorStyle(ctx, variant);
|
|
1537
1645
|
const href = str(slots.href);
|
|
1538
1646
|
const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
|
|
1539
1647
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1548,13 +1656,13 @@ function ButtonEl({
|
|
|
1548
1656
|
justifyContent: "center",
|
|
1549
1657
|
textDecoration: "none",
|
|
1550
1658
|
cursor: "pointer",
|
|
1551
|
-
...buttonShellStyle(ctx, fullWidth),
|
|
1552
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1659
|
+
...buttonShellStyle(ctx, variant, fullWidth),
|
|
1660
|
+
...tokenColorStyle ?? (secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1553
1661
|
// Off-band, prefer the template button's measured fill/label pair — a template may
|
|
1554
1662
|
// fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
|
|
1555
1663
|
// the flipped palette keeps contrast, so the brand-driven colours stay.
|
|
1556
1664
|
!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
1557
|
-
)
|
|
1665
|
+
))
|
|
1558
1666
|
},
|
|
1559
1667
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
1560
1668
|
}
|
|
@@ -2625,13 +2733,13 @@ function renderNode(node, ctx, path) {
|
|
|
2625
2733
|
border: "none",
|
|
2626
2734
|
cursor: "pointer",
|
|
2627
2735
|
// Shape/padding/typography follow the host template's own buttons.
|
|
2628
|
-
...buttonShellStyle(ctx),
|
|
2736
|
+
...buttonShellStyle(ctx, "primary"),
|
|
2629
2737
|
// Brand-styled: the template button's measured fill/label pair off-band, else
|
|
2630
2738
|
// primary fill with a brand-derived label so it reads on custom palettes.
|
|
2631
|
-
|
|
2739
|
+
...buttonColorStyle(ctx, "primary") ?? (!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
|
|
2632
2740
|
background: ctx.brand.palette.primary,
|
|
2633
2741
|
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
2634
|
-
}
|
|
2742
|
+
})
|
|
2635
2743
|
},
|
|
2636
2744
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
2637
2745
|
},
|