@ohhwells/bridge 0.1.140 → 0.1.142
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 +224 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +135 -1
- package/dist/index.d.ts +135 -1
- package/dist/index.js +222 -81
- package/dist/index.js.map +1 -1
- package/dist/styles.css +19 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -72,6 +72,7 @@ __export(index_exports, {
|
|
|
72
72
|
dropIndicatorVariants: () => dropIndicatorVariants,
|
|
73
73
|
ensureFooterTree: () => ensureFooterTree,
|
|
74
74
|
filterAvailablePages: () => filterAvailablePages,
|
|
75
|
+
foldAlignIntoTrees: () => foldAlignIntoTrees,
|
|
75
76
|
getEditModeInitialState: () => getEditModeInitialState,
|
|
76
77
|
insertFooterHours: () => insertFooterHours,
|
|
77
78
|
isEditSessionActive: () => isEditSessionActive,
|
|
@@ -80,6 +81,7 @@ __export(index_exports, {
|
|
|
80
81
|
isValidUrl: () => isValidUrl,
|
|
81
82
|
nextViableSlide: () => nextViableSlide,
|
|
82
83
|
parseAiFooterState: () => parseAiFooterState,
|
|
84
|
+
parseAiSectionsState: () => parseAiSectionsState,
|
|
83
85
|
parseTarget: () => parseTarget,
|
|
84
86
|
removeFooterBlock: () => removeFooterBlock,
|
|
85
87
|
resolveFooterCopyright: () => resolveFooterCopyright,
|
|
@@ -1348,15 +1350,25 @@ function readAssignments(content) {
|
|
|
1348
1350
|
function cssLength(style, prop) {
|
|
1349
1351
|
return style.getPropertyValue(prop) || "0px";
|
|
1350
1352
|
}
|
|
1353
|
+
function withTransitionsSettled(el, read) {
|
|
1354
|
+
const prior = el.style.getPropertyValue("transition");
|
|
1355
|
+
const priority = el.style.getPropertyPriority("transition");
|
|
1356
|
+
el.style.setProperty("transition", "none", "important");
|
|
1357
|
+
try {
|
|
1358
|
+
return read(getComputedStyle(el));
|
|
1359
|
+
} finally {
|
|
1360
|
+
if (prior) el.style.setProperty("transition", prior, priority);
|
|
1361
|
+
else el.style.removeProperty("transition");
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1351
1364
|
function readVariantSample(el) {
|
|
1352
|
-
|
|
1353
|
-
return {
|
|
1365
|
+
return withTransitionsSettled(el, (style) => ({
|
|
1354
1366
|
background: style.backgroundColor,
|
|
1355
1367
|
color: style.color,
|
|
1356
1368
|
borderColor: style.borderTopColor,
|
|
1357
1369
|
borderWidth: style.borderTopWidth,
|
|
1358
1370
|
className: el.className || ""
|
|
1359
|
-
};
|
|
1371
|
+
}));
|
|
1360
1372
|
}
|
|
1361
1373
|
function readSizeSample(el) {
|
|
1362
1374
|
const style = getComputedStyle(el);
|
|
@@ -5296,19 +5308,21 @@ function findIndexSegment(keys) {
|
|
|
5296
5308
|
if (len < 2 || tokenLists.some((t) => t.length !== len)) return null;
|
|
5297
5309
|
let position = -1;
|
|
5298
5310
|
for (let p = 0; p < len; p++) {
|
|
5299
|
-
const
|
|
5300
|
-
const allSame =
|
|
5311
|
+
const values2 = tokenLists.map((t) => t[p]);
|
|
5312
|
+
const allSame = values2.every((v) => v === values2[0]);
|
|
5301
5313
|
if (allSame) continue;
|
|
5302
|
-
|
|
5303
|
-
if (!allNumeric || position !== -1) return null;
|
|
5314
|
+
if (position !== -1) return null;
|
|
5304
5315
|
position = p;
|
|
5305
5316
|
}
|
|
5306
5317
|
if (position === -1) return null;
|
|
5318
|
+
const values = tokenLists.map((t) => t[position]);
|
|
5319
|
+
const numericCount = values.filter((v) => /^\d+$/.test(v)).length;
|
|
5320
|
+
if (numericCount !== 0 && numericCount !== values.length) return null;
|
|
5321
|
+
if (numericCount === 0 && position === len - 1) return null;
|
|
5307
5322
|
const group = tokenLists[0].slice(0, position).join("-");
|
|
5308
5323
|
if (!group) return null;
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
return { position, group };
|
|
5324
|
+
if (new Set(values).size !== values.length) return null;
|
|
5325
|
+
return numericCount === values.length ? { position, group } : { position, group, slug: true };
|
|
5312
5326
|
}
|
|
5313
5327
|
function singleIndexSegment(key) {
|
|
5314
5328
|
const tokens = baseKey(key).split("-");
|
|
@@ -5354,7 +5368,19 @@ function detectItemGroups(sectionEl) {
|
|
|
5354
5368
|
list.push(m);
|
|
5355
5369
|
byShape.set(shape, list);
|
|
5356
5370
|
}
|
|
5357
|
-
|
|
5371
|
+
const shaped = Array.from(byShape.values());
|
|
5372
|
+
clusters.push(...shaped.filter((c) => c.length >= 2));
|
|
5373
|
+
const singles = shaped.filter((c) => c.length === 1).map((c) => c[0]);
|
|
5374
|
+
const bySlugShape = /* @__PURE__ */ new Map();
|
|
5375
|
+
for (const m of singles) {
|
|
5376
|
+
const primary = primaryKey(keyedDescendants(m));
|
|
5377
|
+
const tokens = baseKey(primary ?? "").split("-");
|
|
5378
|
+
const slugShape = `${tokens.length}|${tokens[0]}|${tokens[tokens.length - 1]}`;
|
|
5379
|
+
const list = bySlugShape.get(slugShape) ?? [];
|
|
5380
|
+
list.push(m);
|
|
5381
|
+
bySlugShape.set(slugShape, list);
|
|
5382
|
+
}
|
|
5383
|
+
clusters.push(...Array.from(bySlugShape.values()));
|
|
5358
5384
|
}
|
|
5359
5385
|
for (const members of clusters) {
|
|
5360
5386
|
const keyedPerMember = members.map((m) => keyedDescendants(m));
|
|
@@ -5365,11 +5391,28 @@ function detectItemGroups(sectionEl) {
|
|
|
5365
5391
|
const dedupeKey = `${segment.group}`;
|
|
5366
5392
|
if (seenParents.has(dedupeKey)) continue;
|
|
5367
5393
|
seenParents.add(dedupeKey);
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5394
|
+
let items;
|
|
5395
|
+
if (segment.slug) {
|
|
5396
|
+
const tokens = members.map((_, i) => baseKey(primaries[i]).split("-")[segment.position]);
|
|
5397
|
+
let nextOriginal = 1;
|
|
5398
|
+
const indices = tokens.map((t) => {
|
|
5399
|
+
const cloneMatch = t.match(/^x(\d+)$/);
|
|
5400
|
+
return cloneMatch ? parseInt(cloneMatch[1], 10) : nextOriginal++;
|
|
5401
|
+
});
|
|
5402
|
+
if (new Set(indices).size !== indices.length) continue;
|
|
5403
|
+
items = members.map((el, i) => ({
|
|
5404
|
+
el,
|
|
5405
|
+
index: indices[i],
|
|
5406
|
+
keyed: keyedPerMember[i],
|
|
5407
|
+
slugToken: tokens[i]
|
|
5408
|
+
}));
|
|
5409
|
+
} else {
|
|
5410
|
+
items = members.map((el, i) => ({
|
|
5411
|
+
el,
|
|
5412
|
+
index: indexFromKey(primaries[i], segment.position),
|
|
5413
|
+
keyed: keyedPerMember[i]
|
|
5414
|
+
}));
|
|
5415
|
+
}
|
|
5373
5416
|
groups.push({ group: segment.group, parent, nested: false, items });
|
|
5374
5417
|
}
|
|
5375
5418
|
}
|
|
@@ -5493,6 +5536,18 @@ function rekeyItemClone(clone, source, sibling, group, newIndex) {
|
|
|
5493
5536
|
const delta = newIndex - source.index;
|
|
5494
5537
|
const cloneKeyed = keyedDescendants(clone);
|
|
5495
5538
|
const pairs = [];
|
|
5539
|
+
if (source.slugToken) {
|
|
5540
|
+
source.keyed.forEach((src, i) => {
|
|
5541
|
+
const target = cloneKeyed[i];
|
|
5542
|
+
if (!target || target.attr !== src.attr) return;
|
|
5543
|
+
const tokens = baseKey(src.key).split("-");
|
|
5544
|
+
if (!tokens.includes(source.slugToken)) return;
|
|
5545
|
+
const next = tokens.map((t) => t === source.slugToken ? `x${newIndex}` : t).join("-") + keySuffix(src.key);
|
|
5546
|
+
target.el.setAttribute(src.attr, next);
|
|
5547
|
+
pairs.push({ from: src.key, to: next });
|
|
5548
|
+
});
|
|
5549
|
+
return pairs;
|
|
5550
|
+
}
|
|
5496
5551
|
source.keyed.forEach((src, i) => {
|
|
5497
5552
|
const target = cloneKeyed[i];
|
|
5498
5553
|
if (!target || target.attr !== src.attr) return;
|
|
@@ -5536,7 +5591,12 @@ function syncGroup(detected, state) {
|
|
|
5536
5591
|
clone.setAttribute(ITEM_ATTR, `${detected.group}:${entry.index}`);
|
|
5537
5592
|
rekeyItemClone(clone, source, sibling, detected.group, entry.index);
|
|
5538
5593
|
source.el.insertAdjacentElement("afterend", clone);
|
|
5539
|
-
byIndex.set(entry.index, {
|
|
5594
|
+
byIndex.set(entry.index, {
|
|
5595
|
+
el: clone,
|
|
5596
|
+
index: entry.index,
|
|
5597
|
+
keyed: keyedDescendants(clone),
|
|
5598
|
+
...source.slugToken ? { slugToken: `x${entry.index}` } : {}
|
|
5599
|
+
});
|
|
5540
5600
|
}
|
|
5541
5601
|
const listed = state.items.map((e) => byIndex.get(e.index)?.el).filter((el) => !!el);
|
|
5542
5602
|
let prev = null;
|
|
@@ -5638,9 +5698,16 @@ function applyItemOps(store, ops, currentContent) {
|
|
|
5638
5698
|
const nodes = [];
|
|
5639
5699
|
const added = [];
|
|
5640
5700
|
let elements = syncGroup(detected, state);
|
|
5701
|
+
const sluggy = detected.items.some((item) => item.slugToken);
|
|
5702
|
+
const slugTokenOf = (index) => detected.items.find((item) => item.index === index)?.slugToken ?? (sluggy ? `x${index}` : void 0);
|
|
5641
5703
|
for (const add of ops.add ?? []) {
|
|
5642
5704
|
const sourceEl = elements.get(add.cloneOf);
|
|
5643
|
-
const source = sourceEl ? {
|
|
5705
|
+
const source = sourceEl ? {
|
|
5706
|
+
el: sourceEl,
|
|
5707
|
+
index: add.cloneOf,
|
|
5708
|
+
keyed: keyedDescendants(sourceEl),
|
|
5709
|
+
...slugTokenOf(add.cloneOf) ? { slugToken: slugTokenOf(add.cloneOf) } : {}
|
|
5710
|
+
} : void 0;
|
|
5644
5711
|
if (!source) continue;
|
|
5645
5712
|
const newIndex = Math.max(...state.items.map((e) => e.index), ...detected.items.map((i) => i.index)) + 1;
|
|
5646
5713
|
const sibling = detected.items.find((item) => item.index !== add.cloneOf && !item.el.hasAttribute(ITEM_CLONE_ATTR)) ?? null;
|
|
@@ -5667,7 +5734,12 @@ function applyItemOps(store, ops, currentContent) {
|
|
|
5667
5734
|
if (anchor) anchor.insertAdjacentElement("afterend", clone);
|
|
5668
5735
|
else source.el.insertAdjacentElement("afterend", clone);
|
|
5669
5736
|
elements.set(newIndex, clone);
|
|
5670
|
-
detected.items.push({
|
|
5737
|
+
detected.items.push({
|
|
5738
|
+
el: clone,
|
|
5739
|
+
index: newIndex,
|
|
5740
|
+
keyed: cloneKeyed,
|
|
5741
|
+
...sluggy ? { slugToken: `x${newIndex}` } : {}
|
|
5742
|
+
});
|
|
5671
5743
|
added.push(newIndex);
|
|
5672
5744
|
elements = syncGroup(detected, state);
|
|
5673
5745
|
}
|
|
@@ -6110,16 +6182,25 @@ function foldAlignIntoTrees(state, store) {
|
|
|
6110
6182
|
nextTrees.set(id, fresh);
|
|
6111
6183
|
return fresh;
|
|
6112
6184
|
};
|
|
6185
|
+
const stripChildAligns = (node) => node.children ? {
|
|
6186
|
+
...node,
|
|
6187
|
+
children: node.children.map((child) => {
|
|
6188
|
+
const { align: _dropped, ...rest } = child;
|
|
6189
|
+
return stripChildAligns(rest);
|
|
6190
|
+
})
|
|
6191
|
+
} : node;
|
|
6113
6192
|
const nodes = {};
|
|
6114
6193
|
for (const [key, override] of Object.entries(store.nodes)) {
|
|
6115
6194
|
const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
|
|
6116
6195
|
const tree = match ? treeFor(match[1]) : void 0;
|
|
6117
|
-
const
|
|
6118
|
-
|
|
6196
|
+
const row = match && tree ? tree.rows[Number(match[2])] : void 0;
|
|
6197
|
+
const blockIdx = match ? Number(match[3]) : -1;
|
|
6198
|
+
const block = row?.blocks[blockIdx];
|
|
6199
|
+
if (!row || !block) {
|
|
6119
6200
|
nodes[key] = override;
|
|
6120
6201
|
continue;
|
|
6121
6202
|
}
|
|
6122
|
-
|
|
6203
|
+
row.blocks[blockIdx] = { ...stripChildAligns(block), align: override.align };
|
|
6123
6204
|
const rest = { ...override };
|
|
6124
6205
|
delete rest.align;
|
|
6125
6206
|
if (Object.keys(rest).length > 0) nodes[key] = rest;
|
|
@@ -6132,7 +6213,7 @@ function foldAlignIntoTrees(state, store) {
|
|
|
6132
6213
|
continue;
|
|
6133
6214
|
}
|
|
6134
6215
|
for (const row of tree.rows) {
|
|
6135
|
-
|
|
6216
|
+
row.blocks = row.blocks.map((block) => ({ ...stripChildAligns(block), align: override.align }));
|
|
6136
6217
|
}
|
|
6137
6218
|
const rest = { ...override };
|
|
6138
6219
|
delete rest.align;
|
|
@@ -7293,6 +7374,7 @@ var blockAlignStyle = (blockAlign) => blockAlign ? {
|
|
|
7293
7374
|
alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
|
|
7294
7375
|
textAlign: blockAlign
|
|
7295
7376
|
} : {};
|
|
7377
|
+
var fullBleedBlock = (block) => block.type === "carousel" || block.type === "group" && str(block.slots?.layout) === "overlap";
|
|
7296
7378
|
var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
|
|
7297
7379
|
var AI_MOBILE_CSS = [
|
|
7298
7380
|
// Unscoped (applies at every viewport, not just mobile): re-enables pointer-events for the
|
|
@@ -9358,8 +9440,8 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9358
9440
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
9359
9441
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
9360
9442
|
// the full section width instead of reading at the usual content width.
|
|
9361
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: AI_TREE_TOKENS.sectionMaxWidth, margin: "0 auto", padding: "0 40px", width: "100%", boxSizing: "border-box" }, children: renderNode(child, ctx, `${path}.c${i}`, child.align ?? "center") })
|
|
9362
|
-
) : renderNode(child, ctx, `${path}.c${i}`, i > 0 ? child.align ?? "center" : void 0),
|
|
9443
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { maxWidth: AI_TREE_TOKENS.sectionMaxWidth, margin: "0 auto", padding: "0 40px", width: "100%", boxSizing: "border-box" }, children: renderNode(child, ctx, `${path}.c${i}`, child.align ?? node.align ?? "center") })
|
|
9444
|
+
) : renderNode(child, ctx, `${path}.c${i}`, i > 0 ? child.align ?? node.align ?? "center" : void 0),
|
|
9363
9445
|
i === 0 && needsBaseScrim && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9364
9446
|
"div",
|
|
9365
9447
|
{
|
|
@@ -9392,7 +9474,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9392
9474
|
// child otherwise stretches full-width (unchanged pre-existing behaviour).
|
|
9393
9475
|
...blockAlignStyle(child.align ?? ambientAlign)
|
|
9394
9476
|
},
|
|
9395
|
-
children: renderNode(child, ctx, `${path}.c${i}`, ambientAlign)
|
|
9477
|
+
children: renderNode(child, ctx, `${path}.c${i}`, node.align ?? ambientAlign)
|
|
9396
9478
|
},
|
|
9397
9479
|
i
|
|
9398
9480
|
));
|
|
@@ -9422,8 +9504,20 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
9422
9504
|
}
|
|
9423
9505
|
case "button":
|
|
9424
9506
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonEl, { slots, ctx, path });
|
|
9425
|
-
case "button-row":
|
|
9426
|
-
|
|
9507
|
+
case "button-row": {
|
|
9508
|
+
const rowAlign = node.align ?? ambientAlign;
|
|
9509
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9510
|
+
"div",
|
|
9511
|
+
{
|
|
9512
|
+
style: {
|
|
9513
|
+
display: "flex",
|
|
9514
|
+
gap: AI_TREE_TOKENS.spacing6,
|
|
9515
|
+
justifyContent: rowAlign === "left" ? "flex-start" : rowAlign === "right" ? "flex-end" : "center"
|
|
9516
|
+
},
|
|
9517
|
+
children: (node.children ?? []).map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }, i))
|
|
9518
|
+
}
|
|
9519
|
+
);
|
|
9520
|
+
}
|
|
9427
9521
|
case "media":
|
|
9428
9522
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
9429
9523
|
MediaBox,
|
|
@@ -9802,7 +9896,7 @@ function AiTreeRenderer({
|
|
|
9802
9896
|
// its own horizontal `align`, which takes priority for that block.
|
|
9803
9897
|
...fillHeight ? { display: "grid" } : {},
|
|
9804
9898
|
// Horizontal placement of the block's content within its column.
|
|
9805
|
-
...cellAlignStyle(block.align),
|
|
9899
|
+
...fullBleedBlock(block) ? {} : cellAlignStyle(block.align),
|
|
9806
9900
|
// space-between: each column becomes a flex column whose content spreads over
|
|
9807
9901
|
// the full row height instead of clumping at the top.
|
|
9808
9902
|
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
@@ -10197,38 +10291,39 @@ function deriveTemplateButtonStyle() {
|
|
|
10197
10291
|
el.querySelectorAll("[data-ohw-editable]").length <= 1
|
|
10198
10292
|
);
|
|
10199
10293
|
const isFilled = (el) => {
|
|
10200
|
-
const bg =
|
|
10294
|
+
const bg = withTransitionsSettled(el, (s) => s.backgroundColor);
|
|
10201
10295
|
if (!bg || bg === "transparent") return false;
|
|
10202
10296
|
const alpha = bg.match(/rgba?\([^)]*,\s*([\d.]+)\)$/);
|
|
10203
10297
|
return !alpha || parseFloat(alpha[1]) > 0;
|
|
10204
10298
|
};
|
|
10205
10299
|
const btn = candidates.find(isFilled) ?? candidates[0];
|
|
10206
10300
|
if (!btn) return null;
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
|
|
10215
|
-
|
|
10216
|
-
|
|
10217
|
-
|
|
10218
|
-
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10301
|
+
return withTransitionsSettled(btn, (cs) => {
|
|
10302
|
+
const filled = isFilled(btn);
|
|
10303
|
+
const corners = [
|
|
10304
|
+
cs.borderTopLeftRadius,
|
|
10305
|
+
cs.borderTopRightRadius,
|
|
10306
|
+
cs.borderBottomRightRadius,
|
|
10307
|
+
cs.borderBottomLeftRadius
|
|
10308
|
+
].map((v) => v || "0px");
|
|
10309
|
+
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
10310
|
+
const px2 = (v) => parseFloat(v) || 0;
|
|
10311
|
+
const lineHeight = px2(cs.lineHeight) || px2(cs.fontSize) * 1.2;
|
|
10312
|
+
const contentH = btn.getBoundingClientRect().height - px2(cs.borderTopWidth) - px2(cs.borderBottomWidth);
|
|
10313
|
+
const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
|
|
10314
|
+
const padY = Math.max(px2(cs.paddingTop), px2(cs.paddingBottom), impliedY);
|
|
10315
|
+
const padX = Math.max(px2(cs.paddingLeft), px2(cs.paddingRight));
|
|
10316
|
+
return {
|
|
10317
|
+
radius: radius || "10px",
|
|
10318
|
+
padding: `${padY}px ${padX}px`,
|
|
10319
|
+
...filled ? { background: cs.backgroundColor, color: cs.color } : {},
|
|
10320
|
+
fontFamily: cs.fontFamily || "",
|
|
10321
|
+
fontSize: cs.fontSize || "",
|
|
10322
|
+
fontWeight: cs.fontWeight || "",
|
|
10323
|
+
letterSpacing: cs.letterSpacing || "",
|
|
10324
|
+
textTransform: cs.textTransform || ""
|
|
10325
|
+
};
|
|
10326
|
+
});
|
|
10232
10327
|
}
|
|
10233
10328
|
var mounted = /* @__PURE__ */ new Map();
|
|
10234
10329
|
function findTemplateSection(id) {
|
|
@@ -18436,10 +18531,23 @@ function setPricingCardStyle(tree, index, style) {
|
|
|
18436
18531
|
});
|
|
18437
18532
|
}
|
|
18438
18533
|
function setPricingCardFeaturedTag(tree, index, on) {
|
|
18439
|
-
return
|
|
18534
|
+
return withPricingCollection(tree, (collection) => {
|
|
18535
|
+
const children = collection.children;
|
|
18536
|
+
if (index < 0 || index >= children.length) return false;
|
|
18537
|
+
if (on) {
|
|
18538
|
+
children.forEach((card, i) => {
|
|
18539
|
+
if (i === index) return;
|
|
18540
|
+
const prev2 = featuredOf(card);
|
|
18541
|
+
if (prev2.enabled !== true || badgeOf(prev2).length === 0) return;
|
|
18542
|
+
card.slots = card.slots ?? {};
|
|
18543
|
+
card.slots.featured = composeFeatured(pricingCardStyleOf(prev2), false, badgeOf(prev2));
|
|
18544
|
+
});
|
|
18545
|
+
}
|
|
18546
|
+
const target = children[index];
|
|
18547
|
+
target.slots = target.slots ?? {};
|
|
18440
18548
|
const prev = featuredOf(target);
|
|
18441
|
-
|
|
18442
|
-
|
|
18549
|
+
target.slots.featured = composeFeatured(pricingCardStyleOf(prev), on, badgeOf(prev));
|
|
18550
|
+
return true;
|
|
18443
18551
|
});
|
|
18444
18552
|
}
|
|
18445
18553
|
function pricingCardStyleOf(featured) {
|
|
@@ -18689,25 +18797,40 @@ function ToolbarSeparator() {
|
|
|
18689
18797
|
}
|
|
18690
18798
|
function CardStyleMenu({
|
|
18691
18799
|
value,
|
|
18692
|
-
onChange
|
|
18800
|
+
onChange,
|
|
18801
|
+
disabled = false
|
|
18693
18802
|
}) {
|
|
18694
18803
|
const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
|
|
18804
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
18805
|
+
"button",
|
|
18806
|
+
{
|
|
18807
|
+
type: "button",
|
|
18808
|
+
"aria-label": "Card style",
|
|
18809
|
+
disabled,
|
|
18810
|
+
className: cn(
|
|
18811
|
+
"inline-flex h-8 min-w-[110px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
|
|
18812
|
+
disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
18813
|
+
),
|
|
18814
|
+
children: [
|
|
18815
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StyleSwatch, { style: current.value }),
|
|
18816
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
18817
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
18818
|
+
]
|
|
18819
|
+
}
|
|
18820
|
+
);
|
|
18821
|
+
if (disabled) {
|
|
18822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
18823
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
|
|
18824
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
|
|
18825
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex", children: trigger }) }),
|
|
18826
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
|
|
18827
|
+
] })
|
|
18828
|
+
] });
|
|
18829
|
+
}
|
|
18695
18830
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
|
|
18696
18831
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
|
|
18697
18832
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu, { modal: false, children: [
|
|
18698
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuTrigger, { asChild: true, children:
|
|
18699
|
-
"button",
|
|
18700
|
-
{
|
|
18701
|
-
type: "button",
|
|
18702
|
-
"aria-label": "Card style",
|
|
18703
|
-
className: "inline-flex h-8 min-w-[110px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
|
|
18704
|
-
children: [
|
|
18705
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StyleSwatch, { style: current.value }),
|
|
18706
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex-1 text-left", children: current.label }),
|
|
18707
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
|
|
18708
|
-
]
|
|
18709
|
-
}
|
|
18710
|
-
) }),
|
|
18833
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
|
|
18711
18834
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
|
|
18712
18835
|
const selected = style.value === value;
|
|
18713
18836
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
@@ -18771,23 +18894,35 @@ function PricingCardToolbar({
|
|
|
18771
18894
|
mobile ? "flex-wrap justify-center" : "flex-nowrap"
|
|
18772
18895
|
),
|
|
18773
18896
|
children: [
|
|
18774
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle }),
|
|
18775
18897
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
|
|
18776
18898
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18777
18899
|
CustomToolbarButton,
|
|
18778
18900
|
{
|
|
18779
18901
|
type: "button",
|
|
18780
|
-
"aria-label": featuredTag ? "
|
|
18902
|
+
"aria-label": featuredTag ? "Unmark as featured" : "Mark as featured",
|
|
18781
18903
|
"aria-pressed": featuredTag,
|
|
18782
|
-
active: featuredTag,
|
|
18783
18904
|
onClick: () => onSetFeaturedTag(!featuredTag),
|
|
18784
|
-
className: "size-8",
|
|
18785
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18905
|
+
className: "group size-8",
|
|
18906
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
18907
|
+
import_lucide_react9.Star,
|
|
18908
|
+
{
|
|
18909
|
+
size: 16,
|
|
18910
|
+
fill: "currentColor",
|
|
18911
|
+
strokeWidth: 0,
|
|
18912
|
+
className: cn(
|
|
18913
|
+
"transition-colors",
|
|
18914
|
+
featuredTag ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
|
|
18915
|
+
),
|
|
18916
|
+
style: { pointerEvents: "none" }
|
|
18917
|
+
}
|
|
18918
|
+
)
|
|
18786
18919
|
}
|
|
18787
18920
|
) }),
|
|
18788
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "
|
|
18921
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
|
|
18789
18922
|
] }),
|
|
18790
18923
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18924
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
|
|
18925
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
|
|
18791
18926
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ButtonGlyph, {}) }),
|
|
18792
18927
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "relative inline-flex", children: [
|
|
18793
18928
|
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ButtonGlyph, {}),
|
|
@@ -18930,7 +19065,12 @@ function AiPricingCardOverlay({
|
|
|
18930
19065
|
index: active.index,
|
|
18931
19066
|
pending,
|
|
18932
19067
|
error,
|
|
18933
|
-
onAddTier: () =>
|
|
19068
|
+
onAddTier: () => {
|
|
19069
|
+
const newIndex = pricingCardCount(activeEntry.tree);
|
|
19070
|
+
void runMutation(active.sectionId, addPricingTier).then((applied) => {
|
|
19071
|
+
if (applied) setActive({ sectionId: active.sectionId, index: newIndex });
|
|
19072
|
+
});
|
|
19073
|
+
},
|
|
18934
19074
|
onRemoveTier: () => {
|
|
18935
19075
|
void runMutation(active.sectionId, (tree) => removePricingTier(tree, active.index)).then(
|
|
18936
19076
|
(applied) => {
|
|
@@ -30337,9 +30477,10 @@ function OhhwellsBridge() {
|
|
|
30337
30477
|
if (e.data?.type !== "ow:collect-section") return;
|
|
30338
30478
|
const sectionId = e.data.sectionId;
|
|
30339
30479
|
if (typeof sectionId !== "string" || !sectionId) return;
|
|
30340
|
-
const
|
|
30480
|
+
const foundEl = document.querySelector(
|
|
30341
30481
|
`[data-ohw-section="${CSS.escape(sectionId)}"]`
|
|
30342
30482
|
);
|
|
30483
|
+
const sectionEl = foundEl && !foundEl.hasAttribute("data-ohw-ai-template-hidden") && !foundEl.hasAttribute("data-ohw-ai-removed") && !foundEl.hasAttribute("data-ohw-ai-replaced-by") ? foundEl : null;
|
|
30343
30484
|
const nodes = sectionEl ? collectEditableNodes(void 0, sectionEl).filter(
|
|
30344
30485
|
(n) => n.key && !n.key.startsWith("__ohw_") && !["meta", "sections", "video-setting"].includes(n.type)
|
|
30345
30486
|
).map((n) => ({ ...n, text: n.text ?? "", type: normalizeAiNodeType(n.type) })) : [];
|
|
@@ -31078,7 +31219,7 @@ function OhhwellsBridge() {
|
|
|
31078
31219
|
postToParent2({
|
|
31079
31220
|
type: "ow:ready",
|
|
31080
31221
|
version: "1",
|
|
31081
|
-
bridgeVersion: "0.1.
|
|
31222
|
+
bridgeVersion: "0.1.141",
|
|
31082
31223
|
path: pathname,
|
|
31083
31224
|
nodes: collectEditableNodes(editContentRef.current),
|
|
31084
31225
|
sections
|
|
@@ -32294,6 +32435,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
32294
32435
|
dropIndicatorVariants,
|
|
32295
32436
|
ensureFooterTree,
|
|
32296
32437
|
filterAvailablePages,
|
|
32438
|
+
foldAlignIntoTrees,
|
|
32297
32439
|
getEditModeInitialState,
|
|
32298
32440
|
insertFooterHours,
|
|
32299
32441
|
isEditSessionActive,
|
|
@@ -32302,6 +32444,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
32302
32444
|
isValidUrl,
|
|
32303
32445
|
nextViableSlide,
|
|
32304
32446
|
parseAiFooterState,
|
|
32447
|
+
parseAiSectionsState,
|
|
32305
32448
|
parseTarget,
|
|
32306
32449
|
removeFooterBlock,
|
|
32307
32450
|
resolveFooterCopyright,
|