@ohhwells/bridge 0.1.91 → 0.1.92
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 +138 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +138 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -24,6 +24,8 @@ type AiBlockType = 'text' | 'button' | 'media' | 'media-list' | 'rating' | 'divi
|
|
|
24
24
|
interface AiBlockNode {
|
|
25
25
|
type: AiBlockType;
|
|
26
26
|
span: number;
|
|
27
|
+
/** Horizontal alignment of the block's content within its column. */
|
|
28
|
+
align?: 'left' | 'center' | 'right';
|
|
27
29
|
slots?: Record<string, unknown>;
|
|
28
30
|
children?: AiBlockNode[];
|
|
29
31
|
items?: Array<{
|
|
@@ -55,8 +57,10 @@ interface AiLayoutTree {
|
|
|
55
57
|
scaffold: SectionScaffold;
|
|
56
58
|
tag?: string;
|
|
57
59
|
settings?: AiSectionSettings;
|
|
60
|
+
/** A row's `align` sets the vertical alignment of its columns; `stretch` equalises heights. */
|
|
58
61
|
rows: Array<{
|
|
59
62
|
blocks: AiBlockNode[];
|
|
63
|
+
align?: 'top' | 'center' | 'bottom' | 'stretch';
|
|
60
64
|
}>;
|
|
61
65
|
}
|
|
62
66
|
/** The site brand kit the renderer styles from (editor Brand settings). */
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ type AiBlockType = 'text' | 'button' | 'media' | 'media-list' | 'rating' | 'divi
|
|
|
24
24
|
interface AiBlockNode {
|
|
25
25
|
type: AiBlockType;
|
|
26
26
|
span: number;
|
|
27
|
+
/** Horizontal alignment of the block's content within its column. */
|
|
28
|
+
align?: 'left' | 'center' | 'right';
|
|
27
29
|
slots?: Record<string, unknown>;
|
|
28
30
|
children?: AiBlockNode[];
|
|
29
31
|
items?: Array<{
|
|
@@ -55,8 +57,10 @@ interface AiLayoutTree {
|
|
|
55
57
|
scaffold: SectionScaffold;
|
|
56
58
|
tag?: string;
|
|
57
59
|
settings?: AiSectionSettings;
|
|
60
|
+
/** A row's `align` sets the vertical alignment of its columns; `stretch` equalises heights. */
|
|
58
61
|
rows: Array<{
|
|
59
62
|
blocks: AiBlockNode[];
|
|
63
|
+
align?: 'top' | 'center' | 'bottom' | 'stretch';
|
|
60
64
|
}>;
|
|
61
65
|
}
|
|
62
66
|
/** The site brand kit the renderer styles from (editor Brand settings). */
|
package/dist/index.js
CHANGED
|
@@ -69,6 +69,7 @@ function isRenderableTree(value) {
|
|
|
69
69
|
|
|
70
70
|
// src/lib/ai-sections-store.ts
|
|
71
71
|
var AI_SECTIONS_KEY = "__ohw_ai_sections";
|
|
72
|
+
var AI_SLOT_KEY_PREFIX = "ai.";
|
|
72
73
|
var EMPTY_AI_SECTIONS = { v: 1, sections: [] };
|
|
73
74
|
function parseAiSectionsState(raw) {
|
|
74
75
|
if (!raw) return EMPTY_AI_SECTIONS;
|
|
@@ -112,6 +113,63 @@ function applyTreeToState(state, payload) {
|
|
|
112
113
|
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
113
114
|
return { ...state, v: 1, sections: [...others, entry] };
|
|
114
115
|
}
|
|
116
|
+
function foldAlignIntoTrees(state, store) {
|
|
117
|
+
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
118
|
+
const nextTrees = /* @__PURE__ */ new Map();
|
|
119
|
+
const treeFor = (id) => {
|
|
120
|
+
const cloned = nextTrees.get(id);
|
|
121
|
+
if (cloned) return cloned;
|
|
122
|
+
const entry = byId.get(id);
|
|
123
|
+
if (!entry) return void 0;
|
|
124
|
+
const fresh = {
|
|
125
|
+
...entry.tree,
|
|
126
|
+
rows: entry.tree.rows.map((row) => ({ ...row, blocks: row.blocks.map((block) => ({ ...block })) }))
|
|
127
|
+
};
|
|
128
|
+
nextTrees.set(id, fresh);
|
|
129
|
+
return fresh;
|
|
130
|
+
};
|
|
131
|
+
const nodes = {};
|
|
132
|
+
for (const [key, override] of Object.entries(store.nodes)) {
|
|
133
|
+
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
134
|
+
const tree = match ? treeFor(match[1]) : void 0;
|
|
135
|
+
const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
|
|
136
|
+
if (!block) {
|
|
137
|
+
nodes[key] = override;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
block.align = override.align;
|
|
141
|
+
const rest = { ...override };
|
|
142
|
+
delete rest.align;
|
|
143
|
+
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
144
|
+
}
|
|
145
|
+
const sections = {};
|
|
146
|
+
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
147
|
+
const tree = override.align !== void 0 ? treeFor(sectionId) : void 0;
|
|
148
|
+
if (!tree) {
|
|
149
|
+
sections[sectionId] = override;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
for (const row of tree.rows) {
|
|
153
|
+
for (const block of row.blocks) block.align = override.align;
|
|
154
|
+
}
|
|
155
|
+
const rest = { ...override };
|
|
156
|
+
delete rest.align;
|
|
157
|
+
if (Object.keys(rest).length > 0) sections[sectionId] = rest;
|
|
158
|
+
}
|
|
159
|
+
if (nextTrees.size === 0) return { state, store, changed: false };
|
|
160
|
+
return {
|
|
161
|
+
state: {
|
|
162
|
+
...state,
|
|
163
|
+
v: 1,
|
|
164
|
+
sections: state.sections.map((entry) => {
|
|
165
|
+
const tree = nextTrees.get(entry.id);
|
|
166
|
+
return tree ? { ...entry, tree } : entry;
|
|
167
|
+
})
|
|
168
|
+
},
|
|
169
|
+
store: { v: 1, sections, nodes },
|
|
170
|
+
changed: true
|
|
171
|
+
};
|
|
172
|
+
}
|
|
115
173
|
function removeFromState(state, id) {
|
|
116
174
|
return { ...state, v: 1, sections: state.sections.filter((entry) => entry.id !== id) };
|
|
117
175
|
}
|
|
@@ -330,6 +388,9 @@ function styleSheetCss() {
|
|
|
330
388
|
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
331
389
|
);
|
|
332
390
|
}
|
|
391
|
+
for (const align of ["left", "center", "right"]) {
|
|
392
|
+
rules.push(`[data-ohw-style-align="${align}"] { text-align: ${align} !important; }`);
|
|
393
|
+
}
|
|
333
394
|
return rules.join("\n");
|
|
334
395
|
}
|
|
335
396
|
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
@@ -356,10 +417,24 @@ var SECTION_ATTRS = {
|
|
|
356
417
|
textDistribution: "data-ohw-style-distribution",
|
|
357
418
|
headlineScale: "data-ohw-style-headline",
|
|
358
419
|
imageAspect: "data-ohw-style-aspect",
|
|
359
|
-
spacing: "data-ohw-style-spacing"
|
|
420
|
+
spacing: "data-ohw-style-spacing",
|
|
421
|
+
align: "data-ohw-style-align"
|
|
360
422
|
};
|
|
361
423
|
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
362
|
-
var NODE_PROPS = [
|
|
424
|
+
var NODE_PROPS = [
|
|
425
|
+
"color",
|
|
426
|
+
"font-family",
|
|
427
|
+
"font-size",
|
|
428
|
+
"background",
|
|
429
|
+
"text-align",
|
|
430
|
+
"justify-content",
|
|
431
|
+
"align-items"
|
|
432
|
+
];
|
|
433
|
+
var ALIGN_JUSTIFY = {
|
|
434
|
+
left: "flex-start",
|
|
435
|
+
center: "center",
|
|
436
|
+
right: "flex-end"
|
|
437
|
+
};
|
|
363
438
|
function saveInline(el, prop) {
|
|
364
439
|
const attr = `data-ohw-style-prev-${prop}`;
|
|
365
440
|
if (el.hasAttribute(attr)) return;
|
|
@@ -403,6 +478,10 @@ function clearNodeProps(root) {
|
|
|
403
478
|
function buttonSurfaceOf(el) {
|
|
404
479
|
return el.closest("a, button") ?? el;
|
|
405
480
|
}
|
|
481
|
+
function alignSubjectOf(el) {
|
|
482
|
+
const button = el.closest('[data-ohw-role="button"]');
|
|
483
|
+
return button?.parentElement ?? el;
|
|
484
|
+
}
|
|
406
485
|
function applyStylesToDom(store) {
|
|
407
486
|
ensureStyleSheet();
|
|
408
487
|
clearSectionAttrs(document);
|
|
@@ -448,6 +527,18 @@ function applyStylesToDom(store) {
|
|
|
448
527
|
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
449
528
|
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
450
529
|
}
|
|
530
|
+
if (override.align !== void 0) {
|
|
531
|
+
const subject = alignSubjectOf(el);
|
|
532
|
+
saveInline(subject, "text-align");
|
|
533
|
+
saveInline(subject, "justify-content");
|
|
534
|
+
subject.style.setProperty("text-align", override.align, "important");
|
|
535
|
+
subject.style.setProperty(
|
|
536
|
+
"justify-content",
|
|
537
|
+
ALIGN_JUSTIFY[override.align] ?? "flex-start",
|
|
538
|
+
"important"
|
|
539
|
+
);
|
|
540
|
+
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
541
|
+
}
|
|
451
542
|
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
452
543
|
const surface = buttonSurfaceOf(el);
|
|
453
544
|
if (override.buttonBackground !== void 0) {
|
|
@@ -656,7 +747,7 @@ function TextBlock({ slots, ctx, path }) {
|
|
|
656
747
|
}
|
|
657
748
|
function SectionHeaderBlock({ node, ctx, path }) {
|
|
658
749
|
const slots = node.slots ?? {};
|
|
659
|
-
const align = slots.alignment === "center" ? "center" : "left";
|
|
750
|
+
const align = node.align ?? (slots.alignment === "center" ? "center" : "left");
|
|
660
751
|
const children = node.children ?? [];
|
|
661
752
|
const buttonRowIdx = children.findIndex((c) => c.type === "button-row");
|
|
662
753
|
const buttonRow = buttonRowIdx >= 0 ? children[buttonRowIdx] : void 0;
|
|
@@ -700,7 +791,7 @@ function SectionHeaderBlock({ node, ctx, path }) {
|
|
|
700
791
|
display: "flex",
|
|
701
792
|
gap: AI_TREE_TOKENS.spacing6,
|
|
702
793
|
marginTop: AI_TREE_TOKENS.spacing8,
|
|
703
|
-
justifyContent: align === "center" ? "center" : "flex-start"
|
|
794
|
+
justifyContent: align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start"
|
|
704
795
|
},
|
|
705
796
|
children: (buttonRow.children ?? []).map((button, i) => /* @__PURE__ */ jsx(
|
|
706
797
|
ButtonEl,
|
|
@@ -1033,7 +1124,7 @@ function CardBlock({ node, ctx, path }) {
|
|
|
1033
1124
|
editPath: `${path}.media`
|
|
1034
1125
|
}
|
|
1035
1126
|
) : null;
|
|
1036
|
-
const centered = slots.alignment === "center";
|
|
1127
|
+
const centered = (node.align ?? slots.alignment) === "center";
|
|
1037
1128
|
const content = /* @__PURE__ */ jsxs(
|
|
1038
1129
|
"div",
|
|
1039
1130
|
{
|
|
@@ -1752,6 +1843,19 @@ function AiTreeRenderer({
|
|
|
1752
1843
|
}
|
|
1753
1844
|
})();
|
|
1754
1845
|
const distributed = !isOverlay && settings.textDistribution;
|
|
1846
|
+
const rowAlignItems = (rowAlign) => {
|
|
1847
|
+
if (rowAlign === "top") return "start";
|
|
1848
|
+
if (rowAlign === "bottom") return "end";
|
|
1849
|
+
if (rowAlign === "center" || rowAlign === "stretch") return rowAlign;
|
|
1850
|
+
if (distributed === "space-between") return "stretch";
|
|
1851
|
+
return (distributed ?? settings.verticalPosition) === "top" ? "start" : "center";
|
|
1852
|
+
};
|
|
1853
|
+
const cellAlignStyle = (blockAlign) => blockAlign ? {
|
|
1854
|
+
display: "flex",
|
|
1855
|
+
flexDirection: "column",
|
|
1856
|
+
alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
|
|
1857
|
+
textAlign: blockAlign
|
|
1858
|
+
} : {};
|
|
1755
1859
|
return /* @__PURE__ */ jsxs(
|
|
1756
1860
|
"section",
|
|
1757
1861
|
{
|
|
@@ -1788,7 +1892,7 @@ function AiTreeRenderer({
|
|
|
1788
1892
|
display: "grid",
|
|
1789
1893
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1790
1894
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1791
|
-
alignItems:
|
|
1895
|
+
alignItems: rowAlignItems(row.align),
|
|
1792
1896
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1793
1897
|
},
|
|
1794
1898
|
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
|
|
@@ -1798,6 +1902,8 @@ function AiTreeRenderer({
|
|
|
1798
1902
|
style: {
|
|
1799
1903
|
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1800
1904
|
minWidth: 0,
|
|
1905
|
+
// Horizontal placement of the block's content within its column.
|
|
1906
|
+
...cellAlignStyle(block.align),
|
|
1801
1907
|
// space-between: each column becomes a flex column whose content spreads over
|
|
1802
1908
|
// the full row height instead of clumping at the top.
|
|
1803
1909
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
@@ -20257,12 +20363,35 @@ function OhhwellsBridge() {
|
|
|
20257
20363
|
window.addEventListener("message", handleAiSetBrand);
|
|
20258
20364
|
const handleAiSetStyles = (e) => {
|
|
20259
20365
|
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
20260
|
-
|
|
20366
|
+
let value = typeof e.data.value === "string" ? e.data.value : "";
|
|
20261
20367
|
const previous = stylesRef.current;
|
|
20368
|
+
let previousSections;
|
|
20369
|
+
const store = parseStyleStore(value);
|
|
20370
|
+
if (store) {
|
|
20371
|
+
const folded = foldAlignIntoTrees(parseAiSectionsState(aiSectionsRef.current), store);
|
|
20372
|
+
if (folded.changed) {
|
|
20373
|
+
const nextSections = serializeAiSectionsState(folded.state);
|
|
20374
|
+
if (nextSections !== aiSectionsRef.current) {
|
|
20375
|
+
previousSections = aiSectionsRef.current;
|
|
20376
|
+
aiSectionsRef.current = nextSections;
|
|
20377
|
+
applyAiSectionsToDom(folded.state);
|
|
20378
|
+
postToParentRef.current({
|
|
20379
|
+
type: "ow:change",
|
|
20380
|
+
nodes: [{ key: AI_SECTIONS_KEY, text: nextSections }]
|
|
20381
|
+
});
|
|
20382
|
+
}
|
|
20383
|
+
value = JSON.stringify(folded.store);
|
|
20384
|
+
}
|
|
20385
|
+
}
|
|
20262
20386
|
stylesRef.current = value;
|
|
20263
20387
|
applyStylesToDom(parseStyleStore(value));
|
|
20264
20388
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
20265
|
-
postToParentRef.current({
|
|
20389
|
+
postToParentRef.current({
|
|
20390
|
+
type: "ow:ai-styles-applied",
|
|
20391
|
+
previous,
|
|
20392
|
+
value,
|
|
20393
|
+
...previousSections !== void 0 ? { previousSections } : {}
|
|
20394
|
+
});
|
|
20266
20395
|
};
|
|
20267
20396
|
window.addEventListener("message", handleAiSetStyles);
|
|
20268
20397
|
const handleGetBrand = (e) => {
|
|
@@ -21283,7 +21412,7 @@ function OhhwellsBridge() {
|
|
|
21283
21412
|
postToParent2({
|
|
21284
21413
|
type: "ow:ready",
|
|
21285
21414
|
version: "1",
|
|
21286
|
-
bridgeVersion: "0.1.
|
|
21415
|
+
bridgeVersion: "0.1.91",
|
|
21287
21416
|
path: pathname,
|
|
21288
21417
|
nodes: collectEditableNodes(editContentRef.current),
|
|
21289
21418
|
sections
|