@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.js CHANGED
@@ -1256,15 +1256,25 @@ function readAssignments(content) {
1256
1256
  function cssLength(style, prop) {
1257
1257
  return style.getPropertyValue(prop) || "0px";
1258
1258
  }
1259
+ function withTransitionsSettled(el, read) {
1260
+ const prior = el.style.getPropertyValue("transition");
1261
+ const priority = el.style.getPropertyPriority("transition");
1262
+ el.style.setProperty("transition", "none", "important");
1263
+ try {
1264
+ return read(getComputedStyle(el));
1265
+ } finally {
1266
+ if (prior) el.style.setProperty("transition", prior, priority);
1267
+ else el.style.removeProperty("transition");
1268
+ }
1269
+ }
1259
1270
  function readVariantSample(el) {
1260
- const style = getComputedStyle(el);
1261
- return {
1271
+ return withTransitionsSettled(el, (style) => ({
1262
1272
  background: style.backgroundColor,
1263
1273
  color: style.color,
1264
1274
  borderColor: style.borderTopColor,
1265
1275
  borderWidth: style.borderTopWidth,
1266
1276
  className: el.className || ""
1267
- };
1277
+ }));
1268
1278
  }
1269
1279
  function readSizeSample(el) {
1270
1280
  const style = getComputedStyle(el);
@@ -5204,19 +5214,21 @@ function findIndexSegment(keys) {
5204
5214
  if (len < 2 || tokenLists.some((t) => t.length !== len)) return null;
5205
5215
  let position = -1;
5206
5216
  for (let p = 0; p < len; p++) {
5207
- const values = tokenLists.map((t) => t[p]);
5208
- const allSame = values.every((v) => v === values[0]);
5217
+ const values2 = tokenLists.map((t) => t[p]);
5218
+ const allSame = values2.every((v) => v === values2[0]);
5209
5219
  if (allSame) continue;
5210
- const allNumeric = values.every((v) => /^\d+$/.test(v));
5211
- if (!allNumeric || position !== -1) return null;
5220
+ if (position !== -1) return null;
5212
5221
  position = p;
5213
5222
  }
5214
5223
  if (position === -1) return null;
5224
+ const values = tokenLists.map((t) => t[position]);
5225
+ const numericCount = values.filter((v) => /^\d+$/.test(v)).length;
5226
+ if (numericCount !== 0 && numericCount !== values.length) return null;
5227
+ if (numericCount === 0 && position === len - 1) return null;
5215
5228
  const group = tokenLists[0].slice(0, position).join("-");
5216
5229
  if (!group) return null;
5217
- const indices = tokenLists.map((t) => parseInt(t[position], 10));
5218
- if (new Set(indices).size !== indices.length) return null;
5219
- return { position, group };
5230
+ if (new Set(values).size !== values.length) return null;
5231
+ return numericCount === values.length ? { position, group } : { position, group, slug: true };
5220
5232
  }
5221
5233
  function singleIndexSegment(key) {
5222
5234
  const tokens = baseKey(key).split("-");
@@ -5262,7 +5274,19 @@ function detectItemGroups(sectionEl) {
5262
5274
  list.push(m);
5263
5275
  byShape.set(shape, list);
5264
5276
  }
5265
- clusters.push(...Array.from(byShape.values()));
5277
+ const shaped = Array.from(byShape.values());
5278
+ clusters.push(...shaped.filter((c) => c.length >= 2));
5279
+ const singles = shaped.filter((c) => c.length === 1).map((c) => c[0]);
5280
+ const bySlugShape = /* @__PURE__ */ new Map();
5281
+ for (const m of singles) {
5282
+ const primary = primaryKey(keyedDescendants(m));
5283
+ const tokens = baseKey(primary ?? "").split("-");
5284
+ const slugShape = `${tokens.length}|${tokens[0]}|${tokens[tokens.length - 1]}`;
5285
+ const list = bySlugShape.get(slugShape) ?? [];
5286
+ list.push(m);
5287
+ bySlugShape.set(slugShape, list);
5288
+ }
5289
+ clusters.push(...Array.from(bySlugShape.values()));
5266
5290
  }
5267
5291
  for (const members of clusters) {
5268
5292
  const keyedPerMember = members.map((m) => keyedDescendants(m));
@@ -5273,11 +5297,28 @@ function detectItemGroups(sectionEl) {
5273
5297
  const dedupeKey = `${segment.group}`;
5274
5298
  if (seenParents.has(dedupeKey)) continue;
5275
5299
  seenParents.add(dedupeKey);
5276
- const items = members.map((el, i) => ({
5277
- el,
5278
- index: indexFromKey(primaries[i], segment.position),
5279
- keyed: keyedPerMember[i]
5280
- }));
5300
+ let items;
5301
+ if (segment.slug) {
5302
+ const tokens = members.map((_, i) => baseKey(primaries[i]).split("-")[segment.position]);
5303
+ let nextOriginal = 1;
5304
+ const indices = tokens.map((t) => {
5305
+ const cloneMatch = t.match(/^x(\d+)$/);
5306
+ return cloneMatch ? parseInt(cloneMatch[1], 10) : nextOriginal++;
5307
+ });
5308
+ if (new Set(indices).size !== indices.length) continue;
5309
+ items = members.map((el, i) => ({
5310
+ el,
5311
+ index: indices[i],
5312
+ keyed: keyedPerMember[i],
5313
+ slugToken: tokens[i]
5314
+ }));
5315
+ } else {
5316
+ items = members.map((el, i) => ({
5317
+ el,
5318
+ index: indexFromKey(primaries[i], segment.position),
5319
+ keyed: keyedPerMember[i]
5320
+ }));
5321
+ }
5281
5322
  groups.push({ group: segment.group, parent, nested: false, items });
5282
5323
  }
5283
5324
  }
@@ -5401,6 +5442,18 @@ function rekeyItemClone(clone, source, sibling, group, newIndex) {
5401
5442
  const delta = newIndex - source.index;
5402
5443
  const cloneKeyed = keyedDescendants(clone);
5403
5444
  const pairs = [];
5445
+ if (source.slugToken) {
5446
+ source.keyed.forEach((src, i) => {
5447
+ const target = cloneKeyed[i];
5448
+ if (!target || target.attr !== src.attr) return;
5449
+ const tokens = baseKey(src.key).split("-");
5450
+ if (!tokens.includes(source.slugToken)) return;
5451
+ const next = tokens.map((t) => t === source.slugToken ? `x${newIndex}` : t).join("-") + keySuffix(src.key);
5452
+ target.el.setAttribute(src.attr, next);
5453
+ pairs.push({ from: src.key, to: next });
5454
+ });
5455
+ return pairs;
5456
+ }
5404
5457
  source.keyed.forEach((src, i) => {
5405
5458
  const target = cloneKeyed[i];
5406
5459
  if (!target || target.attr !== src.attr) return;
@@ -5444,7 +5497,12 @@ function syncGroup(detected, state) {
5444
5497
  clone.setAttribute(ITEM_ATTR, `${detected.group}:${entry.index}`);
5445
5498
  rekeyItemClone(clone, source, sibling, detected.group, entry.index);
5446
5499
  source.el.insertAdjacentElement("afterend", clone);
5447
- byIndex.set(entry.index, { el: clone, index: entry.index, keyed: keyedDescendants(clone) });
5500
+ byIndex.set(entry.index, {
5501
+ el: clone,
5502
+ index: entry.index,
5503
+ keyed: keyedDescendants(clone),
5504
+ ...source.slugToken ? { slugToken: `x${entry.index}` } : {}
5505
+ });
5448
5506
  }
5449
5507
  const listed = state.items.map((e) => byIndex.get(e.index)?.el).filter((el) => !!el);
5450
5508
  let prev = null;
@@ -5546,9 +5604,16 @@ function applyItemOps(store, ops, currentContent) {
5546
5604
  const nodes = [];
5547
5605
  const added = [];
5548
5606
  let elements = syncGroup(detected, state);
5607
+ const sluggy = detected.items.some((item) => item.slugToken);
5608
+ const slugTokenOf = (index) => detected.items.find((item) => item.index === index)?.slugToken ?? (sluggy ? `x${index}` : void 0);
5549
5609
  for (const add of ops.add ?? []) {
5550
5610
  const sourceEl = elements.get(add.cloneOf);
5551
- const source = sourceEl ? { el: sourceEl, index: add.cloneOf, keyed: keyedDescendants(sourceEl) } : void 0;
5611
+ const source = sourceEl ? {
5612
+ el: sourceEl,
5613
+ index: add.cloneOf,
5614
+ keyed: keyedDescendants(sourceEl),
5615
+ ...slugTokenOf(add.cloneOf) ? { slugToken: slugTokenOf(add.cloneOf) } : {}
5616
+ } : void 0;
5552
5617
  if (!source) continue;
5553
5618
  const newIndex = Math.max(...state.items.map((e) => e.index), ...detected.items.map((i) => i.index)) + 1;
5554
5619
  const sibling = detected.items.find((item) => item.index !== add.cloneOf && !item.el.hasAttribute(ITEM_CLONE_ATTR)) ?? null;
@@ -5575,7 +5640,12 @@ function applyItemOps(store, ops, currentContent) {
5575
5640
  if (anchor) anchor.insertAdjacentElement("afterend", clone);
5576
5641
  else source.el.insertAdjacentElement("afterend", clone);
5577
5642
  elements.set(newIndex, clone);
5578
- detected.items.push({ el: clone, index: newIndex, keyed: cloneKeyed });
5643
+ detected.items.push({
5644
+ el: clone,
5645
+ index: newIndex,
5646
+ keyed: cloneKeyed,
5647
+ ...sluggy ? { slugToken: `x${newIndex}` } : {}
5648
+ });
5579
5649
  added.push(newIndex);
5580
5650
  elements = syncGroup(detected, state);
5581
5651
  }
@@ -6018,16 +6088,25 @@ function foldAlignIntoTrees(state, store) {
6018
6088
  nextTrees.set(id, fresh);
6019
6089
  return fresh;
6020
6090
  };
6091
+ const stripChildAligns = (node) => node.children ? {
6092
+ ...node,
6093
+ children: node.children.map((child) => {
6094
+ const { align: _dropped, ...rest } = child;
6095
+ return stripChildAligns(rest);
6096
+ })
6097
+ } : node;
6021
6098
  const nodes = {};
6022
6099
  for (const [key, override] of Object.entries(store.nodes)) {
6023
6100
  const match = override.align !== void 0 && key.startsWith(AI_SLOT_KEY_PREFIX) ? key.match(/^ai\.(.+?)\.r(\d+)\.b(\d+)(?:\.|$)/) : null;
6024
6101
  const tree = match ? treeFor(match[1]) : void 0;
6025
- const block = match && tree ? tree.rows[Number(match[2])]?.blocks[Number(match[3])] : void 0;
6026
- if (!block) {
6102
+ const row = match && tree ? tree.rows[Number(match[2])] : void 0;
6103
+ const blockIdx = match ? Number(match[3]) : -1;
6104
+ const block = row?.blocks[blockIdx];
6105
+ if (!row || !block) {
6027
6106
  nodes[key] = override;
6028
6107
  continue;
6029
6108
  }
6030
- block.align = override.align;
6109
+ row.blocks[blockIdx] = { ...stripChildAligns(block), align: override.align };
6031
6110
  const rest = { ...override };
6032
6111
  delete rest.align;
6033
6112
  if (Object.keys(rest).length > 0) nodes[key] = rest;
@@ -6040,7 +6119,7 @@ function foldAlignIntoTrees(state, store) {
6040
6119
  continue;
6041
6120
  }
6042
6121
  for (const row of tree.rows) {
6043
- for (const block of row.blocks) block.align = override.align;
6122
+ row.blocks = row.blocks.map((block) => ({ ...stripChildAligns(block), align: override.align }));
6044
6123
  }
6045
6124
  const rest = { ...override };
6046
6125
  delete rest.align;
@@ -7201,6 +7280,7 @@ var blockAlignStyle = (blockAlign) => blockAlign ? {
7201
7280
  alignItems: blockAlign === "left" ? "flex-start" : blockAlign === "right" ? "flex-end" : "center",
7202
7281
  textAlign: blockAlign
7203
7282
  } : {};
7283
+ var fullBleedBlock = (block) => block.type === "carousel" || block.type === "group" && str(block.slots?.layout) === "overlap";
7204
7284
  var featureLines = (value) => value.split(/\n|<br\s*\/?>/i).map((line) => line.trim()).filter(Boolean);
7205
7285
  var AI_MOBILE_CSS = [
7206
7286
  // Unscoped (applies at every viewport, not just mobile): re-enables pointer-events for the
@@ -9266,8 +9346,8 @@ function renderNode(node, ctx, path, ambientAlign) {
9266
9346
  // layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
9267
9347
  // scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
9268
9348
  // the full section width instead of reading at the usual content width.
9269
- /* @__PURE__ */ 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") })
9270
- ) : renderNode(child, ctx, `${path}.c${i}`, i > 0 ? child.align ?? "center" : void 0),
9349
+ /* @__PURE__ */ 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") })
9350
+ ) : renderNode(child, ctx, `${path}.c${i}`, i > 0 ? child.align ?? node.align ?? "center" : void 0),
9271
9351
  i === 0 && needsBaseScrim && /* @__PURE__ */ jsx(
9272
9352
  "div",
9273
9353
  {
@@ -9300,7 +9380,7 @@ function renderNode(node, ctx, path, ambientAlign) {
9300
9380
  // child otherwise stretches full-width (unchanged pre-existing behaviour).
9301
9381
  ...blockAlignStyle(child.align ?? ambientAlign)
9302
9382
  },
9303
- children: renderNode(child, ctx, `${path}.c${i}`, ambientAlign)
9383
+ children: renderNode(child, ctx, `${path}.c${i}`, node.align ?? ambientAlign)
9304
9384
  },
9305
9385
  i
9306
9386
  ));
@@ -9330,8 +9410,20 @@ function renderNode(node, ctx, path, ambientAlign) {
9330
9410
  }
9331
9411
  case "button":
9332
9412
  return /* @__PURE__ */ jsx(ButtonEl, { slots, ctx, path });
9333
- case "button-row":
9334
- return /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: AI_TREE_TOKENS.spacing6, justifyContent: "center" }, children: (node.children ?? []).map((child, i) => /* @__PURE__ */ jsx(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }, i)) });
9413
+ case "button-row": {
9414
+ const rowAlign = node.align ?? ambientAlign;
9415
+ return /* @__PURE__ */ jsx(
9416
+ "div",
9417
+ {
9418
+ style: {
9419
+ display: "flex",
9420
+ gap: AI_TREE_TOKENS.spacing6,
9421
+ justifyContent: rowAlign === "left" ? "flex-start" : rowAlign === "right" ? "flex-end" : "center"
9422
+ },
9423
+ children: (node.children ?? []).map((child, i) => /* @__PURE__ */ jsx(ButtonEl, { slots: child.slots ?? {}, ctx, path: `${path}.c${i}` }, i))
9424
+ }
9425
+ );
9426
+ }
9335
9427
  case "media":
9336
9428
  return /* @__PURE__ */ jsx(
9337
9429
  MediaBox,
@@ -9710,7 +9802,7 @@ function AiTreeRenderer({
9710
9802
  // its own horizontal `align`, which takes priority for that block.
9711
9803
  ...fillHeight ? { display: "grid" } : {},
9712
9804
  // Horizontal placement of the block's content within its column.
9713
- ...cellAlignStyle(block.align),
9805
+ ...fullBleedBlock(block) ? {} : cellAlignStyle(block.align),
9714
9806
  // space-between: each column becomes a flex column whose content spreads over
9715
9807
  // the full row height instead of clumping at the top.
9716
9808
  ...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
@@ -10105,38 +10197,39 @@ function deriveTemplateButtonStyle() {
10105
10197
  el.querySelectorAll("[data-ohw-editable]").length <= 1
10106
10198
  );
10107
10199
  const isFilled = (el) => {
10108
- const bg = getComputedStyle(el).backgroundColor;
10200
+ const bg = withTransitionsSettled(el, (s) => s.backgroundColor);
10109
10201
  if (!bg || bg === "transparent") return false;
10110
10202
  const alpha = bg.match(/rgba?\([^)]*,\s*([\d.]+)\)$/);
10111
10203
  return !alpha || parseFloat(alpha[1]) > 0;
10112
10204
  };
10113
10205
  const btn = candidates.find(isFilled) ?? candidates[0];
10114
10206
  if (!btn) return null;
10115
- const cs = getComputedStyle(btn);
10116
- const filled = isFilled(btn);
10117
- const corners = [
10118
- cs.borderTopLeftRadius,
10119
- cs.borderTopRightRadius,
10120
- cs.borderBottomRightRadius,
10121
- cs.borderBottomLeftRadius
10122
- ].map((v) => v || "0px");
10123
- const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
10124
- const px2 = (v) => parseFloat(v) || 0;
10125
- const lineHeight = px2(cs.lineHeight) || px2(cs.fontSize) * 1.2;
10126
- const contentH = btn.getBoundingClientRect().height - px2(cs.borderTopWidth) - px2(cs.borderBottomWidth);
10127
- const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
10128
- const padY = Math.max(px2(cs.paddingTop), px2(cs.paddingBottom), impliedY);
10129
- const padX = Math.max(px2(cs.paddingLeft), px2(cs.paddingRight));
10130
- return {
10131
- radius: radius || "10px",
10132
- padding: `${padY}px ${padX}px`,
10133
- ...filled ? { background: cs.backgroundColor, color: cs.color } : {},
10134
- fontFamily: cs.fontFamily || "",
10135
- fontSize: cs.fontSize || "",
10136
- fontWeight: cs.fontWeight || "",
10137
- letterSpacing: cs.letterSpacing || "",
10138
- textTransform: cs.textTransform || ""
10139
- };
10207
+ return withTransitionsSettled(btn, (cs) => {
10208
+ const filled = isFilled(btn);
10209
+ const corners = [
10210
+ cs.borderTopLeftRadius,
10211
+ cs.borderTopRightRadius,
10212
+ cs.borderBottomRightRadius,
10213
+ cs.borderBottomLeftRadius
10214
+ ].map((v) => v || "0px");
10215
+ const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
10216
+ const px2 = (v) => parseFloat(v) || 0;
10217
+ const lineHeight = px2(cs.lineHeight) || px2(cs.fontSize) * 1.2;
10218
+ const contentH = btn.getBoundingClientRect().height - px2(cs.borderTopWidth) - px2(cs.borderBottomWidth);
10219
+ const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
10220
+ const padY = Math.max(px2(cs.paddingTop), px2(cs.paddingBottom), impliedY);
10221
+ const padX = Math.max(px2(cs.paddingLeft), px2(cs.paddingRight));
10222
+ return {
10223
+ radius: radius || "10px",
10224
+ padding: `${padY}px ${padX}px`,
10225
+ ...filled ? { background: cs.backgroundColor, color: cs.color } : {},
10226
+ fontFamily: cs.fontFamily || "",
10227
+ fontSize: cs.fontSize || "",
10228
+ fontWeight: cs.fontWeight || "",
10229
+ letterSpacing: cs.letterSpacing || "",
10230
+ textTransform: cs.textTransform || ""
10231
+ };
10232
+ });
10140
10233
  }
10141
10234
  var mounted = /* @__PURE__ */ new Map();
10142
10235
  function findTemplateSection(id) {
@@ -18344,10 +18437,23 @@ function setPricingCardStyle(tree, index, style) {
18344
18437
  });
18345
18438
  }
18346
18439
  function setPricingCardFeaturedTag(tree, index, on) {
18347
- return withPricingCard(tree, index, (target) => {
18440
+ return withPricingCollection(tree, (collection) => {
18441
+ const children = collection.children;
18442
+ if (index < 0 || index >= children.length) return false;
18443
+ if (on) {
18444
+ children.forEach((card, i) => {
18445
+ if (i === index) return;
18446
+ const prev2 = featuredOf(card);
18447
+ if (prev2.enabled !== true || badgeOf(prev2).length === 0) return;
18448
+ card.slots = card.slots ?? {};
18449
+ card.slots.featured = composeFeatured(pricingCardStyleOf(prev2), false, badgeOf(prev2));
18450
+ });
18451
+ }
18452
+ const target = children[index];
18453
+ target.slots = target.slots ?? {};
18348
18454
  const prev = featuredOf(target);
18349
- const style = pricingCardStyleOf(prev);
18350
- target.slots.featured = composeFeatured(style, on, badgeOf(prev));
18455
+ target.slots.featured = composeFeatured(pricingCardStyleOf(prev), on, badgeOf(prev));
18456
+ return true;
18351
18457
  });
18352
18458
  }
18353
18459
  function pricingCardStyleOf(featured) {
@@ -18597,25 +18703,40 @@ function ToolbarSeparator() {
18597
18703
  }
18598
18704
  function CardStyleMenu({
18599
18705
  value,
18600
- onChange
18706
+ onChange,
18707
+ disabled = false
18601
18708
  }) {
18602
18709
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
18710
+ const trigger = /* @__PURE__ */ jsxs11(
18711
+ "button",
18712
+ {
18713
+ type: "button",
18714
+ "aria-label": "Card style",
18715
+ disabled,
18716
+ className: cn(
18717
+ "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",
18718
+ disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
18719
+ ),
18720
+ children: [
18721
+ /* @__PURE__ */ jsx20(StyleSwatch, { style: current.value }),
18722
+ /* @__PURE__ */ jsx20("span", { className: "flex-1 text-left", children: current.label }),
18723
+ /* @__PURE__ */ jsx20(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18724
+ ]
18725
+ }
18726
+ );
18727
+ if (disabled) {
18728
+ return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18729
+ /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
18730
+ /* @__PURE__ */ jsxs11(Tooltip, { children: [
18731
+ /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20("span", { className: "inline-flex", children: trigger }) }),
18732
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
18733
+ ] })
18734
+ ] });
18735
+ }
18603
18736
  return /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18604
18737
  /* @__PURE__ */ jsx20("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
18605
18738
  /* @__PURE__ */ jsxs11(DropdownMenu, { modal: false, children: [
18606
- /* @__PURE__ */ jsx20(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs11(
18607
- "button",
18608
- {
18609
- type: "button",
18610
- "aria-label": "Card style",
18611
- 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",
18612
- children: [
18613
- /* @__PURE__ */ jsx20(StyleSwatch, { style: current.value }),
18614
- /* @__PURE__ */ jsx20("span", { className: "flex-1 text-left", children: current.label }),
18615
- /* @__PURE__ */ jsx20(ChevronDown3, { size: 16, style: { pointerEvents: "none" } })
18616
- ]
18617
- }
18618
- ) }),
18739
+ /* @__PURE__ */ jsx20(DropdownMenuTrigger, { asChild: true, children: trigger }),
18619
18740
  /* @__PURE__ */ jsx20(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
18620
18741
  const selected = style.value === value;
18621
18742
  return /* @__PURE__ */ jsxs11(
@@ -18679,23 +18800,35 @@ function PricingCardToolbar({
18679
18800
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
18680
18801
  ),
18681
18802
  children: [
18682
- /* @__PURE__ */ jsx20(CardStyleMenu, { value: style, onChange: onSetStyle }),
18683
18803
  /* @__PURE__ */ jsxs11(Tooltip, { children: [
18684
18804
  /* @__PURE__ */ jsx20(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx20(
18685
18805
  CustomToolbarButton,
18686
18806
  {
18687
18807
  type: "button",
18688
- "aria-label": featuredTag ? "Remove featured tag" : "Add featured tag",
18808
+ "aria-label": featuredTag ? "Unmark as featured" : "Mark as featured",
18689
18809
  "aria-pressed": featuredTag,
18690
- active: featuredTag,
18691
18810
  onClick: () => onSetFeaturedTag(!featuredTag),
18692
- className: "size-8",
18693
- children: /* @__PURE__ */ jsx20(Star2, { size: 16, fill: featuredTag ? "currentColor" : "none", style: { pointerEvents: "none" } })
18811
+ className: "group size-8",
18812
+ children: /* @__PURE__ */ jsx20(
18813
+ Star2,
18814
+ {
18815
+ size: 16,
18816
+ fill: "currentColor",
18817
+ strokeWidth: 0,
18818
+ className: cn(
18819
+ "transition-colors",
18820
+ featuredTag ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
18821
+ ),
18822
+ style: { pointerEvents: "none" }
18823
+ }
18824
+ )
18694
18825
  }
18695
18826
  ) }),
18696
- /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Remove featured tag" : "Add featured tag" })
18827
+ /* @__PURE__ */ jsx20(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
18697
18828
  ] }),
18698
18829
  /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18830
+ /* @__PURE__ */ jsx20(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
18831
+ /* @__PURE__ */ jsx20(ToolbarSeparator, {}),
18699
18832
  /* @__PURE__ */ jsx20(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ jsx20(ButtonGlyph, {}) }),
18700
18833
  /* @__PURE__ */ jsx20(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ jsxs11("span", { className: "relative inline-flex", children: [
18701
18834
  /* @__PURE__ */ jsx20(ButtonGlyph, {}),
@@ -18838,7 +18971,12 @@ function AiPricingCardOverlay({
18838
18971
  index: active.index,
18839
18972
  pending,
18840
18973
  error,
18841
- onAddTier: () => runMutation(active.sectionId, addPricingTier),
18974
+ onAddTier: () => {
18975
+ const newIndex = pricingCardCount(activeEntry.tree);
18976
+ void runMutation(active.sectionId, addPricingTier).then((applied) => {
18977
+ if (applied) setActive({ sectionId: active.sectionId, index: newIndex });
18978
+ });
18979
+ },
18842
18980
  onRemoveTier: () => {
18843
18981
  void runMutation(active.sectionId, (tree) => removePricingTier(tree, active.index)).then(
18844
18982
  (applied) => {
@@ -30251,9 +30389,10 @@ function OhhwellsBridge() {
30251
30389
  if (e.data?.type !== "ow:collect-section") return;
30252
30390
  const sectionId = e.data.sectionId;
30253
30391
  if (typeof sectionId !== "string" || !sectionId) return;
30254
- const sectionEl = document.querySelector(
30392
+ const foundEl = document.querySelector(
30255
30393
  `[data-ohw-section="${CSS.escape(sectionId)}"]`
30256
30394
  );
30395
+ 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;
30257
30396
  const nodes = sectionEl ? collectEditableNodes(void 0, sectionEl).filter(
30258
30397
  (n) => n.key && !n.key.startsWith("__ohw_") && !["meta", "sections", "video-setting"].includes(n.type)
30259
30398
  ).map((n) => ({ ...n, text: n.text ?? "", type: normalizeAiNodeType(n.type) })) : [];
@@ -30992,7 +31131,7 @@ function OhhwellsBridge() {
30992
31131
  postToParent2({
30993
31132
  type: "ow:ready",
30994
31133
  version: "1",
30995
- bridgeVersion: "0.1.139",
31134
+ bridgeVersion: "0.1.141",
30996
31135
  path: pathname,
30997
31136
  nodes: collectEditableNodes(editContentRef.current),
30998
31137
  sections
@@ -32207,6 +32346,7 @@ export {
32207
32346
  dropIndicatorVariants,
32208
32347
  ensureFooterTree,
32209
32348
  filterAvailablePages,
32349
+ foldAlignIntoTrees,
32210
32350
  getEditModeInitialState,
32211
32351
  insertFooterHours,
32212
32352
  isEditSessionActive,
@@ -32215,6 +32355,7 @@ export {
32215
32355
  isValidUrl,
32216
32356
  nextViableSlide,
32217
32357
  parseAiFooterState,
32358
+ parseAiSectionsState,
32218
32359
  parseTarget,
32219
32360
  removeFooterBlock,
32220
32361
  resolveFooterCopyright,