@ohhwells/bridge 0.1.113-next.294 → 0.1.113-next.296
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 +197 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -19
- package/dist/index.d.ts +17 -19
- package/dist/index.js +197 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -105,6 +105,10 @@ function enforceLinkHrefs() {
|
|
|
105
105
|
|
|
106
106
|
// src/lib/ai-tree.ts
|
|
107
107
|
var AI_TREE_SCHEMA_VERSIONS = [1];
|
|
108
|
+
var BUTTON_FILL_TOKENS = ["dark", "primary", "accent", "light"];
|
|
109
|
+
var BUTTON_STYLES = ["solid", "outline", "ghost"];
|
|
110
|
+
var BUTTON_RADII = ["square", "rounded", "pill"];
|
|
111
|
+
var BUTTON_SIZES = ["s", "m", "l"];
|
|
108
112
|
var AI_DEFAULT_BRAND = {
|
|
109
113
|
palette: { dark: "#0C0A09", primary: "#0078E5", accent: "#747271", light: "#ECECEB" },
|
|
110
114
|
fonts: {
|
|
@@ -362,6 +366,59 @@ var FONT_VARS = {
|
|
|
362
366
|
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
363
367
|
var CUSTOM_FONT_STYLE_ID = "ohw-brand-custom-fonts";
|
|
364
368
|
var CUSTOM_FONT_FORMATS = /* @__PURE__ */ new Set(["woff2", "woff", "truetype", "opentype"]);
|
|
369
|
+
var BUTTON_FILL_VAR = {
|
|
370
|
+
dark: "var(--brand-text)",
|
|
371
|
+
primary: "var(--brand-primary)",
|
|
372
|
+
accent: "var(--brand-accent)",
|
|
373
|
+
light: "var(--brand-background)"
|
|
374
|
+
};
|
|
375
|
+
var BUTTON_RADIUS_PX = {
|
|
376
|
+
square: 0,
|
|
377
|
+
rounded: AI_TREE_TOKENS.radiusButton,
|
|
378
|
+
pill: 999
|
|
379
|
+
};
|
|
380
|
+
var BUTTON_SIZE_SPEC = {
|
|
381
|
+
s: {
|
|
382
|
+
paddingX: `${AI_TREE_TOKENS.spacing4}px`,
|
|
383
|
+
paddingY: `${AI_TREE_TOKENS.spacing2}px`,
|
|
384
|
+
fontSize: "14px"
|
|
385
|
+
},
|
|
386
|
+
m: {
|
|
387
|
+
paddingX: `${AI_TREE_TOKENS.spacing6}px`,
|
|
388
|
+
paddingY: `${AI_TREE_TOKENS.spacing3}px`,
|
|
389
|
+
fontSize: `${AI_TREE_TOKENS.type.button.size}px`
|
|
390
|
+
},
|
|
391
|
+
l: {
|
|
392
|
+
paddingX: `${AI_TREE_TOKENS.spacing8}px`,
|
|
393
|
+
paddingY: `${AI_TREE_TOKENS.spacing4}px`,
|
|
394
|
+
fontSize: "18px"
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var BUTTON_VAR_ROLES = ["bg", "text", "border", "radius", "padding-x", "padding-y", "font-size"];
|
|
398
|
+
var BUTTON_VAR_NAMES = ["primary", "secondary"].flatMap(
|
|
399
|
+
(variant) => BUTTON_VAR_ROLES.map((role) => `--brand-button-${variant}-${role}`)
|
|
400
|
+
);
|
|
401
|
+
function buttonVariantVars(variant, style) {
|
|
402
|
+
const fill = BUTTON_FILL_VAR[style.fill];
|
|
403
|
+
const text = BUTTON_FILL_VAR[style.textColor];
|
|
404
|
+
const size = BUTTON_SIZE_SPEC[style.size];
|
|
405
|
+
const { bg, border } = style.style === "outline" ? { bg: "transparent", border: fill } : style.style === "ghost" ? { bg: "transparent", border: "transparent" } : { bg: fill, border: "transparent" };
|
|
406
|
+
return {
|
|
407
|
+
[`--brand-button-${variant}-bg`]: bg,
|
|
408
|
+
[`--brand-button-${variant}-text`]: text,
|
|
409
|
+
[`--brand-button-${variant}-border`]: border,
|
|
410
|
+
[`--brand-button-${variant}-radius`]: `${BUTTON_RADIUS_PX[style.radius]}px`,
|
|
411
|
+
[`--brand-button-${variant}-padding-x`]: size.paddingX,
|
|
412
|
+
[`--brand-button-${variant}-padding-y`]: size.paddingY,
|
|
413
|
+
[`--brand-button-${variant}-font-size`]: size.fontSize
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function buttonStyleVars(buttons) {
|
|
417
|
+
return {
|
|
418
|
+
...buttonVariantVars("primary", buttons.primary),
|
|
419
|
+
...buttonVariantVars("secondary", buttons.secondary)
|
|
420
|
+
};
|
|
421
|
+
}
|
|
365
422
|
function brandColorVars(palette) {
|
|
366
423
|
const { dark, primary, accent, light } = palette;
|
|
367
424
|
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
@@ -389,6 +446,11 @@ function brandColorVars(palette) {
|
|
|
389
446
|
"--brand-on-primary": light
|
|
390
447
|
};
|
|
391
448
|
}
|
|
449
|
+
function isButtonStyle(value) {
|
|
450
|
+
if (!value || typeof value !== "object") return false;
|
|
451
|
+
const v = value;
|
|
452
|
+
return BUTTON_FILL_TOKENS.includes(v.fill) && BUTTON_FILL_TOKENS.includes(v.textColor) && BUTTON_STYLES.includes(v.style) && BUTTON_RADII.includes(v.radius) && BUTTON_SIZES.includes(v.size);
|
|
453
|
+
}
|
|
392
454
|
function parseCustomFontWeight(raw) {
|
|
393
455
|
if (typeof raw !== "object" || raw === null) return null;
|
|
394
456
|
const w = raw;
|
|
@@ -417,11 +479,14 @@ function parseBrandKit(raw) {
|
|
|
417
479
|
const palette = p && typeof p.dark === "string" && typeof p.primary === "string" && typeof p.accent === "string" && typeof p.light === "string" ? { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light } : void 0;
|
|
418
480
|
const fonts = f && typeof f.heading === "string" && typeof f.body === "string" ? { heading: f.heading, body: f.body } : void 0;
|
|
419
481
|
const customFonts = Array.isArray(parsed?.customFonts) ? parsed.customFonts.map(parseCustomFont).filter((c) => c !== null) : void 0;
|
|
420
|
-
|
|
482
|
+
const b = parsed?.buttons;
|
|
483
|
+
const buttons = b && isButtonStyle(b.primary) && isButtonStyle(b.secondary) ? { primary: b.primary, secondary: b.secondary } : void 0;
|
|
484
|
+
if (!palette && !fonts && !customFonts && !buttons) return null;
|
|
421
485
|
return {
|
|
422
486
|
...palette ? { palette } : {},
|
|
423
487
|
...fonts ? { fonts } : {},
|
|
424
|
-
...customFonts ? { customFonts } : {}
|
|
488
|
+
...customFonts ? { customFonts } : {},
|
|
489
|
+
...buttons ? { buttons } : {}
|
|
425
490
|
};
|
|
426
491
|
} catch {
|
|
427
492
|
return null;
|
|
@@ -475,7 +540,9 @@ function loadCustomFonts(fonts) {
|
|
|
475
540
|
function applyBrandToDom(kit) {
|
|
476
541
|
const root = document.documentElement;
|
|
477
542
|
if (!kit) {
|
|
478
|
-
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES])
|
|
543
|
+
for (const name of [...BRAND_VAR_NAMES, ...LEGACY_BRAND_VAR_NAMES, ...BUTTON_VAR_NAMES]) {
|
|
544
|
+
root.style.removeProperty(name);
|
|
545
|
+
}
|
|
479
546
|
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
480
547
|
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
481
548
|
document.getElementById(CUSTOM_FONT_STYLE_ID)?.remove();
|
|
@@ -484,6 +551,9 @@ function applyBrandToDom(kit) {
|
|
|
484
551
|
if (kit.palette) {
|
|
485
552
|
for (const [name, value] of Object.entries(brandColorVars(kit.palette))) root.style.setProperty(name, value);
|
|
486
553
|
}
|
|
554
|
+
if (kit.buttons) {
|
|
555
|
+
for (const [name, value] of Object.entries(buttonStyleVars(kit.buttons))) root.style.setProperty(name, value);
|
|
556
|
+
}
|
|
487
557
|
if (kit.customFonts) {
|
|
488
558
|
loadCustomFonts(kit.customFonts);
|
|
489
559
|
}
|
|
@@ -612,7 +682,6 @@ var NODE_PROPS = [
|
|
|
612
682
|
"color",
|
|
613
683
|
"font-family",
|
|
614
684
|
"font-size",
|
|
615
|
-
"background",
|
|
616
685
|
"text-align",
|
|
617
686
|
"justify-content",
|
|
618
687
|
"align-items"
|
|
@@ -662,9 +731,6 @@ function clearNodeProps(root) {
|
|
|
662
731
|
h.removeAttribute(NODE_WROTE_ATTR);
|
|
663
732
|
}
|
|
664
733
|
}
|
|
665
|
-
function buttonSurfaceOf(el) {
|
|
666
|
-
return el.closest("a, button") ?? el;
|
|
667
|
-
}
|
|
668
734
|
function alignSubjectOf(el) {
|
|
669
735
|
const button = el.closest('[data-ohw-role="button"]');
|
|
670
736
|
if (button?.parentElement) return button.parentElement;
|
|
@@ -780,18 +846,6 @@ function applyStylesToDom(store) {
|
|
|
780
846
|
);
|
|
781
847
|
subject.setAttribute(NODE_WROTE_ATTR, "");
|
|
782
848
|
}
|
|
783
|
-
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
784
|
-
const surface = buttonSurfaceOf(el);
|
|
785
|
-
if (override.buttonBackground !== void 0) {
|
|
786
|
-
saveInline(surface, "background");
|
|
787
|
-
surface.style.setProperty("background", override.buttonBackground, "important");
|
|
788
|
-
}
|
|
789
|
-
if (override.buttonText !== void 0) {
|
|
790
|
-
saveInline(surface, "color");
|
|
791
|
-
surface.style.setProperty("color", override.buttonText, "important");
|
|
792
|
-
}
|
|
793
|
-
surface.setAttribute(NODE_WROTE_ATTR, "");
|
|
794
|
-
}
|
|
795
849
|
}
|
|
796
850
|
}
|
|
797
851
|
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
@@ -1386,7 +1440,59 @@ var FEATURE_LINE_CSS = [
|
|
|
1386
1440
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
1387
1441
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
1388
1442
|
].join("");
|
|
1389
|
-
function
|
|
1443
|
+
function buttonSizeSpec(size) {
|
|
1444
|
+
switch (size) {
|
|
1445
|
+
case "s":
|
|
1446
|
+
return { padding: `${AI_TREE_TOKENS.spacing2}px ${AI_TREE_TOKENS.spacing4}px`, fontSize: 14 };
|
|
1447
|
+
case "l":
|
|
1448
|
+
return { padding: `${AI_TREE_TOKENS.spacing4}px ${AI_TREE_TOKENS.spacing8}px`, fontSize: 18 };
|
|
1449
|
+
case "m":
|
|
1450
|
+
default:
|
|
1451
|
+
return { padding: `${AI_TREE_TOKENS.spacing3}px ${AI_TREE_TOKENS.spacing6}px`, fontSize: AI_TREE_TOKENS.type.button.size };
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
function buttonRadiusPx(radius) {
|
|
1455
|
+
switch (radius) {
|
|
1456
|
+
case "square":
|
|
1457
|
+
return 0;
|
|
1458
|
+
case "pill":
|
|
1459
|
+
return 999;
|
|
1460
|
+
case "rounded":
|
|
1461
|
+
default:
|
|
1462
|
+
return AI_TREE_TOKENS.radiusButton;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
function resolveButtonToken(brand, token) {
|
|
1466
|
+
return brand.palette[token];
|
|
1467
|
+
}
|
|
1468
|
+
function buttonColorStyle(ctx, variant) {
|
|
1469
|
+
const token = ctx.brand.buttons?.[variant];
|
|
1470
|
+
if (!token) return null;
|
|
1471
|
+
const fill = resolveButtonToken(ctx.brand, token.fill);
|
|
1472
|
+
const text = resolveButtonToken(ctx.brand, token.textColor);
|
|
1473
|
+
switch (token.style) {
|
|
1474
|
+
case "outline":
|
|
1475
|
+
return { background: "transparent", border: `1px solid ${fill}`, color: text };
|
|
1476
|
+
case "ghost":
|
|
1477
|
+
return { background: "transparent", border: "1px solid transparent", color: text };
|
|
1478
|
+
case "solid":
|
|
1479
|
+
default:
|
|
1480
|
+
return { background: fill, color: text };
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
function buttonShellStyle(ctx, variant, fullWidth) {
|
|
1484
|
+
const buttonToken = ctx.brand.buttons?.[variant];
|
|
1485
|
+
if (buttonToken) {
|
|
1486
|
+
const { padding, fontSize } = buttonSizeSpec(buttonToken.size);
|
|
1487
|
+
return {
|
|
1488
|
+
borderRadius: buttonRadiusPx(buttonToken.radius),
|
|
1489
|
+
padding,
|
|
1490
|
+
fontFamily: ctx.brand.fonts.body,
|
|
1491
|
+
fontSize,
|
|
1492
|
+
lineHeight: AI_TREE_TOKENS.type.button.line,
|
|
1493
|
+
fontWeight: AI_TREE_TOKENS.type.button.weight
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1390
1496
|
const bs = ctx.buttonStyle;
|
|
1391
1497
|
if (bs) {
|
|
1392
1498
|
return {
|
|
@@ -1534,6 +1640,8 @@ function ButtonEl({
|
|
|
1534
1640
|
fullWidth
|
|
1535
1641
|
}) {
|
|
1536
1642
|
const secondary = slots.variant === "secondary";
|
|
1643
|
+
const variant = secondary ? "secondary" : "primary";
|
|
1644
|
+
const tokenColorStyle = buttonColorStyle(ctx, variant);
|
|
1537
1645
|
const href = str(slots.href);
|
|
1538
1646
|
const linkAttrs = ctx.keyFor && path ? { "data-ohw-href-key": ctx.keyFor(`${path}.href`), "data-ohw-role": "button" } : {};
|
|
1539
1647
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1548,13 +1656,13 @@ function ButtonEl({
|
|
|
1548
1656
|
justifyContent: "center",
|
|
1549
1657
|
textDecoration: "none",
|
|
1550
1658
|
cursor: "pointer",
|
|
1551
|
-
...buttonShellStyle(ctx, fullWidth),
|
|
1552
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1659
|
+
...buttonShellStyle(ctx, variant, fullWidth),
|
|
1660
|
+
...tokenColorStyle ?? (secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : (
|
|
1553
1661
|
// Off-band, prefer the template button's measured fill/label pair — a template may
|
|
1554
1662
|
// fill its CTAs with any token (hvac: accent bg, primary text). On an accent band
|
|
1555
1663
|
// the flipped palette keeps contrast, so the brand-driven colours stay.
|
|
1556
1664
|
!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand) }
|
|
1557
|
-
)
|
|
1665
|
+
))
|
|
1558
1666
|
},
|
|
1559
1667
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
1560
1668
|
}
|
|
@@ -2625,13 +2733,13 @@ function renderNode(node, ctx, path) {
|
|
|
2625
2733
|
border: "none",
|
|
2626
2734
|
cursor: "pointer",
|
|
2627
2735
|
// Shape/padding/typography follow the host template's own buttons.
|
|
2628
|
-
...buttonShellStyle(ctx),
|
|
2736
|
+
...buttonShellStyle(ctx, "primary"),
|
|
2629
2737
|
// Brand-styled: the template button's measured fill/label pair off-band, else
|
|
2630
2738
|
// primary fill with a brand-derived label so it reads on custom palettes.
|
|
2631
|
-
|
|
2739
|
+
...buttonColorStyle(ctx, "primary") ?? (!ctx.buttonLabel && ctx.buttonStyle?.background ? { background: ctx.buttonStyle.background, color: ctx.buttonStyle.color } : {
|
|
2632
2740
|
background: ctx.brand.palette.primary,
|
|
2633
2741
|
color: ctx.buttonLabel ?? primaryButtonLabel(ctx.brand)
|
|
2634
|
-
}
|
|
2742
|
+
})
|
|
2635
2743
|
},
|
|
2636
2744
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...textAttrs(ctx, `${path}.c${i}.label`), children: str(cs.label) })
|
|
2637
2745
|
},
|
|
@@ -8992,6 +9100,7 @@ function MediaOverlay({
|
|
|
8992
9100
|
fadingOut = false,
|
|
8993
9101
|
selected = false,
|
|
8994
9102
|
hovered = false,
|
|
9103
|
+
cueOnly = false,
|
|
8995
9104
|
onFadeOutComplete,
|
|
8996
9105
|
onReplace,
|
|
8997
9106
|
onSelect,
|
|
@@ -9000,7 +9109,7 @@ function MediaOverlay({
|
|
|
9000
9109
|
const { rect } = hover;
|
|
9001
9110
|
const skeletonRef = React8.useRef(null);
|
|
9002
9111
|
const isVideo = hover.elementType === "video";
|
|
9003
|
-
const showChrome = !selected || hovered;
|
|
9112
|
+
const showChrome = (!selected || hovered) && !cueOnly;
|
|
9004
9113
|
const autoplay = hover.videoAutoplay ?? true;
|
|
9005
9114
|
const muted = hover.videoMuted ?? true;
|
|
9006
9115
|
const probeRef = React8.useRef(null);
|
|
@@ -9117,7 +9226,7 @@ function MediaOverlay({
|
|
|
9117
9226
|
// parent this needed a whole `ow:click-at` round-trip to re-hit-test inside the iframe;
|
|
9118
9227
|
// in-document, pointer-events does it natively. The button below opts back in, so
|
|
9119
9228
|
// Replace still works.
|
|
9120
|
-
pointerEvents: hover.hasTextOverlap ? "none" : "auto",
|
|
9229
|
+
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
9121
9230
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
9122
9231
|
// than hovered. Hover keeps the existing tinted preview.
|
|
9123
9232
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -9168,7 +9277,7 @@ function MediaOverlay({
|
|
|
9168
9277
|
justifyContent: "center"
|
|
9169
9278
|
} : null,
|
|
9170
9279
|
// Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
|
|
9171
|
-
pointerEvents: hover.hasTextOverlap ? "none" : "auto"
|
|
9280
|
+
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto"
|
|
9172
9281
|
},
|
|
9173
9282
|
onMouseDown: (e) => e.preventDefault(),
|
|
9174
9283
|
onClick: (e) => {
|
|
@@ -9198,7 +9307,8 @@ var OVERLAY_BUTTON_STYLE2 = {
|
|
|
9198
9307
|
};
|
|
9199
9308
|
function CarouselOverlay({
|
|
9200
9309
|
hover,
|
|
9201
|
-
onEdit
|
|
9310
|
+
onEdit,
|
|
9311
|
+
cueOnly = false
|
|
9202
9312
|
}) {
|
|
9203
9313
|
const { rect } = hover;
|
|
9204
9314
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
@@ -9214,12 +9324,12 @@ function CarouselOverlay({
|
|
|
9214
9324
|
width: rect.width,
|
|
9215
9325
|
height: rect.height,
|
|
9216
9326
|
zIndex: 2147483646,
|
|
9217
|
-
pointerEvents: "auto",
|
|
9327
|
+
pointerEvents: cueOnly ? "none" : "auto",
|
|
9218
9328
|
boxShadow: "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
9219
9329
|
background: "color-mix(in srgb, var(--color-bridge-primary) 20%, transparent)"
|
|
9220
9330
|
},
|
|
9221
9331
|
onClick: () => onEdit(hover.key),
|
|
9222
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
9332
|
+
children: cueOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
9223
9333
|
Button,
|
|
9224
9334
|
{
|
|
9225
9335
|
"data-ohw-carousel-overlay": "",
|
|
@@ -9410,7 +9520,8 @@ function ReviewButton({
|
|
|
9410
9520
|
}
|
|
9411
9521
|
function AiSectionOverlay({
|
|
9412
9522
|
postToParent: postToParent2,
|
|
9413
|
-
apiRef
|
|
9523
|
+
apiRef,
|
|
9524
|
+
onSelectionChange
|
|
9414
9525
|
}) {
|
|
9415
9526
|
const [selectedId, setSelectedId] = (0, import_react8.useState)(null);
|
|
9416
9527
|
const [reviewId, setReviewId] = (0, import_react8.useState)(null);
|
|
@@ -9419,6 +9530,9 @@ function AiSectionOverlay({
|
|
|
9419
9530
|
reviewIdRef.current = reviewId;
|
|
9420
9531
|
const selectedIdRef = (0, import_react8.useRef)(null);
|
|
9421
9532
|
selectedIdRef.current = selectedId;
|
|
9533
|
+
(0, import_react8.useEffect)(() => {
|
|
9534
|
+
onSelectionChange?.(selectedId);
|
|
9535
|
+
}, [selectedId, onSelectionChange]);
|
|
9422
9536
|
const report = (0, import_react8.useCallback)(
|
|
9423
9537
|
(el) => {
|
|
9424
9538
|
const labelSrc = el ? sectionElementOf(el) : null;
|
|
@@ -16524,6 +16638,19 @@ function isMediaEditable(el) {
|
|
|
16524
16638
|
const t = el.dataset.ohwEditable;
|
|
16525
16639
|
return t === "image" || t === "bg-image" || t === "video";
|
|
16526
16640
|
}
|
|
16641
|
+
var FULL_BLEED_MIN_COVERAGE = 0.98;
|
|
16642
|
+
function fullBleedSectionIdOf(media) {
|
|
16643
|
+
const section = media.closest("[data-ohw-section]");
|
|
16644
|
+
if (!section) return null;
|
|
16645
|
+
const s = section.getBoundingClientRect();
|
|
16646
|
+
if (s.width <= 0 || s.height <= 0) return null;
|
|
16647
|
+
const m = media.getBoundingClientRect();
|
|
16648
|
+
const overlapX = Math.min(m.right, s.right) - Math.max(m.left, s.left);
|
|
16649
|
+
const overlapY = Math.min(m.bottom, s.bottom) - Math.max(m.top, s.top);
|
|
16650
|
+
if (overlapX <= 0 || overlapY <= 0) return null;
|
|
16651
|
+
if (overlapX * overlapY / (s.width * s.height) < FULL_BLEED_MIN_COVERAGE) return null;
|
|
16652
|
+
return instanceIdOf(movableUnit(section)) || null;
|
|
16653
|
+
}
|
|
16527
16654
|
function isIconMarkupValue(value) {
|
|
16528
16655
|
return /^\s*<(svg|img)\b/i.test(value);
|
|
16529
16656
|
}
|
|
@@ -17734,6 +17861,12 @@ function OhhwellsBridge() {
|
|
|
17734
17861
|
const hoveredImageHasTextOverlapRef = (0, import_react17.useRef)(false);
|
|
17735
17862
|
const dragOverElRef = (0, import_react17.useRef)(null);
|
|
17736
17863
|
const [mediaHover, setMediaHover] = (0, import_react17.useState)(null);
|
|
17864
|
+
const [selectedAiSectionId, setSelectedAiSectionId] = (0, import_react17.useState)(null);
|
|
17865
|
+
const selectedAiSectionIdRef = (0, import_react17.useRef)(null);
|
|
17866
|
+
const handleAiSectionSelectionChange = (0, import_react17.useCallback)((id) => {
|
|
17867
|
+
selectedAiSectionIdRef.current = id;
|
|
17868
|
+
setSelectedAiSectionId(id);
|
|
17869
|
+
}, []);
|
|
17737
17870
|
const [selectedMedia, setSelectedMedia] = (0, import_react17.useState)(null);
|
|
17738
17871
|
const selectedMediaElRef = (0, import_react17.useRef)(null);
|
|
17739
17872
|
const clearMediaSelection = (0, import_react17.useCallback)(() => {
|
|
@@ -20373,6 +20506,14 @@ function OhhwellsBridge() {
|
|
|
20373
20506
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
20374
20507
|
e.preventDefault();
|
|
20375
20508
|
e.stopPropagation();
|
|
20509
|
+
const fullBleedSectionId = fullBleedSectionIdOf(editable);
|
|
20510
|
+
if (fullBleedSectionId && fullBleedSectionId !== selectedAiSectionIdRef.current) {
|
|
20511
|
+
clearMediaSelectionRef.current();
|
|
20512
|
+
deselectRef.current();
|
|
20513
|
+
deactivateRef.current();
|
|
20514
|
+
aiSectionApiRef.current?.selectFromElement(editable);
|
|
20515
|
+
return;
|
|
20516
|
+
}
|
|
20376
20517
|
if (selectedMediaElRef.current === editable) {
|
|
20377
20518
|
postToParentRef.current({ type: "ow:image-pick", key: editable.dataset.ohwKey ?? "", elementType: editable.dataset.ohwEditable ?? "image" });
|
|
20378
20519
|
} else {
|
|
@@ -20824,6 +20965,7 @@ function OhhwellsBridge() {
|
|
|
20824
20965
|
elementType: imgEl.dataset.ohwEditable ?? "image",
|
|
20825
20966
|
hasTextOverlap,
|
|
20826
20967
|
isDragOver,
|
|
20968
|
+
fullBleedSectionId: fullBleedSectionIdOf(imgEl),
|
|
20827
20969
|
...video ? { videoAutoplay: video.autoplay, videoMuted: video.muted } : {}
|
|
20828
20970
|
});
|
|
20829
20971
|
const track = imgEl.closest("[data-ohw-hover-pause]");
|
|
@@ -22688,7 +22830,11 @@ function OhhwellsBridge() {
|
|
|
22688
22830
|
if (!key) return;
|
|
22689
22831
|
const r2 = getVisibleRect(container);
|
|
22690
22832
|
setCarouselHover(
|
|
22691
|
-
(prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : {
|
|
22833
|
+
(prev) => prev && prev.key === key && prev.rect.top === r2.top && prev.rect.left === r2.left && prev.rect.width === r2.width && prev.rect.height === r2.height ? prev : {
|
|
22834
|
+
key,
|
|
22835
|
+
rect: { top: r2.top, left: r2.left, width: r2.width, height: r2.height },
|
|
22836
|
+
fullBleedSectionId: fullBleedSectionIdOf(container)
|
|
22837
|
+
}
|
|
22692
22838
|
);
|
|
22693
22839
|
};
|
|
22694
22840
|
const applyToolbarPos = (rect) => {
|
|
@@ -23617,7 +23763,14 @@ function OhhwellsBridge() {
|
|
|
23617
23763
|
bridgeRoot ? (0, import_react_dom5.createPortal)(
|
|
23618
23764
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
23619
23765
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
23620
|
-
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
23766
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
23767
|
+
AiSectionOverlay,
|
|
23768
|
+
{
|
|
23769
|
+
postToParent: postToParent2,
|
|
23770
|
+
apiRef: aiSectionApiRef,
|
|
23771
|
+
onSelectionChange: handleAiSectionSelectionChange
|
|
23772
|
+
}
|
|
23773
|
+
),
|
|
23621
23774
|
isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
23622
23775
|
"div",
|
|
23623
23776
|
{
|
|
@@ -23650,6 +23803,7 @@ function OhhwellsBridge() {
|
|
|
23650
23803
|
{
|
|
23651
23804
|
hover: mediaHover,
|
|
23652
23805
|
isUploading: false,
|
|
23806
|
+
cueOnly: !mediaHover.isDragOver && !!mediaHover.fullBleedSectionId && mediaHover.fullBleedSectionId !== selectedAiSectionId,
|
|
23653
23807
|
onReplace: handleMediaReplace,
|
|
23654
23808
|
onSelect: handleMediaSelect,
|
|
23655
23809
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
@@ -23667,7 +23821,14 @@ function OhhwellsBridge() {
|
|
|
23667
23821
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
23668
23822
|
}
|
|
23669
23823
|
),
|
|
23670
|
-
carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
23824
|
+
carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
23825
|
+
CarouselOverlay,
|
|
23826
|
+
{
|
|
23827
|
+
hover: carouselHover,
|
|
23828
|
+
onEdit: handleEditCarousel,
|
|
23829
|
+
cueOnly: !!carouselHover.fullBleedSectionId && carouselHover.fullBleedSectionId !== selectedAiSectionId
|
|
23830
|
+
}
|
|
23831
|
+
),
|
|
23671
23832
|
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
23672
23833
|
siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
23673
23834
|
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|