@ohhwells/bridge 0.1.79 → 0.1.80
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 +104 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +104 -80
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -139,6 +139,8 @@ declare function isRenderableTree(value: unknown): value is AiLayoutTree;
|
|
|
139
139
|
interface AiTreeRendererProps {
|
|
140
140
|
tree: AiLayoutTree;
|
|
141
141
|
brand?: AiBrandKit;
|
|
142
|
+
/** The host template's button corner radius (e.g. "0px", "8px"); a form's submit adopts it. */
|
|
143
|
+
buttonRadius?: string | null;
|
|
142
144
|
/** Resolves a media ref to a URL; null renders a placeholder. */
|
|
143
145
|
resolveMedia?: (ref: string) => string | null;
|
|
144
146
|
/**
|
|
@@ -148,7 +150,7 @@ interface AiTreeRendererProps {
|
|
|
148
150
|
*/
|
|
149
151
|
editKeyPrefix?: string;
|
|
150
152
|
}
|
|
151
|
-
declare function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }: AiTreeRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
153
|
+
declare function AiTreeRenderer({ tree, brand, buttonRadius, resolveMedia, editKeyPrefix, }: AiTreeRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
152
154
|
|
|
153
155
|
type LinkPage = {
|
|
154
156
|
path: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -139,6 +139,8 @@ declare function isRenderableTree(value: unknown): value is AiLayoutTree;
|
|
|
139
139
|
interface AiTreeRendererProps {
|
|
140
140
|
tree: AiLayoutTree;
|
|
141
141
|
brand?: AiBrandKit;
|
|
142
|
+
/** The host template's button corner radius (e.g. "0px", "8px"); a form's submit adopts it. */
|
|
143
|
+
buttonRadius?: string | null;
|
|
142
144
|
/** Resolves a media ref to a URL; null renders a placeholder. */
|
|
143
145
|
resolveMedia?: (ref: string) => string | null;
|
|
144
146
|
/**
|
|
@@ -148,7 +150,7 @@ interface AiTreeRendererProps {
|
|
|
148
150
|
*/
|
|
149
151
|
editKeyPrefix?: string;
|
|
150
152
|
}
|
|
151
|
-
declare function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }: AiTreeRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
153
|
+
declare function AiTreeRenderer({ tree, brand, buttonRadius, resolveMedia, editKeyPrefix, }: AiTreeRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
152
154
|
|
|
153
155
|
type LinkPage = {
|
|
154
156
|
path: string;
|
package/dist/index.js
CHANGED
|
@@ -469,8 +469,6 @@ var AI_MOBILE_CSS = [
|
|
|
469
469
|
// Group containers flatten to a column on phones; span placements come along for free.
|
|
470
470
|
"[data-ai-group]{display:flex !important;flex-direction:column !important}",
|
|
471
471
|
"[data-ai-group] > *{grid-column:auto !important}",
|
|
472
|
-
// The 50:50 form collapses to a single stacked column on phones.
|
|
473
|
-
"[data-ai-form]{grid-template-columns:1fr !important}",
|
|
474
472
|
"[data-ai-section] img{max-width:100%}",
|
|
475
473
|
"}",
|
|
476
474
|
"@media (min-width: 769px) and (max-width: 1024px){",
|
|
@@ -1567,9 +1565,9 @@ function renderNode(node, ctx, path) {
|
|
|
1567
1565
|
const fieldStyle = {
|
|
1568
1566
|
width: "100%",
|
|
1569
1567
|
boxSizing: "border-box",
|
|
1570
|
-
border: `1px solid ${ctx.brand.palette.
|
|
1571
|
-
borderRadius:
|
|
1572
|
-
padding:
|
|
1568
|
+
border: `1px solid color-mix(in srgb, ${ctx.brand.palette.dark} 45%, #ffffff)`,
|
|
1569
|
+
borderRadius: 0,
|
|
1570
|
+
padding: 12,
|
|
1573
1571
|
background: "#fff",
|
|
1574
1572
|
color: ctx.brand.palette.dark,
|
|
1575
1573
|
outline: "none",
|
|
@@ -1577,81 +1575,90 @@ function renderNode(node, ctx, path) {
|
|
|
1577
1575
|
};
|
|
1578
1576
|
const labelStyle = {
|
|
1579
1577
|
...typeStyle(AI_TREE_TOKENS.type.bodyMBold, ctx.brand.fonts.body),
|
|
1580
|
-
color: ctx.brand.palette.dark
|
|
1578
|
+
color: ctx.brand.palette.dark,
|
|
1579
|
+
textAlign: "left",
|
|
1580
|
+
width: "100%"
|
|
1581
1581
|
};
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1582
|
+
const centered = ctx.sectionAlignment === "center";
|
|
1583
|
+
const submitAlign = centered ? "center" : "flex-start";
|
|
1584
|
+
const children = node.children ?? [];
|
|
1585
|
+
return (
|
|
1586
|
+
// 32px between the field group and the submit. In a stacked (centered) section the form is
|
|
1587
|
+
// capped at 780px and centered — the section's 12-col grid would otherwise leave it hugging
|
|
1588
|
+
// the left edge; a split section lets it fill its own column.
|
|
1589
|
+
/* @__PURE__ */ jsxs(
|
|
1590
|
+
"form",
|
|
1591
|
+
{
|
|
1592
|
+
...formAttrs,
|
|
1593
|
+
"data-ai-form": "",
|
|
1594
|
+
style: {
|
|
1595
|
+
display: "flex",
|
|
1596
|
+
flexDirection: "column",
|
|
1597
|
+
gap: 32,
|
|
1598
|
+
width: "100%",
|
|
1599
|
+
...centered ? { maxWidth: 780, marginLeft: "auto", marginRight: "auto" } : {}
|
|
1600
|
+
},
|
|
1601
|
+
children: [
|
|
1602
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexDirection: "column", gap: 24, width: "100%", alignItems: "flex-start" }, children: children.map((child, i) => {
|
|
1603
|
+
if (child.type !== "input") return null;
|
|
1604
|
+
const cs = child.slots ?? {};
|
|
1605
|
+
const kind = str(cs.kind);
|
|
1606
|
+
const label = str(cs.label);
|
|
1607
|
+
const placeholder = str(cs.placeholder);
|
|
1608
|
+
const required = cs.required === true;
|
|
1609
|
+
const name = label.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "") || `field-${i}`;
|
|
1610
|
+
const isTextarea = kind === "textarea";
|
|
1611
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 8, width: "100%" }, children: [
|
|
1612
|
+
/* @__PURE__ */ jsx("label", { ...textAttrs(ctx, `${path}.c${i}.label`), style: labelStyle, children: label }),
|
|
1613
|
+
isTextarea ? /* @__PURE__ */ jsx(
|
|
1614
|
+
"textarea",
|
|
1615
|
+
{
|
|
1616
|
+
name,
|
|
1617
|
+
placeholder,
|
|
1618
|
+
required,
|
|
1619
|
+
style: { ...fieldStyle, height: 180, resize: "vertical" }
|
|
1620
|
+
}
|
|
1621
|
+
) : /* @__PURE__ */ jsx(
|
|
1622
|
+
"input",
|
|
1623
|
+
{
|
|
1624
|
+
name,
|
|
1625
|
+
type: kind === "email" ? "email" : "text",
|
|
1626
|
+
placeholder,
|
|
1627
|
+
required,
|
|
1628
|
+
style: { ...fieldStyle, height: 48 }
|
|
1629
|
+
}
|
|
1630
|
+
)
|
|
1631
|
+
] }, i);
|
|
1632
|
+
}) }),
|
|
1633
|
+
children.map((child, i) => {
|
|
1634
|
+
if (child.type === "input") return null;
|
|
1635
|
+
const cs = child.slots ?? {};
|
|
1636
|
+
return /* @__PURE__ */ jsx(
|
|
1637
|
+
"button",
|
|
1638
|
+
{
|
|
1639
|
+
type: "submit",
|
|
1640
|
+
style: {
|
|
1641
|
+
alignSelf: submitAlign,
|
|
1642
|
+
border: "none",
|
|
1643
|
+
cursor: "pointer",
|
|
1644
|
+
padding: "12px 24px",
|
|
1645
|
+
// Corner radius follows the host template's own buttons (measured from a template
|
|
1646
|
+
// CTA); 8px only when the page has no template button to match.
|
|
1647
|
+
borderRadius: ctx.buttonRadius ?? 8,
|
|
1648
|
+
// Brand-styled: primary fill, brand-derived label colour (not a fixed token) so it
|
|
1649
|
+
// reads correctly on custom palettes.
|
|
1650
|
+
background: ctx.brand.palette.primary,
|
|
1651
|
+
color: ctx.buttonLabel ?? ctx.brand.palette.light,
|
|
1652
|
+
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1653
|
+
},
|
|
1654
|
+
children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1609
1655
|
},
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
placeholder,
|
|
1617
|
-
style: { ...fieldStyle, height: 140, resize: "vertical" }
|
|
1618
|
-
}
|
|
1619
|
-
) : /* @__PURE__ */ jsx(
|
|
1620
|
-
"input",
|
|
1621
|
-
{
|
|
1622
|
-
name,
|
|
1623
|
-
type: kind === "email" ? "email" : "text",
|
|
1624
|
-
placeholder,
|
|
1625
|
-
style: { ...fieldStyle, height: 48 }
|
|
1626
|
-
}
|
|
1627
|
-
)
|
|
1628
|
-
]
|
|
1629
|
-
},
|
|
1630
|
-
i
|
|
1631
|
-
);
|
|
1632
|
-
}
|
|
1633
|
-
const cs = child.slots ?? {};
|
|
1634
|
-
return /* @__PURE__ */ jsx(
|
|
1635
|
-
"button",
|
|
1636
|
-
{
|
|
1637
|
-
type: "submit",
|
|
1638
|
-
style: {
|
|
1639
|
-
gridColumn: "1 / -1",
|
|
1640
|
-
justifySelf: "start",
|
|
1641
|
-
border: "none",
|
|
1642
|
-
cursor: "pointer",
|
|
1643
|
-
padding: `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`,
|
|
1644
|
-
borderRadius: AI_TREE_TOKENS.radiusButton,
|
|
1645
|
-
background: ctx.brand.palette.primary,
|
|
1646
|
-
color: AI_TREE_TOKENS.textPrimaryForeground,
|
|
1647
|
-
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body)
|
|
1648
|
-
},
|
|
1649
|
-
children: /* @__PURE__ */ jsx("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
1650
|
-
},
|
|
1651
|
-
i
|
|
1652
|
-
);
|
|
1653
|
-
})
|
|
1654
|
-
}
|
|
1656
|
+
i
|
|
1657
|
+
);
|
|
1658
|
+
})
|
|
1659
|
+
]
|
|
1660
|
+
}
|
|
1661
|
+
)
|
|
1655
1662
|
);
|
|
1656
1663
|
}
|
|
1657
1664
|
case "schedule-widget":
|
|
@@ -1674,7 +1681,13 @@ function renderNode(node, ctx, path) {
|
|
|
1674
1681
|
return null;
|
|
1675
1682
|
}
|
|
1676
1683
|
}
|
|
1677
|
-
function AiTreeRenderer({
|
|
1684
|
+
function AiTreeRenderer({
|
|
1685
|
+
tree,
|
|
1686
|
+
brand,
|
|
1687
|
+
buttonRadius,
|
|
1688
|
+
resolveMedia,
|
|
1689
|
+
editKeyPrefix
|
|
1690
|
+
}) {
|
|
1678
1691
|
if (!isRenderableTree(tree)) {
|
|
1679
1692
|
return null;
|
|
1680
1693
|
}
|
|
@@ -1686,6 +1699,8 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1686
1699
|
resolveMedia: resolveMedia ?? (() => null),
|
|
1687
1700
|
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1688
1701
|
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1702
|
+
sectionAlignment: (tree.settings ?? {}).alignment === "center" ? "center" : "left",
|
|
1703
|
+
buttonRadius,
|
|
1689
1704
|
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1690
1705
|
};
|
|
1691
1706
|
const settings = tree.settings ?? {};
|
|
@@ -1815,6 +1830,13 @@ function deriveTemplateBrand() {
|
|
|
1815
1830
|
}
|
|
1816
1831
|
};
|
|
1817
1832
|
}
|
|
1833
|
+
function deriveTemplateButtonRadius() {
|
|
1834
|
+
if (typeof document === "undefined") return null;
|
|
1835
|
+
const btn = document.querySelector('[data-ohw-role="button"]');
|
|
1836
|
+
if (!btn) return null;
|
|
1837
|
+
const radius = getComputedStyle(btn).borderTopLeftRadius;
|
|
1838
|
+
return radius || null;
|
|
1839
|
+
}
|
|
1818
1840
|
var mounted = /* @__PURE__ */ new Map();
|
|
1819
1841
|
function findTemplateSection(id) {
|
|
1820
1842
|
for (const el of document.querySelectorAll(`[data-ohw-section="${CSS.escape(id)}"]`)) {
|
|
@@ -1966,6 +1988,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1966
1988
|
if (typeof document === "undefined") return;
|
|
1967
1989
|
const brandOverride = deriveBrandOverride();
|
|
1968
1990
|
const templateBrand = deriveTemplateBrand();
|
|
1991
|
+
const templateButtonRadius = deriveTemplateButtonRadius();
|
|
1969
1992
|
const brandKey = brandOverride ? JSON.stringify(brandOverride) : "";
|
|
1970
1993
|
const pagePath = window.location.pathname;
|
|
1971
1994
|
const pageSections = state.sections.filter((entry) => (entry.path ?? "/") === pagePath);
|
|
@@ -2005,6 +2028,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
2005
2028
|
{
|
|
2006
2029
|
tree: entry.tree,
|
|
2007
2030
|
brand: brandOverride ?? entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
2031
|
+
buttonRadius: templateButtonRadius,
|
|
2008
2032
|
resolveMedia,
|
|
2009
2033
|
editKeyPrefix: `ai.${entry.id}`
|
|
2010
2034
|
}
|
|
@@ -20996,7 +21020,7 @@ function OhhwellsBridge() {
|
|
|
20996
21020
|
postToParent2({
|
|
20997
21021
|
type: "ow:ready",
|
|
20998
21022
|
version: "1",
|
|
20999
|
-
bridgeVersion: "0.1.
|
|
21023
|
+
bridgeVersion: "0.1.79",
|
|
21000
21024
|
path: pathname,
|
|
21001
21025
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21002
21026
|
sections
|