@ohhwells/bridge 0.1.145 → 0.1.147
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 +158 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +157 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -87,6 +87,7 @@ __export(index_exports, {
|
|
|
87
87
|
resolveFooterCopyright: () => resolveFooterCopyright,
|
|
88
88
|
serializeAiFooterState: () => serializeAiFooterState,
|
|
89
89
|
stepViableSlide: () => stepViableSlide,
|
|
90
|
+
stripTextAlignCss: () => stripTextAlignCss,
|
|
90
91
|
toggleVariants: () => toggleVariants,
|
|
91
92
|
useOhwCarousel: () => useOhwCarousel,
|
|
92
93
|
validateUrlInput: () => validateUrlInput,
|
|
@@ -6258,12 +6259,34 @@ function applyTreeToState(state, payload) {
|
|
|
6258
6259
|
...selfEdit ? priorEntry?.beforeSection ? { beforeSection: priorEntry.beforeSection } : {} : insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
|
|
6259
6260
|
...selfEdit ? priorEntry?.replaces ? { replaces: priorEntry.replaces } : {} : payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
|
|
6260
6261
|
tree: payload.tree,
|
|
6261
|
-
media
|
|
6262
|
+
// A column insert rebuilds the media map from the live DOM keys. The photo
|
|
6263
|
+
// still points at the ref it was generated with. Keep that ref.
|
|
6264
|
+
media: { ...priorEntry?.media ?? {}, ...payload.media ?? {} },
|
|
6262
6265
|
...payload.brand && typeof payload.brand === "object" ? { brand: payload.brand } : {}
|
|
6263
6266
|
};
|
|
6264
6267
|
const others = state.sections.filter((existing) => existing.id !== entry.id);
|
|
6265
6268
|
return { ...state, v: 1, sections: [...others, entry] };
|
|
6266
6269
|
}
|
|
6270
|
+
function stripTextAlignCss(html) {
|
|
6271
|
+
return html.replace(/\sstyle="([^"]*)"/gi, (whole, value) => {
|
|
6272
|
+
if (!/text-align\s*:/i.test(value)) return whole;
|
|
6273
|
+
const kept = value.split(";").map((decl) => decl.trim()).filter((decl) => decl && !/^text-align\s*:/i.test(decl)).join("; ");
|
|
6274
|
+
return kept ? ` style="${kept}"` : "";
|
|
6275
|
+
});
|
|
6276
|
+
}
|
|
6277
|
+
function stripTextAlignInValue(value) {
|
|
6278
|
+
if (typeof value === "string") return stripTextAlignCss(value);
|
|
6279
|
+
if (Array.isArray(value)) return value.map(stripTextAlignInValue);
|
|
6280
|
+
if (value && typeof value === "object") {
|
|
6281
|
+
return Object.fromEntries(
|
|
6282
|
+
Object.entries(value).map(([key, inner]) => [
|
|
6283
|
+
key,
|
|
6284
|
+
stripTextAlignInValue(inner)
|
|
6285
|
+
])
|
|
6286
|
+
);
|
|
6287
|
+
}
|
|
6288
|
+
return value;
|
|
6289
|
+
}
|
|
6267
6290
|
function foldAlignIntoTrees(state, store) {
|
|
6268
6291
|
const byId = new Map(state.sections.map((entry) => [entry.id, entry]));
|
|
6269
6292
|
const nextTrees = /* @__PURE__ */ new Map();
|
|
@@ -6286,6 +6309,12 @@ function foldAlignIntoTrees(state, store) {
|
|
|
6286
6309
|
return stripChildAligns(rest);
|
|
6287
6310
|
})
|
|
6288
6311
|
} : node;
|
|
6312
|
+
const stripContentAligns = (node) => ({
|
|
6313
|
+
...node,
|
|
6314
|
+
...node.slots ? { slots: stripTextAlignInValue(node.slots) } : {},
|
|
6315
|
+
...node.children ? { children: node.children.map(stripContentAligns) } : {}
|
|
6316
|
+
});
|
|
6317
|
+
const authoritative = (block) => stripChildAligns(stripContentAligns(block));
|
|
6289
6318
|
const nodes = {};
|
|
6290
6319
|
for (const [key, override] of Object.entries(store.nodes)) {
|
|
6291
6320
|
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
@@ -6297,7 +6326,7 @@ function foldAlignIntoTrees(state, store) {
|
|
|
6297
6326
|
nodes[key] = override;
|
|
6298
6327
|
continue;
|
|
6299
6328
|
}
|
|
6300
|
-
row.blocks[blockIdx] = { ...
|
|
6329
|
+
row.blocks[blockIdx] = { ...authoritative(block), align: override.align };
|
|
6301
6330
|
const rest = { ...override };
|
|
6302
6331
|
delete rest.align;
|
|
6303
6332
|
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
@@ -6310,7 +6339,7 @@ function foldAlignIntoTrees(state, store) {
|
|
|
6310
6339
|
continue;
|
|
6311
6340
|
}
|
|
6312
6341
|
for (const row of tree.rows) {
|
|
6313
|
-
row.blocks = row.blocks.map((block) => ({ ...
|
|
6342
|
+
row.blocks = row.blocks.map((block) => ({ ...authoritative(block), align: override.align }));
|
|
6314
6343
|
}
|
|
6315
6344
|
const rest = { ...override };
|
|
6316
6345
|
delete rest.align;
|
|
@@ -9759,6 +9788,46 @@ function FooterSocialRowBlock({
|
|
|
9759
9788
|
}
|
|
9760
9789
|
);
|
|
9761
9790
|
}
|
|
9791
|
+
function EmptySlotPlaceholder({ name }) {
|
|
9792
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9793
|
+
"div",
|
|
9794
|
+
{
|
|
9795
|
+
"data-ai-slot": name,
|
|
9796
|
+
"data-ai-slot-empty": "",
|
|
9797
|
+
"aria-hidden": "true",
|
|
9798
|
+
style: {
|
|
9799
|
+
minHeight: 88,
|
|
9800
|
+
borderRadius: 12,
|
|
9801
|
+
border: "1px dashed #D6D3D1",
|
|
9802
|
+
display: "flex",
|
|
9803
|
+
alignItems: "center",
|
|
9804
|
+
justifyContent: "center",
|
|
9805
|
+
padding: 16,
|
|
9806
|
+
color: "#A8A29E",
|
|
9807
|
+
fontSize: 13,
|
|
9808
|
+
lineHeight: 1.4,
|
|
9809
|
+
textAlign: "center",
|
|
9810
|
+
pointerEvents: "none"
|
|
9811
|
+
},
|
|
9812
|
+
children: "Ask AI to add something here"
|
|
9813
|
+
}
|
|
9814
|
+
);
|
|
9815
|
+
}
|
|
9816
|
+
function splitSides(node) {
|
|
9817
|
+
const named = /* @__PURE__ */ new Map();
|
|
9818
|
+
const unnamed = [];
|
|
9819
|
+
(node.children ?? []).forEach((child, index) => {
|
|
9820
|
+
if (child.slot === "left" || child.slot === "right") {
|
|
9821
|
+
named.set(child.slot, { node: child, index });
|
|
9822
|
+
} else {
|
|
9823
|
+
unnamed.push({ node: child, index });
|
|
9824
|
+
}
|
|
9825
|
+
});
|
|
9826
|
+
return {
|
|
9827
|
+
left: named.get("left") ?? unnamed.shift() ?? null,
|
|
9828
|
+
right: named.get("right") ?? unnamed.shift() ?? null
|
|
9829
|
+
};
|
|
9830
|
+
}
|
|
9762
9831
|
function renderNode(node, ctx, path, ambientAlign) {
|
|
9763
9832
|
const slots = node.slots ?? {};
|
|
9764
9833
|
switch (node.type) {
|
|
@@ -9766,9 +9835,11 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9766
9835
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TextBlock, { slots, ctx, path, align: node.align ?? ambientAlign });
|
|
9767
9836
|
// Layout container: arranges child blocks, contributes no content of its own. `grid` is a
|
|
9768
9837
|
// nested 12-column grid the children span (a collage is 3–5 media on it, bottom-aligned so
|
|
9769
|
-
// mixed aspects read as a composition); `split` is
|
|
9770
|
-
// is a column.
|
|
9771
|
-
//
|
|
9838
|
+
// mixed aspects read as a composition); `split` is left and right (index order when `slot`
|
|
9839
|
+
// is omitted); `stack` is a column. A missing split side is a canvas placeholder only when
|
|
9840
|
+
// `emptySlots` names it. A one-child split used to keep a row at span 12 (a testimonial
|
|
9841
|
+
// under a heading) sits centered at half the row width. Children render through this same
|
|
9842
|
+
// dispatcher, so edit markers, media resolution, and copy paths all work unchanged.
|
|
9772
9843
|
case "group": {
|
|
9773
9844
|
const layout = str(slots.layout);
|
|
9774
9845
|
const gap = slots.spacing === "tight" ? AI_TREE_TOKENS.spacing3 : slots.spacing === "airy" ? AI_TREE_TOKENS.spacing8 : AI_TREE_TOKENS.spacing6;
|
|
@@ -9866,24 +9937,38 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9866
9937
|
i
|
|
9867
9938
|
));
|
|
9868
9939
|
if (layout === "grid") {
|
|
9869
|
-
|
|
9940
|
+
const holes = ctx.keyFor ? node.emptySlots ?? [] : [];
|
|
9941
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
9870
9942
|
"div",
|
|
9871
9943
|
{
|
|
9872
9944
|
"data-ai-group": "grid",
|
|
9873
9945
|
style: { display: "grid", gridTemplateColumns: "repeat(12, 1fr)", gap, alignItems: "end" },
|
|
9874
|
-
children:
|
|
9946
|
+
children: [
|
|
9947
|
+
kids,
|
|
9948
|
+
holes.map((name) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridColumn: "span 6", minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptySlotPlaceholder, { name }) }, name))
|
|
9949
|
+
]
|
|
9875
9950
|
}
|
|
9876
9951
|
);
|
|
9877
9952
|
}
|
|
9878
9953
|
if (layout === "split") {
|
|
9954
|
+
const { left, right } = splitSides(node);
|
|
9955
|
+
const open = new Set(ctx.keyFor ? node.emptySlots ?? [] : []);
|
|
9956
|
+
const side = (entry, name) => entry ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { minWidth: 0 }, children: renderNode(entry.node, ctx, `${path}.c${entry.index}`) }, name) : open.has(name) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmptySlotPlaceholder, { name }, name) : null;
|
|
9957
|
+
if (!left && !open.has("left") || !right && !open.has("right")) {
|
|
9958
|
+
const only = left ?? right;
|
|
9959
|
+
return only ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-ai-group": "split", style: { display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: "50%", minWidth: 0 }, children: renderNode(only.node, ctx, `${path}.c${only.index}`) }) }) : null;
|
|
9960
|
+
}
|
|
9879
9961
|
const ratio = str(slots.ratio);
|
|
9880
9962
|
const cols = ratio === "3:5" ? "3fr 5fr" : ratio === "5:3" ? "5fr 3fr" : "1fr 1fr";
|
|
9881
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
9963
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
9882
9964
|
"div",
|
|
9883
9965
|
{
|
|
9884
9966
|
"data-ai-group": "split",
|
|
9885
9967
|
style: { display: "grid", gridTemplateColumns: cols, gap, alignItems: "center" },
|
|
9886
|
-
children:
|
|
9968
|
+
children: [
|
|
9969
|
+
side(left, "left"),
|
|
9970
|
+
side(right, "right")
|
|
9971
|
+
]
|
|
9887
9972
|
}
|
|
9888
9973
|
);
|
|
9889
9974
|
}
|
|
@@ -30154,14 +30239,73 @@ function OhhwellsBridge() {
|
|
|
30154
30239
|
value = JSON.stringify(foldedHeight.store);
|
|
30155
30240
|
}
|
|
30156
30241
|
}
|
|
30242
|
+
const restoreNodes = e.data.restoreNodes;
|
|
30243
|
+
const restored = [];
|
|
30244
|
+
if (restoreNodes && typeof restoreNodes === "object") {
|
|
30245
|
+
for (const [key, html] of Object.entries(restoreNodes)) {
|
|
30246
|
+
if (typeof html !== "string") continue;
|
|
30247
|
+
const els = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
|
|
30248
|
+
if (els.length === 0) continue;
|
|
30249
|
+
for (const el of Array.from(els)) el.innerHTML = html;
|
|
30250
|
+
editContentRef.current = { ...editContentRef.current, [key]: html };
|
|
30251
|
+
restored.push({ key, text: html });
|
|
30252
|
+
}
|
|
30253
|
+
}
|
|
30254
|
+
const previousNodes = {};
|
|
30255
|
+
const strippedNodes = [];
|
|
30256
|
+
if (!restoreNodes) {
|
|
30257
|
+
const aligned = parseStyleStore(value);
|
|
30258
|
+
const prior = parseStyleStore(previous);
|
|
30259
|
+
const keys = /* @__PURE__ */ new Set();
|
|
30260
|
+
if (aligned) {
|
|
30261
|
+
for (const [key, override] of Object.entries(aligned.nodes)) {
|
|
30262
|
+
if (override.align === void 0) continue;
|
|
30263
|
+
if (prior?.nodes[key]?.align === override.align) continue;
|
|
30264
|
+
keys.add(key);
|
|
30265
|
+
}
|
|
30266
|
+
for (const [sectionId, override] of Object.entries(aligned.sections)) {
|
|
30267
|
+
if (override.align === void 0) continue;
|
|
30268
|
+
if (prior?.sections[sectionId]?.align === override.align) continue;
|
|
30269
|
+
const escaped = CSS.escape(sectionId);
|
|
30270
|
+
const markers = document.querySelectorAll(
|
|
30271
|
+
`[data-ohw-instance="${escaped}"], [data-ohw-section="${escaped}"]`
|
|
30272
|
+
);
|
|
30273
|
+
for (const marker of Array.from(markers)) {
|
|
30274
|
+
const editables = marker.querySelectorAll(
|
|
30275
|
+
'[data-ohw-key][data-ohw-editable="text"], [data-ohw-key][data-ohw-editable="plain"]'
|
|
30276
|
+
);
|
|
30277
|
+
for (const el of Array.from(editables)) {
|
|
30278
|
+
const key = el.getAttribute("data-ohw-key");
|
|
30279
|
+
if (key) keys.add(key);
|
|
30280
|
+
}
|
|
30281
|
+
}
|
|
30282
|
+
}
|
|
30283
|
+
}
|
|
30284
|
+
for (const key of keys) {
|
|
30285
|
+
if (key.startsWith(AI_SLOT_KEY_PREFIX) || key.startsWith("__ohw_")) continue;
|
|
30286
|
+
const els = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
|
|
30287
|
+
if (els.length === 0) continue;
|
|
30288
|
+
const before = sanitizeHtml(els[0].innerHTML);
|
|
30289
|
+
const after = stripTextAlignCss(before);
|
|
30290
|
+
if (after === before) continue;
|
|
30291
|
+
for (const el of Array.from(els)) el.innerHTML = after;
|
|
30292
|
+
previousNodes[key] = before;
|
|
30293
|
+
editContentRef.current = { ...editContentRef.current, [key]: after };
|
|
30294
|
+
strippedNodes.push({ key, text: after });
|
|
30295
|
+
}
|
|
30296
|
+
}
|
|
30157
30297
|
stylesRef.current = value;
|
|
30158
30298
|
applyStylesToDom(parseStyleStore(value));
|
|
30159
|
-
postToParentRef.current({
|
|
30299
|
+
postToParentRef.current({
|
|
30300
|
+
type: "ow:change",
|
|
30301
|
+
nodes: [{ key: STYLE_STORE_KEY, text: value }, ...strippedNodes, ...restored]
|
|
30302
|
+
});
|
|
30160
30303
|
postToParentRef.current({
|
|
30161
30304
|
type: "ow:ai-styles-applied",
|
|
30162
30305
|
previous,
|
|
30163
30306
|
value,
|
|
30164
|
-
...previousSections !== void 0 ? { previousSections } : {}
|
|
30307
|
+
...previousSections !== void 0 ? { previousSections } : {},
|
|
30308
|
+
...Object.keys(previousNodes).length > 0 ? { previousNodes } : {}
|
|
30165
30309
|
});
|
|
30166
30310
|
};
|
|
30167
30311
|
window.addEventListener("message", handleAiSetStyles);
|
|
@@ -31506,7 +31650,7 @@ function OhhwellsBridge() {
|
|
|
31506
31650
|
postToParent2({
|
|
31507
31651
|
type: "ow:ready",
|
|
31508
31652
|
version: "1",
|
|
31509
|
-
bridgeVersion: "0.1.
|
|
31653
|
+
bridgeVersion: "0.1.146",
|
|
31510
31654
|
path: pathname,
|
|
31511
31655
|
nodes: collectEditableNodes(editContentRef.current),
|
|
31512
31656
|
sections
|
|
@@ -32737,6 +32881,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
32737
32881
|
resolveFooterCopyright,
|
|
32738
32882
|
serializeAiFooterState,
|
|
32739
32883
|
stepViableSlide,
|
|
32884
|
+
stripTextAlignCss,
|
|
32740
32885
|
toggleVariants,
|
|
32741
32886
|
useOhwCarousel,
|
|
32742
32887
|
validateUrlInput,
|