@ohhwells/bridge 0.1.132 → 0.1.134-next.362
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 +318 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +318 -93
- package/dist/index.js.map +1 -1
- package/dist/pages.cjs +1 -1
- package/dist/pages.cjs.map +1 -1
- package/dist/pages.js +1 -1
- package/dist/pages.js.map +1 -1
- package/dist/styles.css +43 -0
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -2656,6 +2656,19 @@ function quotedFont(font) {
|
|
|
2656
2656
|
const cleaned = font.replace(/["']/g, "").trim();
|
|
2657
2657
|
return cleaned ? `"${cleaned}"` : "sans-serif";
|
|
2658
2658
|
}
|
|
2659
|
+
function themeFont(role, fallback) {
|
|
2660
|
+
const quoted = quotedFont(fallback);
|
|
2661
|
+
return role === "heading" ? `var(--brand-font-heading, var(--font-heading, var(--font-display, ${quoted})))` : `var(--brand-font-body, var(--font-body, ${quoted}))`;
|
|
2662
|
+
}
|
|
2663
|
+
function withThemeFonts(brand) {
|
|
2664
|
+
return {
|
|
2665
|
+
...brand,
|
|
2666
|
+
fonts: {
|
|
2667
|
+
heading: themeFont("heading", brand.fonts.heading),
|
|
2668
|
+
body: themeFont("body", brand.fonts.body)
|
|
2669
|
+
}
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2659
2672
|
function footerLogoStyle(fallbackFont, fallbackColor) {
|
|
2660
2673
|
return {
|
|
2661
2674
|
fontFamily: `var(--brand-font-heading, var(--font-heading, var(--font-display, ${quotedFont(fallbackFont)})))`,
|
|
@@ -2727,7 +2740,7 @@ var AI_MOBILE_CSS = [
|
|
|
2727
2740
|
// page's first section. Top only (bottom needs no nav clearance); ~96px approximates the
|
|
2728
2741
|
// template nav's own height (measured ~94px) — there's no shared `--ohw-header-h` var to read
|
|
2729
2742
|
// an exact figure from (no live measurement exists), so this is a safe approximation, not a
|
|
2730
|
-
// pixel-exact fit. Horizontal spacing already comes from `data-ai-
|
|
2743
|
+
// pixel-exact fit. Horizontal spacing already comes from `data-ai-section-inner`.
|
|
2731
2744
|
'[data-ai-overlay-clearance] [data-ai-overlap-layer="overlay"]{padding-top:96px}',
|
|
2732
2745
|
// A full-bleed carousel's height is pure arithmetic: it spans the whole window, so 16/9 turns
|
|
2733
2746
|
// window width straight into height. Measured at 16/9 it came out ~90% of the viewport at EVERY
|
|
@@ -2743,8 +2756,10 @@ var AI_MOBILE_CSS = [
|
|
|
2743
2756
|
"[data-ai-section]{overflow-x:hidden}",
|
|
2744
2757
|
// `:not([data-ai-full-bleed])`: this `!important` gutter beat the inline `padding: 0` that a
|
|
2745
2758
|
// full-bleed section's container sets, so a carousel/media hero that is edge-to-edge on desktop
|
|
2746
|
-
// still got a 20px band of section background down both sides on a phone.
|
|
2747
|
-
|
|
2759
|
+
// still got a 20px band of section background down both sides on a phone. The footer's own
|
|
2760
|
+
// container keeps the unguarded rule below — `data-ai-full-bleed` can never appear on it.
|
|
2761
|
+
"[data-ai-section-inner]:not([data-ai-full-bleed]){padding:0 20px !important}",
|
|
2762
|
+
"[data-ai-container]{padding:0 20px !important}",
|
|
2748
2763
|
"[data-ai-row]{display:flex !important;flex-direction:column !important;align-items:stretch !important}",
|
|
2749
2764
|
"[data-ai-cell]{width:100%;min-width:0}",
|
|
2750
2765
|
// The rule above turns every row into a COLUMN flex container on phones, which silently breaks
|
|
@@ -2945,6 +2960,31 @@ function pricingCardEmphasis(featured, ctx, hasBg) {
|
|
|
2945
2960
|
function textAttrs(ctx, path) {
|
|
2946
2961
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
2947
2962
|
}
|
|
2963
|
+
var AI_RESPONSIVE_CSS = [
|
|
2964
|
+
"@media (max-width: 960px) {",
|
|
2965
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
|
|
2966
|
+
' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
|
|
2967
|
+
"}",
|
|
2968
|
+
"@media (max-width: 640px) {",
|
|
2969
|
+
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
2970
|
+
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
2971
|
+
// Group containers flatten to a column on phones; span placements come along for free.
|
|
2972
|
+
// `:not([data-ai-group="overlap"])` for the same reason as the twin pair in AI_MOBILE_CSS — see
|
|
2973
|
+
// the comment there. This sheet's copy is the narrower selector, so without the exemption it
|
|
2974
|
+
// flattens an `overlap` hero below 640px even though the other rule stands down: measured a 390px
|
|
2975
|
+
// viewport with the heading/CTA in flow *under* the image, 219px of section background where the
|
|
2976
|
+
// layered text used to be.
|
|
2977
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) { display: flex !important; flex-direction: column !important; }',
|
|
2978
|
+
' [data-ai-responsive] [data-ai-group]:not([data-ai-group="overlap"]) > * { grid-column: auto !important; }',
|
|
2979
|
+
// `:not([data-ai-full-bleed])` for the same reason as the twin rule in AI_MOBILE_CSS: this one
|
|
2980
|
+
// is narrower (0,2,0 vs 0,1,0) and also `!important`, so without the guard it wins outright and
|
|
2981
|
+
// a full-bleed hero gets its 20px side band back below 640px only — the one width where the
|
|
2982
|
+
// other rule had already been taught to stand down.
|
|
2983
|
+
" [data-ai-responsive] [data-ai-section-inner]:not([data-ai-full-bleed]) { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
2984
|
+
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
2985
|
+
" [data-ai-responsive] img { max-width: 100%; }",
|
|
2986
|
+
"}"
|
|
2987
|
+
].join("\n");
|
|
2948
2988
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
2949
2989
|
function MediaBox({
|
|
2950
2990
|
refValue,
|
|
@@ -2965,9 +3005,9 @@ function MediaBox({
|
|
|
2965
3005
|
const url = refValue ? ctx.resolveMedia(refValue) : null;
|
|
2966
3006
|
const isIcon = /^(lucide|simple):/.test(refValue);
|
|
2967
3007
|
const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
|
|
2968
|
-
const editAttrs = ctx.keyFor && editPath
|
|
3008
|
+
const editAttrs = ctx.keyFor && editPath ? {
|
|
2969
3009
|
"data-ohw-key": ctx.keyFor(editPath),
|
|
2970
|
-
...genericImageEdit ? { "data-ohw-editable": "image" } : {}
|
|
3010
|
+
...isIcon ? { "data-ohw-editable": "icon" } : genericImageEdit ? { "data-ohw-editable": "image" } : {}
|
|
2971
3011
|
} : {};
|
|
2972
3012
|
if (isIcon) {
|
|
2973
3013
|
const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
|
|
@@ -2975,6 +3015,7 @@ function MediaBox({
|
|
|
2975
3015
|
"span",
|
|
2976
3016
|
{
|
|
2977
3017
|
"data-ai-icon": refValue,
|
|
3018
|
+
...editAttrs,
|
|
2978
3019
|
style: {
|
|
2979
3020
|
display: "inline-flex",
|
|
2980
3021
|
width: 48,
|
|
@@ -4159,18 +4200,25 @@ function FadeSlideshow({ node, ctx, path }) {
|
|
|
4159
4200
|
(dir) => onInteract(stepViableSlide(index, failed, count, dir, loop)),
|
|
4160
4201
|
[count, failed, index, loop, onInteract]
|
|
4161
4202
|
);
|
|
4203
|
+
const prefetchRef = import_react.default.useRef(prefetch);
|
|
4204
|
+
import_react.default.useEffect(() => {
|
|
4205
|
+
prefetchRef.current = prefetch;
|
|
4206
|
+
});
|
|
4207
|
+
import_react.default.useEffect(() => {
|
|
4208
|
+
if (autoplay) hasInteractedRef.current = false;
|
|
4209
|
+
}, [autoplay]);
|
|
4162
4210
|
import_react.default.useEffect(() => {
|
|
4163
4211
|
if (!autoplay) return;
|
|
4164
4212
|
const id = window.setInterval(() => {
|
|
4165
4213
|
if (hasInteractedRef.current || hoveredRef.current) return;
|
|
4166
4214
|
setIndex((i) => loop ? (i + 1) % count : Math.min(count - 1, i + 1));
|
|
4167
4215
|
}, intervalMs);
|
|
4168
|
-
const warmId = window.setTimeout(() =>
|
|
4216
|
+
const warmId = window.setTimeout(() => prefetchRef.current(1 % count), Math.min(1500, intervalMs / 2));
|
|
4169
4217
|
return () => {
|
|
4170
4218
|
window.clearInterval(id);
|
|
4171
4219
|
window.clearTimeout(warmId);
|
|
4172
4220
|
};
|
|
4173
|
-
}, [autoplay, count, intervalMs, loop
|
|
4221
|
+
}, [autoplay, count, intervalMs, loop]);
|
|
4174
4222
|
const hasMovedRef = import_react.default.useRef(false);
|
|
4175
4223
|
import_react.default.useEffect(() => {
|
|
4176
4224
|
if (!hasMovedRef.current) {
|
|
@@ -4461,7 +4509,7 @@ function CollectionBlock({ node, ctx, path }) {
|
|
|
4461
4509
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
4462
4510
|
"div",
|
|
4463
4511
|
{
|
|
4464
|
-
"data-ai-grid":
|
|
4512
|
+
"data-ai-grid": String(itemsPerRow),
|
|
4465
4513
|
"data-ohw-pricing-collection": isPricing ? "" : void 0,
|
|
4466
4514
|
style: {
|
|
4467
4515
|
display: "grid",
|
|
@@ -4721,7 +4769,7 @@ function renderNode(node, ctx, path, ambientAlign) {
|
|
|
4721
4769
|
},
|
|
4722
4770
|
children: [
|
|
4723
4771
|
i > 0 && ctx.heroOverlapFullBleed ? (
|
|
4724
|
-
// The section's `data-ai-
|
|
4772
|
+
// The section's `data-ai-section-inner` gave up its max-width/gutter so the base
|
|
4725
4773
|
// layer (this group's i===0 sibling) can span edge-to-edge — reintroduced here,
|
|
4726
4774
|
// scoped to just the overlay text, so a heading/copy/CTA stack doesn't stretch
|
|
4727
4775
|
// the full section width instead of reading at the usual content width.
|
|
@@ -5044,7 +5092,7 @@ function AiTreeRenderer({
|
|
|
5044
5092
|
if (!isRenderableTree(tree)) {
|
|
5045
5093
|
return null;
|
|
5046
5094
|
}
|
|
5047
|
-
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
5095
|
+
const resolvedBrand = withThemeFonts(brand ?? AI_DEFAULT_BRAND);
|
|
5048
5096
|
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
5049
5097
|
const blockBrand = band?.brand ?? resolvedBrand;
|
|
5050
5098
|
const placeholderMap = buildPlaceholderMap(tree);
|
|
@@ -5114,6 +5162,7 @@ function AiTreeRenderer({
|
|
|
5114
5162
|
...fillHeight ? { "data-ai-fill-height": "" } : {},
|
|
5115
5163
|
...needsOverlayClearance ? { "data-ai-overlay-clearance": "" } : {},
|
|
5116
5164
|
...bgAttrs,
|
|
5165
|
+
"data-ai-responsive": "",
|
|
5117
5166
|
style: {
|
|
5118
5167
|
position: "relative",
|
|
5119
5168
|
padding: `${padCss} 0`,
|
|
@@ -5127,12 +5176,13 @@ function AiTreeRenderer({
|
|
|
5127
5176
|
...fillHeight ? { display: "grid" } : {}
|
|
5128
5177
|
},
|
|
5129
5178
|
children: [
|
|
5130
|
-
|
|
5179
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
5131
5180
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_MOBILE_CSS }),
|
|
5181
|
+
isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
|
|
5132
5182
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
5133
5183
|
"div",
|
|
5134
5184
|
{
|
|
5135
|
-
"data-ai-
|
|
5185
|
+
"data-ai-section-inner": "",
|
|
5136
5186
|
...fullBleedMedia ? { "data-ai-full-bleed": "" } : {},
|
|
5137
5187
|
style: {
|
|
5138
5188
|
position: "relative",
|
|
@@ -5149,7 +5199,7 @@ function AiTreeRenderer({
|
|
|
5149
5199
|
children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
5150
5200
|
"div",
|
|
5151
5201
|
{
|
|
5152
|
-
"data-ai-
|
|
5202
|
+
"data-ai-columns": "",
|
|
5153
5203
|
style: {
|
|
5154
5204
|
display: "grid",
|
|
5155
5205
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
@@ -5200,7 +5250,7 @@ function AiFooterRenderer({
|
|
|
5200
5250
|
if (!isRenderableFooterTree(tree)) {
|
|
5201
5251
|
return null;
|
|
5202
5252
|
}
|
|
5203
|
-
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
5253
|
+
const resolvedBrand = withThemeFonts(brand ?? AI_DEFAULT_BRAND);
|
|
5204
5254
|
const bandBg = surface?.background ?? resolvedBrand.palette.dark;
|
|
5205
5255
|
const bandText = surface?.text ?? resolvedBrand.palette.light;
|
|
5206
5256
|
const onDark = surface ? isDarkColor(surface.background) : true;
|
|
@@ -5805,9 +5855,10 @@ function applyAiSectionsToDom(state, options) {
|
|
|
5805
5855
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
5806
5856
|
continue;
|
|
5807
5857
|
}
|
|
5808
|
-
const isNewMount = !existing || !existing.container.isConnected;
|
|
5809
5858
|
let container = existing?.container;
|
|
5859
|
+
let isNewMount = false;
|
|
5810
5860
|
if (!container || !container.isConnected) {
|
|
5861
|
+
isNewMount = true;
|
|
5811
5862
|
existing?.root.unmount();
|
|
5812
5863
|
container?.remove();
|
|
5813
5864
|
container = document.createElement("div");
|
|
@@ -9023,7 +9074,7 @@ var isLabelWeight = (label) => label === "number" || label === "weight";
|
|
|
9023
9074
|
var isLabelShadow = (label) => label === "shadow";
|
|
9024
9075
|
var getDefaultConfig = () => {
|
|
9025
9076
|
const themeColor = fromTheme("color");
|
|
9026
|
-
const
|
|
9077
|
+
const themeFont2 = fromTheme("font");
|
|
9027
9078
|
const themeText = fromTheme("text");
|
|
9028
9079
|
const themeFontWeight = fromTheme("font-weight");
|
|
9029
9080
|
const themeTracking = fromTheme("tracking");
|
|
@@ -9945,7 +9996,7 @@ var getDefaultConfig = () => {
|
|
|
9945
9996
|
* @see https://tailwindcss.com/docs/font-family
|
|
9946
9997
|
*/
|
|
9947
9998
|
"font-family": [{
|
|
9948
|
-
font: [isArbitraryVariableFamilyName, isArbitraryFamilyName,
|
|
9999
|
+
font: [isArbitraryVariableFamilyName, isArbitraryFamilyName, themeFont2]
|
|
9949
10000
|
}],
|
|
9950
10001
|
/**
|
|
9951
10002
|
* Font Feature Settings
|
|
@@ -13375,17 +13426,9 @@ var Button = React7.forwardRef(
|
|
|
13375
13426
|
);
|
|
13376
13427
|
Button.displayName = "Button";
|
|
13377
13428
|
|
|
13378
|
-
// src/ui/
|
|
13379
|
-
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
13429
|
+
// src/ui/media-skeleton.ts
|
|
13380
13430
|
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
13381
|
-
var
|
|
13382
|
-
var OVERLAY_BUTTON_STYLE = {
|
|
13383
|
-
pointerEvents: "auto",
|
|
13384
|
-
fontFamily: "Inter, sans-serif",
|
|
13385
|
-
fontSize: 12,
|
|
13386
|
-
color: "#000"
|
|
13387
|
-
};
|
|
13388
|
-
var SKELETON_CSS = `
|
|
13431
|
+
var MEDIA_SKELETON_CSS = `
|
|
13389
13432
|
@keyframes ohw-media-shimmer {
|
|
13390
13433
|
0% { transform: translateX(-100%); }
|
|
13391
13434
|
100% { transform: translateX(100%); }
|
|
@@ -13402,6 +13445,16 @@ var SKELETON_CSS = `
|
|
|
13402
13445
|
animation: ohw-media-shimmer 1.4s infinite;
|
|
13403
13446
|
}
|
|
13404
13447
|
`;
|
|
13448
|
+
|
|
13449
|
+
// src/ui/MediaOverlay.tsx
|
|
13450
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
13451
|
+
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
13452
|
+
var OVERLAY_BUTTON_STYLE = {
|
|
13453
|
+
pointerEvents: "auto",
|
|
13454
|
+
fontFamily: "Inter, sans-serif",
|
|
13455
|
+
fontSize: 12,
|
|
13456
|
+
color: "#000"
|
|
13457
|
+
};
|
|
13405
13458
|
var REPLACE_BUTTON_INSET = 12;
|
|
13406
13459
|
function replaceButtonMode(image, button) {
|
|
13407
13460
|
if (!button.fullWidth || !button.height) return "none";
|
|
@@ -13440,6 +13493,7 @@ function MediaOverlay({
|
|
|
13440
13493
|
(prev) => prev && prev.fullWidth === width && prev.height === height ? prev : { fullWidth: width, height }
|
|
13441
13494
|
);
|
|
13442
13495
|
}, [isVideo]);
|
|
13496
|
+
const replaceLabel = isVideo ? "Replace video" : hover.elementType === "bg-image" ? "Replace background" : "Replace image";
|
|
13443
13497
|
const replaceMode = buttonSize ? replaceButtonMode({ width: rect.width, height: rect.height }, buttonSize) : "none";
|
|
13444
13498
|
const box = {
|
|
13445
13499
|
position: "fixed",
|
|
@@ -13469,7 +13523,7 @@ function MediaOverlay({
|
|
|
13469
13523
|
"data-ohw-media-skeleton": "",
|
|
13470
13524
|
"aria-hidden": true,
|
|
13471
13525
|
style: { ...box, pointerEvents: "none" },
|
|
13472
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("style", { children:
|
|
13526
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("style", { children: MEDIA_SKELETON_CSS })
|
|
13473
13527
|
}
|
|
13474
13528
|
);
|
|
13475
13529
|
}
|
|
@@ -13538,11 +13592,10 @@ function MediaOverlay({
|
|
|
13538
13592
|
className: "flex items-center justify-center cursor-pointer",
|
|
13539
13593
|
style: {
|
|
13540
13594
|
...box,
|
|
13541
|
-
//
|
|
13542
|
-
//
|
|
13543
|
-
//
|
|
13544
|
-
|
|
13545
|
-
pointerEvents: hover.hasTextOverlap || cueOnly ? "none" : "auto",
|
|
13595
|
+
// Visual only. `pointer-events: auto` on this full-bleed rect covered the navbar
|
|
13596
|
+
// (hero bg includes the absolute TopNav) and swallowed CTA press-drag. Text overlay
|
|
13597
|
+
// and cueOnly also need clicks to fall through — Replace / video controls opt back in.
|
|
13598
|
+
pointerEvents: "none",
|
|
13546
13599
|
// Selected: a firm component ring with no wash, so the image reads as chosen rather
|
|
13547
13600
|
// than hovered. Hover keeps the existing tinted preview.
|
|
13548
13601
|
boxShadow: selected ? "inset 0 0 0 2px var(--color-bridge-primary)" : "inset 0 0 0 1.5px var(--color-bridge-primary)",
|
|
@@ -13569,17 +13622,17 @@ function MediaOverlay({
|
|
|
13569
13622
|
},
|
|
13570
13623
|
children: [
|
|
13571
13624
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
13572
|
-
|
|
13625
|
+
replaceLabel
|
|
13573
13626
|
]
|
|
13574
13627
|
}
|
|
13575
13628
|
),
|
|
13576
|
-
replaceMode
|
|
13629
|
+
showChrome && replaceMode !== "none" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
13577
13630
|
Button,
|
|
13578
13631
|
{
|
|
13579
13632
|
"data-ohw-media-overlay": "",
|
|
13580
13633
|
variant: "outline",
|
|
13581
13634
|
size: "sm",
|
|
13582
|
-
"aria-label":
|
|
13635
|
+
"aria-label": replaceLabel,
|
|
13583
13636
|
className: "gap-1.5 cursor-pointer hover:bg-background",
|
|
13584
13637
|
style: {
|
|
13585
13638
|
...OVERLAY_BUTTON_STYLE,
|
|
@@ -13602,7 +13655,7 @@ function MediaOverlay({
|
|
|
13602
13655
|
},
|
|
13603
13656
|
children: [
|
|
13604
13657
|
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
13605
|
-
replaceMode === "full" ?
|
|
13658
|
+
replaceMode === "full" ? replaceLabel : null
|
|
13606
13659
|
]
|
|
13607
13660
|
}
|
|
13608
13661
|
)
|
|
@@ -15899,6 +15952,17 @@ function setCarouselSlideAsset(tree, index, assetId) {
|
|
|
15899
15952
|
return true;
|
|
15900
15953
|
});
|
|
15901
15954
|
}
|
|
15955
|
+
function carouselAutoplay(tree) {
|
|
15956
|
+
return findCarouselBlock(tree)?.slots?.autoplay === true;
|
|
15957
|
+
}
|
|
15958
|
+
function setCarouselAutoplay(tree, on) {
|
|
15959
|
+
return withCarousel(tree, (block) => {
|
|
15960
|
+
const slots = { ...block.slots, autoplay: on };
|
|
15961
|
+
if (!on) delete slots.interval;
|
|
15962
|
+
block.slots = slots;
|
|
15963
|
+
return true;
|
|
15964
|
+
});
|
|
15965
|
+
}
|
|
15902
15966
|
|
|
15903
15967
|
// src/ui/ai-section/AiFadeCarouselOverlay.tsx
|
|
15904
15968
|
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
@@ -16012,10 +16076,85 @@ function Pill4({ label, onClick, disabled }) {
|
|
|
16012
16076
|
}
|
|
16013
16077
|
);
|
|
16014
16078
|
}
|
|
16079
|
+
function TogglePill({
|
|
16080
|
+
label,
|
|
16081
|
+
on,
|
|
16082
|
+
onToggle,
|
|
16083
|
+
disabled
|
|
16084
|
+
}) {
|
|
16085
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
16086
|
+
"button",
|
|
16087
|
+
{
|
|
16088
|
+
type: "button",
|
|
16089
|
+
role: "switch",
|
|
16090
|
+
"aria-checked": on,
|
|
16091
|
+
onClick: onToggle,
|
|
16092
|
+
disabled,
|
|
16093
|
+
title: on ? `${label} on \u2014 click to turn off` : `${label} off \u2014 click to turn on`,
|
|
16094
|
+
style: {
|
|
16095
|
+
height: 28,
|
|
16096
|
+
padding: "0 8px 0 10px",
|
|
16097
|
+
display: "inline-flex",
|
|
16098
|
+
alignItems: "center",
|
|
16099
|
+
gap: 8,
|
|
16100
|
+
borderRadius: 999,
|
|
16101
|
+
border: "none",
|
|
16102
|
+
cursor: disabled ? "default" : "pointer",
|
|
16103
|
+
background: "#ffffff",
|
|
16104
|
+
color: OHW_BLUE_DARK4,
|
|
16105
|
+
opacity: disabled ? 0.4 : 1,
|
|
16106
|
+
fontSize: 12,
|
|
16107
|
+
lineHeight: "16px",
|
|
16108
|
+
fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
|
|
16109
|
+
whiteSpace: "nowrap",
|
|
16110
|
+
flex: "0 0 auto"
|
|
16111
|
+
},
|
|
16112
|
+
children: [
|
|
16113
|
+
label,
|
|
16114
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
16115
|
+
"span",
|
|
16116
|
+
{
|
|
16117
|
+
"aria-hidden": true,
|
|
16118
|
+
style: {
|
|
16119
|
+
position: "relative",
|
|
16120
|
+
width: 26,
|
|
16121
|
+
height: 15,
|
|
16122
|
+
borderRadius: 999,
|
|
16123
|
+
flex: "0 0 auto",
|
|
16124
|
+
// Off is a grey track, not a washed-out blue: the pill's own white background already
|
|
16125
|
+
// carries the brand colour in the text, and a pale blue track next to it read as
|
|
16126
|
+
// "disabled control" rather than "switch that is off".
|
|
16127
|
+
background: on ? OHW_BLUE_DARK4 : "#CBD5E1",
|
|
16128
|
+
transition: "background 120ms ease"
|
|
16129
|
+
},
|
|
16130
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
16131
|
+
"span",
|
|
16132
|
+
{
|
|
16133
|
+
style: {
|
|
16134
|
+
position: "absolute",
|
|
16135
|
+
top: 2,
|
|
16136
|
+
left: on ? 13 : 2,
|
|
16137
|
+
width: 11,
|
|
16138
|
+
height: 11,
|
|
16139
|
+
borderRadius: "50%",
|
|
16140
|
+
background: "#ffffff",
|
|
16141
|
+
boxShadow: "0 1px 2px rgba(0,0,0,0.3)",
|
|
16142
|
+
transition: "left 120ms ease"
|
|
16143
|
+
}
|
|
16144
|
+
}
|
|
16145
|
+
)
|
|
16146
|
+
}
|
|
16147
|
+
)
|
|
16148
|
+
]
|
|
16149
|
+
}
|
|
16150
|
+
);
|
|
16151
|
+
}
|
|
16015
16152
|
function CarouselSlideToolbar({
|
|
16016
16153
|
pending,
|
|
16017
16154
|
error,
|
|
16018
|
-
|
|
16155
|
+
autoplay,
|
|
16156
|
+
onChangeImage,
|
|
16157
|
+
onToggleAutoplay
|
|
16019
16158
|
}) {
|
|
16020
16159
|
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
16021
16160
|
"div",
|
|
@@ -16032,11 +16171,18 @@ function CarouselSlideToolbar({
|
|
|
16032
16171
|
padding: 8,
|
|
16033
16172
|
borderRadius: 12,
|
|
16034
16173
|
boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
|
|
16035
|
-
|
|
16036
|
-
|
|
16174
|
+
// Not dimmed while pending, only inert. The toolbar used to drop to 0.6 opacity for the
|
|
16175
|
+
// length of the validate round-trip, which on a local backend is short enough that the
|
|
16176
|
+
// autoplay toggle just flashed — a dim and an un-dim with nothing in between. Progress is
|
|
16177
|
+
// reported where the change is: the switch moves at once (optimistically), and an image
|
|
16178
|
+
// swap raises the skeleton over the slide.
|
|
16179
|
+
pointerEvents: pending ? "none" : "auto"
|
|
16037
16180
|
},
|
|
16038
16181
|
children: [
|
|
16039
|
-
/* @__PURE__ */ (0, import_jsx_runtime22.
|
|
16182
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
|
|
16183
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Pill4, { label: "Change Image", onClick: onChangeImage }),
|
|
16184
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
|
|
16185
|
+
] }),
|
|
16040
16186
|
error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
|
|
16041
16187
|
]
|
|
16042
16188
|
}
|
|
@@ -16052,8 +16198,24 @@ function AiFadeCarouselOverlay({
|
|
|
16052
16198
|
const [active, setActive] = (0, import_react12.useState)(null);
|
|
16053
16199
|
const [pending, setPending] = (0, import_react12.useState)(false);
|
|
16054
16200
|
const [error, setError] = (0, import_react12.useState)(null);
|
|
16201
|
+
const [autoplayOverride, setAutoplayOverride] = (0, import_react12.useState)(null);
|
|
16202
|
+
const [swapping, setSwapping] = (0, import_react12.useState)(null);
|
|
16203
|
+
const skeletonRef = (0, import_react12.useRef)(null);
|
|
16055
16204
|
const activeRef = (0, import_react12.useRef)(null);
|
|
16056
16205
|
activeRef.current = active;
|
|
16206
|
+
(0, import_react12.useEffect)(() => {
|
|
16207
|
+
setAutoplayOverride(null);
|
|
16208
|
+
}, [active?.sectionId, active?.index]);
|
|
16209
|
+
(0, import_react12.useEffect)(() => {
|
|
16210
|
+
if (!swapping?.fadingOut || !skeletonRef.current) return;
|
|
16211
|
+
const anim = skeletonRef.current.animate([{ opacity: 1 }, { opacity: 0 }], {
|
|
16212
|
+
duration: MEDIA_UPLOAD_FADE_MS,
|
|
16213
|
+
easing: "ease-out",
|
|
16214
|
+
fill: "forwards"
|
|
16215
|
+
});
|
|
16216
|
+
anim.finished.then(() => setSwapping(null)).catch(() => setSwapping(null));
|
|
16217
|
+
return () => anim.cancel();
|
|
16218
|
+
}, [swapping?.fadingOut]);
|
|
16057
16219
|
(0, import_react12.useEffect)(() => {
|
|
16058
16220
|
const onMove = (e) => {
|
|
16059
16221
|
const t = e.target;
|
|
@@ -16194,6 +16356,27 @@ function AiFadeCarouselOverlay({
|
|
|
16194
16356
|
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
|
|
16195
16357
|
}
|
|
16196
16358
|
),
|
|
16359
|
+
swapping && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
16360
|
+
"div",
|
|
16361
|
+
{
|
|
16362
|
+
ref: skeletonRef,
|
|
16363
|
+
"data-ohw-bridge": "",
|
|
16364
|
+
"data-ohw-media-skeleton": "",
|
|
16365
|
+
"aria-hidden": true,
|
|
16366
|
+
style: {
|
|
16367
|
+
position: "fixed",
|
|
16368
|
+
top: swapping.rect.top,
|
|
16369
|
+
left: swapping.rect.left,
|
|
16370
|
+
width: swapping.rect.width,
|
|
16371
|
+
height: swapping.rect.height,
|
|
16372
|
+
// Under the toolbar (2147483647) so its controls stay visible and clickable over the
|
|
16373
|
+
// slide being swapped, and inert so it cannot eat the click that dismisses them.
|
|
16374
|
+
zIndex: 2147483646,
|
|
16375
|
+
pointerEvents: "none"
|
|
16376
|
+
},
|
|
16377
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("style", { children: MEDIA_SKELETON_CSS })
|
|
16378
|
+
}
|
|
16379
|
+
),
|
|
16197
16380
|
activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
16198
16381
|
ItemInteractionLayer,
|
|
16199
16382
|
{
|
|
@@ -16204,14 +16387,36 @@ function AiFadeCarouselOverlay({
|
|
|
16204
16387
|
{
|
|
16205
16388
|
pending,
|
|
16206
16389
|
error,
|
|
16390
|
+
autoplay: autoplayOverride ?? carouselAutoplay(activeEntry.tree),
|
|
16391
|
+
onToggleAutoplay: () => {
|
|
16392
|
+
const next = !(autoplayOverride ?? carouselAutoplay(activeEntry.tree));
|
|
16393
|
+
setAutoplayOverride(next);
|
|
16394
|
+
void runMutation(active.sectionId, (tree) => setCarouselAutoplay(tree, next)).then(
|
|
16395
|
+
(ok) => {
|
|
16396
|
+
if (!ok) setAutoplayOverride(null);
|
|
16397
|
+
}
|
|
16398
|
+
);
|
|
16399
|
+
},
|
|
16207
16400
|
onChangeImage: () => {
|
|
16208
|
-
void requestAssetPick2(postToParent2).then((picked) => {
|
|
16401
|
+
void requestAssetPick2(postToParent2).then(async (picked) => {
|
|
16209
16402
|
if (!picked) return;
|
|
16210
|
-
|
|
16403
|
+
const slideRect = readRect5(active);
|
|
16404
|
+
if (slideRect) setSwapping({ rect: slideRect, fadingOut: false });
|
|
16405
|
+
const ok = await runMutation(
|
|
16211
16406
|
active.sectionId,
|
|
16212
16407
|
(tree) => setCarouselSlideAsset(tree, active.index, picked.assetId),
|
|
16213
16408
|
{ [picked.assetId]: picked.url }
|
|
16214
16409
|
);
|
|
16410
|
+
if (!ok) {
|
|
16411
|
+
setSwapping(null);
|
|
16412
|
+
return;
|
|
16413
|
+
}
|
|
16414
|
+
const preload = new Image();
|
|
16415
|
+
const done = () => setSwapping((s) => s ? { ...s, fadingOut: true } : s);
|
|
16416
|
+
preload.onload = done;
|
|
16417
|
+
preload.onerror = done;
|
|
16418
|
+
preload.src = picked.url;
|
|
16419
|
+
if (preload.complete) done();
|
|
16215
16420
|
});
|
|
16216
16421
|
}
|
|
16217
16422
|
}
|
|
@@ -19682,6 +19887,7 @@ function readLogoSizeState(content, placement) {
|
|
|
19682
19887
|
function getLogoElement(el) {
|
|
19683
19888
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
19684
19889
|
if (marked) return marked;
|
|
19890
|
+
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
19685
19891
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
19686
19892
|
if (!root) return null;
|
|
19687
19893
|
const anchor = el.closest("a");
|
|
@@ -23173,7 +23379,7 @@ function getNavigationSelectionParent(el) {
|
|
|
23173
23379
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
23174
23380
|
return resolveFooterLinksContainerFrom(el);
|
|
23175
23381
|
}
|
|
23176
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
23382
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup2(el)) {
|
|
23177
23383
|
return getNavigationRoot(el);
|
|
23178
23384
|
}
|
|
23179
23385
|
return null;
|
|
@@ -23395,7 +23601,6 @@ var ICONS = {
|
|
|
23395
23601
|
insertUnorderedList: '<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>',
|
|
23396
23602
|
insertOrderedList: '<line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4"/><path d="M4 10h2"/><path d="M6 18H4c0-1 2-2 2-3s-1-1.5-2-1"/>'
|
|
23397
23603
|
};
|
|
23398
|
-
var HEIGHT_SETTLE_DELAYS = [150, 400, 800];
|
|
23399
23604
|
var SELECTION_CHROME_GAP2 = 4;
|
|
23400
23605
|
var TOOLBAR_STROKE_GAP2 = 4;
|
|
23401
23606
|
var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
|
|
@@ -24375,21 +24580,6 @@ function OhhwellsBridge() {
|
|
|
24375
24580
|
const [isItemDragging, setIsItemDragging] = (0, import_react21.useState)(false);
|
|
24376
24581
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = (0, import_react21.useState)(false);
|
|
24377
24582
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
24378
|
-
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
24379
|
-
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
24380
|
-
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
24381
|
-
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
24382
|
-
floatingPanelRef.current = floatingPanel;
|
|
24383
|
-
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
24384
|
-
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
24385
|
-
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
24386
|
-
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
24387
|
-
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
24388
|
-
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
24389
|
-
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
24390
|
-
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
24391
|
-
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
24392
|
-
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
24393
24583
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = (0, import_react21.useState)(null);
|
|
24394
24584
|
const [footerHeadingVisible, setFooterHeadingVisible] = (0, import_react21.useState)(null);
|
|
24395
24585
|
const footerDragRef = (0, import_react21.useRef)(null);
|
|
@@ -24415,6 +24605,21 @@ function OhhwellsBridge() {
|
|
|
24415
24605
|
const stylesRef = (0, import_react21.useRef)("");
|
|
24416
24606
|
const appliedDrawerRef = (0, import_react21.useRef)(null);
|
|
24417
24607
|
const pendingDeleteUndoRef = (0, import_react21.useRef)(null);
|
|
24608
|
+
const [floatingPanel, setFloatingPanel] = (0, import_react21.useState)(null);
|
|
24609
|
+
const floatingPanelOpenRef = (0, import_react21.useRef)(false);
|
|
24610
|
+
const floatingPanelRef = (0, import_react21.useRef)(null);
|
|
24611
|
+
floatingPanelRef.current = floatingPanel;
|
|
24612
|
+
const setFloatingPanelRef = (0, import_react21.useRef)(setFloatingPanel);
|
|
24613
|
+
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react21.useState)(null);
|
|
24614
|
+
const buttonCollectionDragRef = (0, import_react21.useRef)(null);
|
|
24615
|
+
const buttonDropInsertIndexRef = (0, import_react21.useRef)(null);
|
|
24616
|
+
const [buttonDropSlots, setButtonDropSlots] = (0, import_react21.useState)([]);
|
|
24617
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react21.useState)(null);
|
|
24618
|
+
const buttonPointerDragRef = (0, import_react21.useRef)(null);
|
|
24619
|
+
const [buttonStyleTick, setButtonStyleTick] = (0, import_react21.useState)(0);
|
|
24620
|
+
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react21.useState)(null);
|
|
24621
|
+
const [editorViewport, setEditorViewport] = (0, import_react21.useState)("desktop");
|
|
24622
|
+
const [parentScrollSnap, setParentScrollSnap] = (0, import_react21.useState)(null);
|
|
24418
24623
|
const [sitePages, setSitePages] = (0, import_react21.useState)([]);
|
|
24419
24624
|
const [sectionsByPath, setSectionsByPath] = (0, import_react21.useState)({});
|
|
24420
24625
|
const sectionsPrefetchGenRef = (0, import_react21.useRef)(0);
|
|
@@ -24423,7 +24628,18 @@ function OhhwellsBridge() {
|
|
|
24423
24628
|
const linkPopoverOpenRef = (0, import_react21.useRef)(false);
|
|
24424
24629
|
const linkPopoverGraceUntilRef = (0, import_react21.useRef)(0);
|
|
24425
24630
|
setLinkPopoverRef.current = setLinkPopover;
|
|
24631
|
+
setFloatingPanelRef.current = setFloatingPanel;
|
|
24426
24632
|
linkPopoverSessionRef.current = linkPopover;
|
|
24633
|
+
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
24634
|
+
(0, import_react21.useEffect)(() => {
|
|
24635
|
+
const syncViewport = () => {
|
|
24636
|
+
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
24637
|
+
setEditorViewport((prev) => prev === next ? prev : next);
|
|
24638
|
+
};
|
|
24639
|
+
syncViewport();
|
|
24640
|
+
window.addEventListener("resize", syncViewport);
|
|
24641
|
+
return () => window.removeEventListener("resize", syncViewport);
|
|
24642
|
+
}, []);
|
|
24427
24643
|
(0, import_react21.useEffect)(() => {
|
|
24428
24644
|
setSectionOrderPersistHandler((entries) => {
|
|
24429
24645
|
const currentPath = window.location.pathname;
|
|
@@ -26102,6 +26318,7 @@ function OhhwellsBridge() {
|
|
|
26102
26318
|
applyAiFooterFromContent(content);
|
|
26103
26319
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
26104
26320
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
26321
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
26105
26322
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
26106
26323
|
}
|
|
26107
26324
|
applyBrandChrome(content);
|
|
@@ -26111,12 +26328,12 @@ function OhhwellsBridge() {
|
|
|
26111
26328
|
if (key === "__ohw_sections") continue;
|
|
26112
26329
|
if (key === AI_SECTIONS_KEY) continue;
|
|
26113
26330
|
if (key === AI_FOOTER_KEY) continue;
|
|
26331
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
26332
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
26114
26333
|
if (key === BRAND_KIT_KEY) continue;
|
|
26115
26334
|
if (key === STYLE_STORE_KEY) continue;
|
|
26116
26335
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
26117
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
26118
26336
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
26119
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
26120
26337
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
26121
26338
|
continue;
|
|
26122
26339
|
}
|
|
@@ -26330,17 +26547,18 @@ function OhhwellsBridge() {
|
|
|
26330
26547
|
}
|
|
26331
26548
|
applyAiFooterFromContent(content);
|
|
26332
26549
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
26550
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
26333
26551
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
26334
26552
|
}
|
|
26335
26553
|
for (const [key, val] of Object.entries(content)) {
|
|
26336
26554
|
if (key === "__ohw_sections") continue;
|
|
26337
26555
|
if (key === AI_SECTIONS_KEY) continue;
|
|
26338
26556
|
if (key === AI_FOOTER_KEY) continue;
|
|
26557
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
26558
|
+
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
26339
26559
|
if (key === BRAND_KIT_KEY) continue;
|
|
26340
26560
|
if (key === STYLE_STORE_KEY) continue;
|
|
26341
26561
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
26342
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
26343
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
26344
26562
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
26345
26563
|
continue;
|
|
26346
26564
|
}
|
|
@@ -26596,26 +26814,11 @@ function OhhwellsBridge() {
|
|
|
26596
26814
|
const t2 = setTimeout(measure, 500);
|
|
26597
26815
|
const ro = new ResizeObserver(schedule);
|
|
26598
26816
|
ro.observe(document.body);
|
|
26599
|
-
let lastWidth = window.innerWidth;
|
|
26600
|
-
let resizeTimers = [];
|
|
26601
|
-
const clearResizeTimers = () => {
|
|
26602
|
-
resizeTimers.forEach(clearTimeout);
|
|
26603
|
-
resizeTimers = [];
|
|
26604
|
-
};
|
|
26605
|
-
const handleResize = () => {
|
|
26606
|
-
if (window.innerWidth === lastWidth) return;
|
|
26607
|
-
lastWidth = window.innerWidth;
|
|
26608
|
-
clearResizeTimers();
|
|
26609
|
-
resizeTimers = HEIGHT_SETTLE_DELAYS.map((delay) => setTimeout(measure, delay));
|
|
26610
|
-
};
|
|
26611
|
-
window.addEventListener("resize", handleResize);
|
|
26612
26817
|
return () => {
|
|
26613
26818
|
clearTimeout(t1);
|
|
26614
26819
|
clearTimeout(t2);
|
|
26615
26820
|
if (raf != null) cancelAnimationFrame(raf);
|
|
26616
26821
|
ro.disconnect();
|
|
26617
|
-
clearResizeTimers();
|
|
26618
|
-
window.removeEventListener("resize", handleResize);
|
|
26619
26822
|
};
|
|
26620
26823
|
}, [pathname, isEditMode, postToParent2]);
|
|
26621
26824
|
(0, import_react21.useEffect)(() => {
|
|
@@ -26910,6 +27113,13 @@ function OhhwellsBridge() {
|
|
|
26910
27113
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
26911
27114
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
26912
27115
|
if (isInsideLinkEditor(target)) return;
|
|
27116
|
+
if (isInsideFloatingPanel(target)) return;
|
|
27117
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
27118
|
+
if (target.closest(
|
|
27119
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
27120
|
+
)) {
|
|
27121
|
+
return;
|
|
27122
|
+
}
|
|
26913
27123
|
if (selectedMediaElRef.current && !selectedMediaElRef.current.contains(target) && !target.closest("[data-ohw-media-overlay], [data-ohw-edit-chrome], [data-ohw-item-interaction]")) {
|
|
26914
27124
|
clearMediaSelectionRef.current();
|
|
26915
27125
|
}
|
|
@@ -26930,13 +27140,6 @@ function OhhwellsBridge() {
|
|
|
26930
27140
|
return;
|
|
26931
27141
|
}
|
|
26932
27142
|
}
|
|
26933
|
-
if (isInsideFloatingPanel(target)) return;
|
|
26934
|
-
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
26935
|
-
if (target.closest(
|
|
26936
|
-
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
26937
|
-
)) {
|
|
26938
|
-
return;
|
|
26939
|
-
}
|
|
26940
27143
|
{
|
|
26941
27144
|
const formEl = getFormElement(target);
|
|
26942
27145
|
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
@@ -27316,6 +27519,9 @@ function OhhwellsBridge() {
|
|
|
27316
27519
|
setHoveredItemRect(null);
|
|
27317
27520
|
hoveredNavContainerRef.current = null;
|
|
27318
27521
|
setHoveredNavContainerRect(null);
|
|
27522
|
+
siblingHintElRef.current = null;
|
|
27523
|
+
setSiblingHintRect(null);
|
|
27524
|
+
setSiblingHintRects([]);
|
|
27319
27525
|
return;
|
|
27320
27526
|
}
|
|
27321
27527
|
{
|
|
@@ -27436,7 +27642,6 @@ function OhhwellsBridge() {
|
|
|
27436
27642
|
hoveredNavContainerRef.current = null;
|
|
27437
27643
|
setHoveredNavContainerRect(null);
|
|
27438
27644
|
hoveredItemElRef.current = editable;
|
|
27439
|
-
setHoveredItemRect(isSelectedForHoverRef.current(editable) ? null : editable.getBoundingClientRect());
|
|
27440
27645
|
}
|
|
27441
27646
|
}
|
|
27442
27647
|
}
|
|
@@ -28146,7 +28351,11 @@ function OhhwellsBridge() {
|
|
|
28146
28351
|
};
|
|
28147
28352
|
const handleMouseMove = (e) => {
|
|
28148
28353
|
const { clientX, clientY } = e;
|
|
28149
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
28354
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
28355
|
+
dismissImageHover();
|
|
28356
|
+
clearImageHover();
|
|
28357
|
+
return;
|
|
28358
|
+
}
|
|
28150
28359
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) {
|
|
28151
28360
|
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
28152
28361
|
formHoverElRef.current = null;
|
|
@@ -28175,7 +28384,12 @@ function OhhwellsBridge() {
|
|
|
28175
28384
|
setHoveredItemRect(null);
|
|
28176
28385
|
hoveredNavContainerRef.current = null;
|
|
28177
28386
|
setHoveredNavContainerRect(null);
|
|
28387
|
+
siblingHintElRef.current = null;
|
|
28388
|
+
setSiblingHintRect(null);
|
|
28389
|
+
setSiblingHintRects([]);
|
|
28178
28390
|
dismissImageHover();
|
|
28391
|
+
clearImageHover();
|
|
28392
|
+
setSectionGap(null);
|
|
28179
28393
|
return;
|
|
28180
28394
|
}
|
|
28181
28395
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
@@ -28187,7 +28401,11 @@ function OhhwellsBridge() {
|
|
|
28187
28401
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
28188
28402
|
const { clientX, clientY } = e.data;
|
|
28189
28403
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
28190
|
-
if (pointOwnedByFloatingPanel(clientX, clientY))
|
|
28404
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) {
|
|
28405
|
+
dismissImageHover();
|
|
28406
|
+
clearImageHover();
|
|
28407
|
+
return;
|
|
28408
|
+
}
|
|
28191
28409
|
if (isNavDrawerOpen() && isPointOutsideOpenDrawer(clientX, clientY)) return;
|
|
28192
28410
|
if (probeSocialsRowAt(clientX, clientY)) return;
|
|
28193
28411
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -28539,6 +28757,7 @@ function OhhwellsBridge() {
|
|
|
28539
28757
|
applyAiFooterFromContent(content);
|
|
28540
28758
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
28541
28759
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
28760
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((f) => markFormFields(f));
|
|
28542
28761
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
28543
28762
|
}
|
|
28544
28763
|
applyBrandChrome(content);
|
|
@@ -28552,12 +28771,12 @@ function OhhwellsBridge() {
|
|
|
28552
28771
|
}
|
|
28553
28772
|
if (key === AI_SECTIONS_KEY) continue;
|
|
28554
28773
|
if (key === AI_FOOTER_KEY) continue;
|
|
28774
|
+
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28775
|
+
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
28555
28776
|
if (key === BRAND_KIT_KEY) continue;
|
|
28556
28777
|
if (key === STYLE_STORE_KEY) continue;
|
|
28557
28778
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
28558
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
28559
28779
|
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
28560
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
28561
28780
|
if (typeof content[AI_FOOTER_KEY] === "string" && content[AI_FOOTER_KEY] && isAiFooterOwnedContentKey(key)) {
|
|
28562
28781
|
continue;
|
|
28563
28782
|
}
|
|
@@ -29094,6 +29313,12 @@ function OhhwellsBridge() {
|
|
|
29094
29313
|
closeLinkPopoverRef.current();
|
|
29095
29314
|
return;
|
|
29096
29315
|
}
|
|
29316
|
+
if (floatingPanelOpenRef.current) {
|
|
29317
|
+
setFloatingPanelRef.current(null);
|
|
29318
|
+
deselectRef.current();
|
|
29319
|
+
deactivateRef.current();
|
|
29320
|
+
return;
|
|
29321
|
+
}
|
|
29097
29322
|
deselectRef.current();
|
|
29098
29323
|
deactivateRef.current();
|
|
29099
29324
|
clearMediaSelectionRef.current();
|
|
@@ -29856,10 +30081,10 @@ function OhhwellsBridge() {
|
|
|
29856
30081
|
window.removeEventListener("message", handleDeleteSection);
|
|
29857
30082
|
window.removeEventListener("message", handleDuplicateSection);
|
|
29858
30083
|
window.removeEventListener("message", handleDeactivate);
|
|
29859
|
-
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
29860
30084
|
window.removeEventListener("message", handleToastAction);
|
|
29861
30085
|
window.removeEventListener("message", handleFormCount);
|
|
29862
30086
|
window.removeEventListener("message", handleUiEscape);
|
|
30087
|
+
document.documentElement.removeAttribute("data-ohw-panel-dragging");
|
|
29863
30088
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
29864
30089
|
autoSaveTimers.current.clear();
|
|
29865
30090
|
if (imageUnhoverTimerRef.current) clearTimeout(imageUnhoverTimerRef.current);
|
|
@@ -30153,7 +30378,7 @@ function OhhwellsBridge() {
|
|
|
30153
30378
|
postToParent2({
|
|
30154
30379
|
type: "ow:ready",
|
|
30155
30380
|
version: "1",
|
|
30156
|
-
bridgeVersion: "0.1.
|
|
30381
|
+
bridgeVersion: "0.1.134",
|
|
30157
30382
|
path: pathname,
|
|
30158
30383
|
nodes: collectEditableNodes(editContentRef.current),
|
|
30159
30384
|
sections
|