@ohhwells/bridge 0.1.64-next.176 → 0.1.64
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 +1505 -1560
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -18
- package/dist/index.d.ts +6 -18
- package/dist/index.js +1494 -1548
- package/dist/index.js.map +1 -1
- package/dist/styles.css +99 -59
- package/package.json +1 -6
- package/dist/pages.cjs +0 -141
- package/dist/pages.cjs.map +0 -1
- package/dist/pages.d.cts +0 -45
- package/dist/pages.d.ts +0 -45
- package/dist/pages.js +0 -107
- package/dist/pages.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -96,7 +96,6 @@ function applyTreeToState(state, payload) {
|
|
|
96
96
|
const entry = {
|
|
97
97
|
id: payload.id,
|
|
98
98
|
label: payload.label ?? "Generated section",
|
|
99
|
-
...typeof payload.path === "string" && payload.path ? { path: payload.path } : {},
|
|
100
99
|
afterSection: payload.mode === "insert" && !insertBefore ? payload.targetSectionId ?? null : null,
|
|
101
100
|
...insertBefore && payload.targetSectionId ? { beforeSection: payload.targetSectionId } : {},
|
|
102
101
|
...payload.mode === "replace" && payload.targetSectionId ? { replaces: payload.targetSectionId } : {},
|
|
@@ -119,317 +118,6 @@ function deleteSectionFromState(state, sectionId) {
|
|
|
119
118
|
return { ...state, v: 1, sections: state.sections, removed: [...removed, sectionId] };
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
// src/lib/brand-chrome.ts
|
|
123
|
-
var BRAND_NAME_KEY = "__ohw_brand_name";
|
|
124
|
-
var BRAND_TITLE_KEY = "__ohw_site_title";
|
|
125
|
-
var BRAND_FAVICON_LETTER_KEY = "__ohw_favicon_letter";
|
|
126
|
-
var BRAND_CHROME_KEYS = /* @__PURE__ */ new Set([
|
|
127
|
-
BRAND_NAME_KEY,
|
|
128
|
-
BRAND_TITLE_KEY,
|
|
129
|
-
BRAND_FAVICON_LETTER_KEY
|
|
130
|
-
]);
|
|
131
|
-
function upsertMeta(selector, attr, token, value) {
|
|
132
|
-
let el = document.head.querySelector(selector);
|
|
133
|
-
if (!el) {
|
|
134
|
-
el = document.createElement("meta");
|
|
135
|
-
el.setAttribute(attr, token);
|
|
136
|
-
document.head.appendChild(el);
|
|
137
|
-
}
|
|
138
|
-
if (el.getAttribute("content") !== value) el.setAttribute("content", value);
|
|
139
|
-
}
|
|
140
|
-
function escapeXml(value) {
|
|
141
|
-
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
142
|
-
}
|
|
143
|
-
function applyLetterFavicon(letter) {
|
|
144
|
-
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="12" fill="#111827"/><text x="32" y="46" font-family="system-ui,-apple-system,Segoe UI,sans-serif" font-size="40" font-weight="700" text-anchor="middle" fill="#ffffff">${escapeXml(letter)}</text></svg>`;
|
|
145
|
-
const href = `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
146
|
-
let link = document.head.querySelector('link[rel="icon"]');
|
|
147
|
-
if (!link) {
|
|
148
|
-
link = document.createElement("link");
|
|
149
|
-
link.rel = "icon";
|
|
150
|
-
document.head.appendChild(link);
|
|
151
|
-
}
|
|
152
|
-
link.type = "image/svg+xml";
|
|
153
|
-
if (link.href !== href) link.href = href;
|
|
154
|
-
}
|
|
155
|
-
function applyBrandChrome(content) {
|
|
156
|
-
const name = content[BRAND_NAME_KEY];
|
|
157
|
-
if (typeof name === "string" && name.length > 0) {
|
|
158
|
-
document.querySelectorAll("[data-ohw-wordmark]").forEach((el) => {
|
|
159
|
-
if (el.textContent !== name) el.textContent = name;
|
|
160
|
-
if (el.getAttribute("title") !== name) el.setAttribute("title", name);
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
const title = content[BRAND_TITLE_KEY];
|
|
164
|
-
if (typeof title === "string" && title.length > 0) {
|
|
165
|
-
if (document.title !== title) document.title = title;
|
|
166
|
-
upsertMeta('meta[property="og:title"]', "property", "og:title", title);
|
|
167
|
-
upsertMeta('meta[name="twitter:title"]', "name", "twitter:title", title);
|
|
168
|
-
}
|
|
169
|
-
const letter = content[BRAND_FAVICON_LETTER_KEY];
|
|
170
|
-
if (typeof letter === "string" && letter.length > 0) {
|
|
171
|
-
applyLetterFavicon(letter);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// src/lib/brand-kit.ts
|
|
176
|
-
var BRAND_KIT_KEY = "__ohw_brand";
|
|
177
|
-
var BRAND_VAR_PREFIX = "--ohw-brand-";
|
|
178
|
-
var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
|
|
179
|
-
(role) => `${BRAND_VAR_PREFIX}${role}`
|
|
180
|
-
);
|
|
181
|
-
var FONT_VARS = {
|
|
182
|
-
heading: ["--font-heading", "--font-display", "--brand-font-heading"],
|
|
183
|
-
body: ["--font-body", "--brand-font-body"]
|
|
184
|
-
};
|
|
185
|
-
var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
|
|
186
|
-
function brandColorVars(kit) {
|
|
187
|
-
const { dark, primary, accent, light } = kit.palette;
|
|
188
|
-
const mix = (a, aPct, b) => `color-mix(in srgb, ${a} ${aPct}%, ${b})`;
|
|
189
|
-
return {
|
|
190
|
-
[`${BRAND_VAR_PREFIX}primary`]: primary,
|
|
191
|
-
[`${BRAND_VAR_PREFIX}accent`]: accent,
|
|
192
|
-
[`${BRAND_VAR_PREFIX}light`]: light,
|
|
193
|
-
[`${BRAND_VAR_PREFIX}dark`]: dark,
|
|
194
|
-
[`${BRAND_VAR_PREFIX}surface`]: mix(light, 95, dark),
|
|
195
|
-
[`${BRAND_VAR_PREFIX}border`]: mix(light, 85, dark),
|
|
196
|
-
[`${BRAND_VAR_PREFIX}muted`]: mix(dark, 62, light)
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
function parseBrandKit(raw) {
|
|
200
|
-
if (!raw) return null;
|
|
201
|
-
try {
|
|
202
|
-
const parsed = JSON.parse(raw);
|
|
203
|
-
const p = parsed?.palette;
|
|
204
|
-
const f = parsed?.fonts;
|
|
205
|
-
if (!p || !f || typeof p.dark !== "string" || typeof p.primary !== "string" || typeof p.accent !== "string" || typeof p.light !== "string" || typeof f.heading !== "string" || typeof f.body !== "string") {
|
|
206
|
-
return null;
|
|
207
|
-
}
|
|
208
|
-
return {
|
|
209
|
-
palette: { dark: p.dark, primary: p.primary, accent: p.accent, light: p.light },
|
|
210
|
-
fonts: { heading: f.heading, body: f.body }
|
|
211
|
-
};
|
|
212
|
-
} catch {
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
function familyOf(stack) {
|
|
217
|
-
const first = stack.split(",")[0]?.trim() ?? "";
|
|
218
|
-
return first.replace(/^['"]|['"]$/g, "");
|
|
219
|
-
}
|
|
220
|
-
function loadBrandFonts(families) {
|
|
221
|
-
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
222
|
-
if (unique.length === 0) return;
|
|
223
|
-
const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
|
|
224
|
-
const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
|
|
225
|
-
let link = document.getElementById(BRAND_FONT_LINK_ID);
|
|
226
|
-
if (!link) {
|
|
227
|
-
link = document.createElement("link");
|
|
228
|
-
link.id = BRAND_FONT_LINK_ID;
|
|
229
|
-
link.rel = "stylesheet";
|
|
230
|
-
document.head.appendChild(link);
|
|
231
|
-
}
|
|
232
|
-
if (link.href !== href) link.href = href;
|
|
233
|
-
}
|
|
234
|
-
function applyBrandToDom(kit) {
|
|
235
|
-
const root = document.documentElement;
|
|
236
|
-
if (!kit) {
|
|
237
|
-
for (const name of BRAND_VAR_NAMES) root.style.removeProperty(name);
|
|
238
|
-
for (const name of [...FONT_VARS.heading, ...FONT_VARS.body]) root.style.removeProperty(name);
|
|
239
|
-
document.getElementById(BRAND_FONT_LINK_ID)?.remove();
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
for (const [name, value] of Object.entries(brandColorVars(kit))) root.style.setProperty(name, value);
|
|
243
|
-
for (const name of FONT_VARS.heading) root.style.setProperty(name, kit.fonts.heading);
|
|
244
|
-
for (const name of FONT_VARS.body) root.style.setProperty(name, kit.fonts.body);
|
|
245
|
-
loadBrandFonts([familyOf(kit.fonts.heading), familyOf(kit.fonts.body)]);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// src/lib/section-styles.ts
|
|
249
|
-
var STYLE_STORE_KEY = "__ohw_styles";
|
|
250
|
-
var STYLE_SHEET_ID = "ohw-section-styles";
|
|
251
|
-
function parseStyleStore(raw) {
|
|
252
|
-
if (!raw) return null;
|
|
253
|
-
try {
|
|
254
|
-
const parsed = JSON.parse(raw);
|
|
255
|
-
if (parsed?.v !== 1) return null;
|
|
256
|
-
return {
|
|
257
|
-
v: 1,
|
|
258
|
-
sections: typeof parsed.sections === "object" && parsed.sections ? parsed.sections : {},
|
|
259
|
-
nodes: typeof parsed.nodes === "object" && parsed.nodes ? parsed.nodes : {}
|
|
260
|
-
};
|
|
261
|
-
} catch {
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
var BG_VALUES = {
|
|
266
|
-
surface: "color-mix(in srgb, var(--ohw-brand-light, var(--color-light, #ECECEB)) 94%, var(--ohw-brand-dark, var(--color-dark, #0C0A09)))",
|
|
267
|
-
accent: "var(--ohw-brand-primary, var(--color-primary, #0078E5))",
|
|
268
|
-
"accent-soft": "color-mix(in srgb, var(--ohw-brand-primary, var(--color-primary, #0078E5)) 12%, var(--ohw-brand-light, var(--color-light, #FFFFFF)))"
|
|
269
|
-
};
|
|
270
|
-
var HEADLINE_SIZES = { md: 24, lg: 32, xl: 40, display: 56 };
|
|
271
|
-
function styleSheetCss() {
|
|
272
|
-
const rules = [];
|
|
273
|
-
for (const [tone, value] of Object.entries(BG_VALUES)) {
|
|
274
|
-
rules.push(`[data-ohw-style-bg="${tone}"] { background: ${value} !important; }`);
|
|
275
|
-
}
|
|
276
|
-
rules.push(
|
|
277
|
-
`[data-ohw-style-bg="accent"] { color: var(--ohw-brand-light, var(--color-light, #FFFFFF)) !important; }`
|
|
278
|
-
);
|
|
279
|
-
rules.push(
|
|
280
|
-
`[data-ohw-style-distribution="space-between"] { display: flex !important; flex-direction: column; justify-content: space-between; }`,
|
|
281
|
-
`[data-ohw-style-distribution="center"] { display: flex !important; flex-direction: column; justify-content: center; }`
|
|
282
|
-
);
|
|
283
|
-
for (const [scale, size] of Object.entries(HEADLINE_SIZES)) {
|
|
284
|
-
rules.push(
|
|
285
|
-
`[data-ohw-style-headline="${scale}"] :is(h1, h2, h3) { font-size: ${size}px !important; line-height: 1.15 !important; }`
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
rules.push(
|
|
289
|
-
`[data-ohw-style-aspect="fill-height"] img { height: 100% !important; aspect-ratio: auto !important; object-fit: cover; }`
|
|
290
|
-
);
|
|
291
|
-
for (const aspect of ["1:1", "4:5", "3:4", "3:2", "16:9", "2:1", "3:1"]) {
|
|
292
|
-
rules.push(
|
|
293
|
-
`[data-ohw-style-aspect="${aspect.replace(":", "-")}"] img { aspect-ratio: ${aspect.replace(":", " / ")} !important; height: auto !important; object-fit: cover; }`
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
const pad = { tight: 40, balanced: 64, airy: 96 };
|
|
297
|
-
for (const [spacing, px] of Object.entries(pad)) {
|
|
298
|
-
rules.push(
|
|
299
|
-
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px}px !important; padding-bottom: ${px}px !important; }`
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
return rules.join("\n");
|
|
303
|
-
}
|
|
304
|
-
var STYLE_FONT_LINK_ID = "ohw-style-fonts";
|
|
305
|
-
function loadStyleFonts(families) {
|
|
306
|
-
const unique = [...new Set(families.map((f) => f.trim()).filter(Boolean))];
|
|
307
|
-
const existing = document.getElementById(STYLE_FONT_LINK_ID);
|
|
308
|
-
if (unique.length === 0) {
|
|
309
|
-
existing?.remove();
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
const spec = unique.map((f) => `${f.replace(/ /g, "+")}:400,500,600,700`).join("|");
|
|
313
|
-
const href = `https://fonts.googleapis.com/css?family=${spec}&display=swap`;
|
|
314
|
-
let link = existing;
|
|
315
|
-
if (!link) {
|
|
316
|
-
link = document.createElement("link");
|
|
317
|
-
link.id = STYLE_FONT_LINK_ID;
|
|
318
|
-
link.rel = "stylesheet";
|
|
319
|
-
document.head.appendChild(link);
|
|
320
|
-
}
|
|
321
|
-
if (link.href !== href) link.href = href;
|
|
322
|
-
}
|
|
323
|
-
var SECTION_ATTRS = {
|
|
324
|
-
sectionBackground: "data-ohw-style-bg",
|
|
325
|
-
textDistribution: "data-ohw-style-distribution",
|
|
326
|
-
headlineScale: "data-ohw-style-headline",
|
|
327
|
-
imageAspect: "data-ohw-style-aspect",
|
|
328
|
-
spacing: "data-ohw-style-spacing"
|
|
329
|
-
};
|
|
330
|
-
var NODE_WROTE_ATTR = "data-ohw-style-node";
|
|
331
|
-
var NODE_PROPS = ["color", "font-family", "font-size", "background"];
|
|
332
|
-
function saveInline(el, prop) {
|
|
333
|
-
const attr = `data-ohw-style-prev-${prop}`;
|
|
334
|
-
if (!el.hasAttribute(attr)) el.setAttribute(attr, el.style.getPropertyValue(prop));
|
|
335
|
-
}
|
|
336
|
-
function restoreInline(el, prop) {
|
|
337
|
-
const attr = `data-ohw-style-prev-${prop}`;
|
|
338
|
-
if (!el.hasAttribute(attr)) return;
|
|
339
|
-
const prev = el.getAttribute(attr) ?? "";
|
|
340
|
-
if (prev) el.style.setProperty(prop, prev);
|
|
341
|
-
else el.style.removeProperty(prop);
|
|
342
|
-
el.removeAttribute(attr);
|
|
343
|
-
}
|
|
344
|
-
function ensureStyleSheet() {
|
|
345
|
-
let el = document.getElementById(STYLE_SHEET_ID);
|
|
346
|
-
if (!el) {
|
|
347
|
-
el = document.createElement("style");
|
|
348
|
-
el.id = STYLE_SHEET_ID;
|
|
349
|
-
document.head.appendChild(el);
|
|
350
|
-
}
|
|
351
|
-
const css = styleSheetCss();
|
|
352
|
-
if (el.textContent !== css) el.textContent = css;
|
|
353
|
-
}
|
|
354
|
-
function clearSectionAttrs(root) {
|
|
355
|
-
for (const attr of Object.values(SECTION_ATTRS)) {
|
|
356
|
-
for (const el of Array.from(root.querySelectorAll(`[${attr}]`))) el.removeAttribute(attr);
|
|
357
|
-
}
|
|
358
|
-
for (const el of Array.from(root.querySelectorAll("[data-ohw-style-bgcolor]"))) {
|
|
359
|
-
restoreInline(el, "background");
|
|
360
|
-
el.removeAttribute("data-ohw-style-bgcolor");
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function clearNodeProps(root) {
|
|
364
|
-
for (const el of Array.from(root.querySelectorAll(`[${NODE_WROTE_ATTR}]`))) {
|
|
365
|
-
const h = el;
|
|
366
|
-
for (const prop of NODE_PROPS) restoreInline(h, prop);
|
|
367
|
-
h.removeAttribute(NODE_WROTE_ATTR);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
function buttonSurfaceOf(el) {
|
|
371
|
-
return el.closest("a, button") ?? el;
|
|
372
|
-
}
|
|
373
|
-
function applyStylesToDom(store) {
|
|
374
|
-
ensureStyleSheet();
|
|
375
|
-
clearSectionAttrs(document);
|
|
376
|
-
clearNodeProps(document);
|
|
377
|
-
loadStyleFonts(
|
|
378
|
-
store ? Object.values(store.nodes).flatMap((n) => n.fontFamily ? [n.fontFamily] : []) : []
|
|
379
|
-
);
|
|
380
|
-
if (!store) return;
|
|
381
|
-
for (const [sectionId, override] of Object.entries(store.sections)) {
|
|
382
|
-
const sections = document.querySelectorAll(
|
|
383
|
-
`[data-ohw-section="${CSS.escape(sectionId)}"]`
|
|
384
|
-
);
|
|
385
|
-
for (const section of Array.from(sections)) {
|
|
386
|
-
for (const [prop, attr] of Object.entries(SECTION_ATTRS)) {
|
|
387
|
-
const value = override[prop];
|
|
388
|
-
if (value === void 0) continue;
|
|
389
|
-
if (prop === "sectionBackground" && override.sectionBackgroundColor !== void 0) continue;
|
|
390
|
-
section.setAttribute(attr, String(value).replace(":", "-"));
|
|
391
|
-
}
|
|
392
|
-
if (override.sectionBackgroundColor !== void 0) {
|
|
393
|
-
saveInline(section, "background");
|
|
394
|
-
section.style.setProperty("background", override.sectionBackgroundColor, "important");
|
|
395
|
-
section.setAttribute("data-ohw-style-bgcolor", "");
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
for (const [key, override] of Object.entries(store.nodes)) {
|
|
400
|
-
const nodes = document.querySelectorAll(`[data-ohw-key="${CSS.escape(key)}"]`);
|
|
401
|
-
for (const el of Array.from(nodes)) {
|
|
402
|
-
if (override.color !== void 0) {
|
|
403
|
-
saveInline(el, "color");
|
|
404
|
-
el.style.setProperty("color", override.color, "important");
|
|
405
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
406
|
-
}
|
|
407
|
-
if (override.fontFamily !== void 0) {
|
|
408
|
-
saveInline(el, "font-family");
|
|
409
|
-
el.style.setProperty("font-family", `'${override.fontFamily}'`, "important");
|
|
410
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
411
|
-
}
|
|
412
|
-
if (override.fontSize !== void 0) {
|
|
413
|
-
saveInline(el, "font-size");
|
|
414
|
-
el.style.setProperty("font-size", `${override.fontSize}px`, "important");
|
|
415
|
-
el.setAttribute(NODE_WROTE_ATTR, "");
|
|
416
|
-
}
|
|
417
|
-
if (override.buttonBackground !== void 0 || override.buttonText !== void 0) {
|
|
418
|
-
const surface = buttonSurfaceOf(el);
|
|
419
|
-
if (override.buttonBackground !== void 0) {
|
|
420
|
-
saveInline(surface, "background");
|
|
421
|
-
surface.style.setProperty("background", override.buttonBackground, "important");
|
|
422
|
-
}
|
|
423
|
-
if (override.buttonText !== void 0) {
|
|
424
|
-
saveInline(surface, "color");
|
|
425
|
-
surface.style.setProperty("color", override.buttonText, "important");
|
|
426
|
-
}
|
|
427
|
-
surface.setAttribute(NODE_WROTE_ATTR, "");
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
121
|
// src/ui/ai-tree/aiSectionsManager.tsx
|
|
434
122
|
import { flushSync } from "react-dom";
|
|
435
123
|
import { createRoot } from "react-dom/client";
|
|
@@ -444,8 +132,7 @@ function lucideByName(name) {
|
|
|
444
132
|
}
|
|
445
133
|
var typeStyle = (spec, font) => ({
|
|
446
134
|
fontFamily: font,
|
|
447
|
-
|
|
448
|
-
fontSize: spec.size >= 24 ? `clamp(${Math.max(18, Math.round(spec.size * 0.6))}px, ${(spec.size / 9).toFixed(2)}vw, ${spec.size}px)` : spec.size,
|
|
135
|
+
fontSize: spec.size,
|
|
449
136
|
lineHeight: spec.line,
|
|
450
137
|
fontWeight: spec.weight
|
|
451
138
|
});
|
|
@@ -472,8 +159,6 @@ var AI_RESPONSIVE_CSS = [
|
|
|
472
159
|
" [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
|
|
473
160
|
" [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
|
|
474
161
|
" [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
|
|
475
|
-
" [data-ai-responsive] { overflow-x: hidden; }",
|
|
476
|
-
" [data-ai-responsive] img { max-width: 100%; }",
|
|
477
162
|
"}"
|
|
478
163
|
].join("\n");
|
|
479
164
|
var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
|
@@ -1481,20 +1166,6 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1481
1166
|
const overlayAlpha = { low: 0.25, medium: 0.45, high: 0.65 }[settings.overlayIntensity ?? "medium"];
|
|
1482
1167
|
const backgroundUrl = isOverlay && settings.backgroundMedia ? ctx.resolveMedia(settings.backgroundMedia) : null;
|
|
1483
1168
|
const bgAttrs = ctx.keyFor && isOverlay && settings.backgroundMedia ? { "data-ohw-key": ctx.keyFor("settings.backgroundMedia"), "data-ohw-editable": "bg-image" } : {};
|
|
1484
|
-
const toneBackground = (() => {
|
|
1485
|
-
const { dark, primary, light } = resolvedBrand.palette;
|
|
1486
|
-
switch (settings.sectionBackground) {
|
|
1487
|
-
case "surface":
|
|
1488
|
-
return `color-mix(in srgb, ${light} 94%, ${dark})`;
|
|
1489
|
-
case "accent":
|
|
1490
|
-
return primary;
|
|
1491
|
-
case "accent-soft":
|
|
1492
|
-
return `color-mix(in srgb, ${primary} 12%, ${light})`;
|
|
1493
|
-
default:
|
|
1494
|
-
return void 0;
|
|
1495
|
-
}
|
|
1496
|
-
})();
|
|
1497
|
-
const distributed = !isOverlay && settings.textDistribution;
|
|
1498
1169
|
return /* @__PURE__ */ jsxs(
|
|
1499
1170
|
"section",
|
|
1500
1171
|
{
|
|
@@ -1504,11 +1175,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1504
1175
|
style: {
|
|
1505
1176
|
position: "relative",
|
|
1506
1177
|
padding: `${pad}px 0`,
|
|
1507
|
-
background:
|
|
1178
|
+
background: isOverlay && !backgroundUrl ? "#DBEAFE" : void 0,
|
|
1508
1179
|
backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
|
|
1509
1180
|
backgroundSize: "cover",
|
|
1510
|
-
backgroundPosition: "center"
|
|
1511
|
-
color: settings.sectionBackground === "accent" ? resolvedBrand.palette.light : void 0
|
|
1181
|
+
backgroundPosition: "center"
|
|
1512
1182
|
},
|
|
1513
1183
|
children: [
|
|
1514
1184
|
/* @__PURE__ */ jsx("style", { children: AI_RESPONSIVE_CSS }),
|
|
@@ -1532,24 +1202,10 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1532
1202
|
display: "grid",
|
|
1533
1203
|
gridTemplateColumns: "repeat(12, 1fr)",
|
|
1534
1204
|
gap: AI_TREE_TOKENS.spacing6,
|
|
1535
|
-
alignItems:
|
|
1205
|
+
alignItems: settings.verticalPosition === "top" ? "start" : "center",
|
|
1536
1206
|
marginTop: r2 > 0 ? AI_TREE_TOKENS.spacing8 : 0
|
|
1537
1207
|
},
|
|
1538
|
-
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx(
|
|
1539
|
-
"div",
|
|
1540
|
-
{
|
|
1541
|
-
"data-ai-cell": "",
|
|
1542
|
-
style: {
|
|
1543
|
-
gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`,
|
|
1544
|
-
minWidth: 0,
|
|
1545
|
-
// space-between: each column becomes a flex column whose content spreads over
|
|
1546
|
-
// the full row height instead of clumping at the top.
|
|
1547
|
-
...distributed === "space-between" ? { display: "flex", flexDirection: "column", justifyContent: "space-between" } : {}
|
|
1548
|
-
},
|
|
1549
|
-
children: renderNode(block, ctx, `r${r2}.b${b}`)
|
|
1550
|
-
},
|
|
1551
|
-
b
|
|
1552
|
-
))
|
|
1208
|
+
children: (row.blocks ?? []).map((block, b) => /* @__PURE__ */ jsx("div", { style: { gridColumn: `span ${Math.min(12, Math.max(1, block.span))}`, minWidth: 0 }, children: renderNode(block, ctx, `r${r2}.b${b}`) }, b))
|
|
1553
1209
|
},
|
|
1554
1210
|
r2
|
|
1555
1211
|
))
|
|
@@ -1565,34 +1221,17 @@ import { jsx as jsx2 } from "react/jsx-runtime";
|
|
|
1565
1221
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1566
1222
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1567
1223
|
var REMOVED_ATTR = "data-ohw-ai-removed";
|
|
1568
|
-
function readRootVar(name) {
|
|
1569
|
-
if (typeof document === "undefined") return "";
|
|
1570
|
-
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
1571
|
-
}
|
|
1572
|
-
function deriveBrandOverride() {
|
|
1573
|
-
const dark = readRootVar("--ohw-brand-dark");
|
|
1574
|
-
const primary = readRootVar("--ohw-brand-primary");
|
|
1575
|
-
const light = readRootVar("--ohw-brand-light");
|
|
1576
|
-
if (!dark || !primary || !light) return null;
|
|
1577
|
-
const accent = readRootVar("--ohw-brand-accent");
|
|
1578
|
-
const heading = readRootVar("--font-heading") || readRootVar("--font-display");
|
|
1579
|
-
const body = readRootVar("--font-body");
|
|
1580
|
-
return {
|
|
1581
|
-
palette: { dark, primary, accent: accent || dark, light },
|
|
1582
|
-
fonts: {
|
|
1583
|
-
heading: heading || AI_DEFAULT_BRAND.fonts.heading,
|
|
1584
|
-
body: body || AI_DEFAULT_BRAND.fonts.body
|
|
1585
|
-
}
|
|
1586
|
-
};
|
|
1587
|
-
}
|
|
1588
1224
|
function deriveTemplateBrand() {
|
|
1589
|
-
|
|
1590
|
-
const
|
|
1591
|
-
const
|
|
1225
|
+
if (typeof document === "undefined") return null;
|
|
1226
|
+
const cs = getComputedStyle(document.documentElement);
|
|
1227
|
+
const read = (name) => cs.getPropertyValue(name).trim();
|
|
1228
|
+
const dark = read("--color-dark");
|
|
1229
|
+
const primary = read("--color-primary");
|
|
1230
|
+
const light = read("--color-light");
|
|
1592
1231
|
if (!dark || !primary || !light) return null;
|
|
1593
|
-
const accent =
|
|
1594
|
-
const heading =
|
|
1595
|
-
const body =
|
|
1232
|
+
const accent = read("--color-accent");
|
|
1233
|
+
const heading = read("--font-heading") || read("--font-display");
|
|
1234
|
+
const body = read("--font-body");
|
|
1596
1235
|
return {
|
|
1597
1236
|
palette: { dark, primary, accent: accent || dark, light },
|
|
1598
1237
|
fonts: {
|
|
@@ -1684,12 +1323,8 @@ function syncReplacedOriginals(state) {
|
|
|
1684
1323
|
}
|
|
1685
1324
|
function applyAiSectionsToDom(state, options) {
|
|
1686
1325
|
if (typeof document === "undefined") return;
|
|
1687
|
-
const brandOverride = deriveBrandOverride();
|
|
1688
1326
|
const templateBrand = deriveTemplateBrand();
|
|
1689
|
-
const
|
|
1690
|
-
const pagePath = window.location.pathname;
|
|
1691
|
-
const pageSections = state.sections.filter((entry) => !entry.path || entry.path === pagePath);
|
|
1692
|
-
const activeIds = new Set(pageSections.map((entry) => entry.id));
|
|
1327
|
+
const activeIds = new Set(state.sections.map((entry) => entry.id));
|
|
1693
1328
|
for (const [id, section] of mounted) {
|
|
1694
1329
|
if (!activeIds.has(id)) {
|
|
1695
1330
|
section.root.unmount();
|
|
@@ -1697,8 +1332,8 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1697
1332
|
mounted.delete(id);
|
|
1698
1333
|
}
|
|
1699
1334
|
}
|
|
1700
|
-
for (const entry of
|
|
1701
|
-
const serialized = JSON.stringify(entry)
|
|
1335
|
+
for (const entry of state.sections) {
|
|
1336
|
+
const serialized = JSON.stringify(entry);
|
|
1702
1337
|
const existing = mounted.get(entry.id);
|
|
1703
1338
|
if (existing && existing.serialized === serialized && existing.container.isConnected) {
|
|
1704
1339
|
continue;
|
|
@@ -1712,7 +1347,6 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1712
1347
|
mounted.delete(entry.id);
|
|
1713
1348
|
}
|
|
1714
1349
|
container.setAttribute("data-ohw-section", entry.id);
|
|
1715
|
-
container.setAttribute("data-ohw-instance", entry.id);
|
|
1716
1350
|
container.setAttribute("data-ohw-section-label", entry.label);
|
|
1717
1351
|
placeContainer(container, entry);
|
|
1718
1352
|
const root = mounted.get(entry.id)?.root ?? createRoot(container);
|
|
@@ -1723,7 +1357,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1723
1357
|
AiTreeRenderer,
|
|
1724
1358
|
{
|
|
1725
1359
|
tree: entry.tree,
|
|
1726
|
-
brand:
|
|
1360
|
+
brand: entry.brand ?? options?.brand ?? templateBrand ?? void 0,
|
|
1727
1361
|
resolveMedia,
|
|
1728
1362
|
editKeyPrefix: `ai.${entry.id}`
|
|
1729
1363
|
}
|
|
@@ -2340,7 +1974,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
2340
1974
|
const autoId = useId();
|
|
2341
1975
|
const insertAfter = insertAfterProp ?? autoId;
|
|
2342
1976
|
const [schedule, setSchedule] = useState2(null);
|
|
2343
|
-
const [loading, setLoading] = useState2(
|
|
1977
|
+
const [loading, setLoading] = useState2(true);
|
|
2344
1978
|
const [inEditor, setInEditor] = useState2(false);
|
|
2345
1979
|
const [isHovered, setIsHovered] = useState2(false);
|
|
2346
1980
|
const [modalState, setModalState] = useState2(null);
|
|
@@ -2514,10 +2148,8 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
|
|
|
2514
2148
|
"*"
|
|
2515
2149
|
);
|
|
2516
2150
|
};
|
|
2151
|
+
if (!inEditor && !loading && !schedule) return null;
|
|
2517
2152
|
const sectionId = `scheduling-${insertAfter}`;
|
|
2518
|
-
if (!inEditor && !loading && !schedule) {
|
|
2519
|
-
return /* @__PURE__ */ jsx4("section", { "data-ohw-section": sectionId, "data-ohw-scheduling-anchor": insertAfter, style: { display: "none" } });
|
|
2520
|
-
}
|
|
2521
2153
|
return /* @__PURE__ */ jsxs3(
|
|
2522
2154
|
"section",
|
|
2523
2155
|
{
|
|
@@ -6515,6 +6147,7 @@ function getChromeStyle(state) {
|
|
|
6515
6147
|
}
|
|
6516
6148
|
function ClampedToolbarSlot({
|
|
6517
6149
|
placement,
|
|
6150
|
+
align = "center",
|
|
6518
6151
|
children
|
|
6519
6152
|
}) {
|
|
6520
6153
|
const slotRef = useRef2(null);
|
|
@@ -6536,7 +6169,7 @@ function ClampedToolbarSlot({
|
|
|
6536
6169
|
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN - half)
|
|
6537
6170
|
);
|
|
6538
6171
|
const offsetX = clampedCenter - centerX;
|
|
6539
|
-
slot.style.transform = `translateX(calc(-50% + ${offsetX}px))`;
|
|
6172
|
+
slot.style.transform = align === "left" ? "none" : `translateX(calc(-50% + ${offsetX}px))`;
|
|
6540
6173
|
};
|
|
6541
6174
|
clamp();
|
|
6542
6175
|
const ro = new ResizeObserver(clamp);
|
|
@@ -6547,19 +6180,20 @@ function ClampedToolbarSlot({
|
|
|
6547
6180
|
ro.disconnect();
|
|
6548
6181
|
window.removeEventListener("resize", clamp);
|
|
6549
6182
|
};
|
|
6550
|
-
}, [placement, children]);
|
|
6183
|
+
}, [placement, children, align]);
|
|
6551
6184
|
return /* @__PURE__ */ jsx12(
|
|
6552
6185
|
"div",
|
|
6553
6186
|
{
|
|
6554
6187
|
ref: slotRef,
|
|
6555
6188
|
className: cn(
|
|
6556
|
-
"pointer-events-auto absolute
|
|
6189
|
+
"pointer-events-auto absolute",
|
|
6190
|
+
align === "left" ? "left-0" : "left-1/2",
|
|
6557
6191
|
placement === "top" ? "bottom-full" : "top-full"
|
|
6558
6192
|
),
|
|
6559
6193
|
style: {
|
|
6560
6194
|
marginBottom: placement === "top" ? TOOLBAR_STROKE_GAP : void 0,
|
|
6561
6195
|
marginTop: placement === "bottom" ? TOOLBAR_STROKE_GAP : void 0,
|
|
6562
|
-
transform: "translateX(-50%)"
|
|
6196
|
+
transform: align === "left" ? "none" : "translateX(-50%)"
|
|
6563
6197
|
},
|
|
6564
6198
|
"data-ohw-item-toolbar-anchor": placement,
|
|
6565
6199
|
children
|
|
@@ -6628,6 +6262,7 @@ function ItemInteractionLayer({
|
|
|
6628
6262
|
onItemClick,
|
|
6629
6263
|
itemDragSurface = true,
|
|
6630
6264
|
chromeGap,
|
|
6265
|
+
toolbarAlign = "center",
|
|
6631
6266
|
className
|
|
6632
6267
|
}) {
|
|
6633
6268
|
if (state === "default") return null;
|
|
@@ -6715,8 +6350,8 @@ function ItemInteractionLayer({
|
|
|
6715
6350
|
)
|
|
6716
6351
|
}
|
|
6717
6352
|
),
|
|
6718
|
-
showToolbar && state === "active-top" && /* @__PURE__ */ jsx12(ClampedToolbarSlot, { placement: "top", children: toolbar }),
|
|
6719
|
-
showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ jsx12(ClampedToolbarSlot, { placement: "bottom", children: toolbar }),
|
|
6353
|
+
showToolbar && state === "active-top" && /* @__PURE__ */ jsx12(ClampedToolbarSlot, { align: toolbarAlign, placement: "top", children: toolbar }),
|
|
6354
|
+
showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ jsx12(ClampedToolbarSlot, { align: toolbarAlign, placement: "bottom", children: toolbar }),
|
|
6720
6355
|
useDetachedBelowToolbar && toolbarBelowRect ? /* @__PURE__ */ jsx12(
|
|
6721
6356
|
DetachedBelowToolbarSlot,
|
|
6722
6357
|
{
|
|
@@ -6730,6 +6365,616 @@ function ItemInteractionLayer({
|
|
|
6730
6365
|
);
|
|
6731
6366
|
}
|
|
6732
6367
|
|
|
6368
|
+
// src/lib/forms.ts
|
|
6369
|
+
var FORM_SELECTOR = '[data-ohw-editable="form"]';
|
|
6370
|
+
function getFormElement(el) {
|
|
6371
|
+
if (!el) return null;
|
|
6372
|
+
return el.closest(FORM_SELECTOR);
|
|
6373
|
+
}
|
|
6374
|
+
function formKeyOf(form) {
|
|
6375
|
+
return form.getAttribute("data-ohw-key");
|
|
6376
|
+
}
|
|
6377
|
+
function formHasLongText(form) {
|
|
6378
|
+
return form.querySelector("textarea") !== null;
|
|
6379
|
+
}
|
|
6380
|
+
function collectFormFields(form) {
|
|
6381
|
+
const fields = {};
|
|
6382
|
+
form.querySelectorAll(
|
|
6383
|
+
"input, textarea, select"
|
|
6384
|
+
).forEach((input) => {
|
|
6385
|
+
const type = input.type;
|
|
6386
|
+
if (type === "submit" || type === "button" || type === "reset") return;
|
|
6387
|
+
const key = input.getAttribute("name") ?? input.getAttribute("data-ohw-key");
|
|
6388
|
+
if (!key) return;
|
|
6389
|
+
if (type === "checkbox") {
|
|
6390
|
+
fields[key] = input.checked ? "yes" : "no";
|
|
6391
|
+
return;
|
|
6392
|
+
}
|
|
6393
|
+
fields[key] = input.value;
|
|
6394
|
+
});
|
|
6395
|
+
return fields;
|
|
6396
|
+
}
|
|
6397
|
+
function formStateContainer(form) {
|
|
6398
|
+
return form.closest("[data-ohw-editable-state]") ?? form.parentElement ?? form;
|
|
6399
|
+
}
|
|
6400
|
+
function showSuccess(form, message) {
|
|
6401
|
+
const container = formStateContainer(form);
|
|
6402
|
+
const views = container.querySelectorAll("[data-ohw-state-view]");
|
|
6403
|
+
if (views.length > 0) {
|
|
6404
|
+
views.forEach((view) => {
|
|
6405
|
+
view.style.display = view.getAttribute("data-ohw-state-view") === "success" ? "block" : "none";
|
|
6406
|
+
});
|
|
6407
|
+
return;
|
|
6408
|
+
}
|
|
6409
|
+
const text = message || form.getAttribute("data-ohw-success-text") || DEFAULT_SUCCESS_TEXT;
|
|
6410
|
+
const note = document.createElement("p");
|
|
6411
|
+
note.setAttribute("data-ohw-form-success", "");
|
|
6412
|
+
note.setAttribute("role", "status");
|
|
6413
|
+
note.innerHTML = text;
|
|
6414
|
+
form.replaceChildren(note);
|
|
6415
|
+
}
|
|
6416
|
+
function showSubmitError(form, message = "Something went wrong. Please try again.") {
|
|
6417
|
+
let note = form.querySelector("[data-ohw-form-error]");
|
|
6418
|
+
if (!note) {
|
|
6419
|
+
note = document.createElement("p");
|
|
6420
|
+
note.setAttribute("data-ohw-form-error", "");
|
|
6421
|
+
note.setAttribute("role", "alert");
|
|
6422
|
+
note.style.marginTop = "8px";
|
|
6423
|
+
form.appendChild(note);
|
|
6424
|
+
}
|
|
6425
|
+
note.textContent = message;
|
|
6426
|
+
note.style.display = "";
|
|
6427
|
+
}
|
|
6428
|
+
function clearSubmitError(form) {
|
|
6429
|
+
const note = form.querySelector("[data-ohw-form-error]");
|
|
6430
|
+
if (note) note.style.display = "none";
|
|
6431
|
+
}
|
|
6432
|
+
var SUCCESS_TEXT_ATTR = "data-ohw-form-success-text";
|
|
6433
|
+
var HIDDEN_ATTR = "data-ohw-form-hidden";
|
|
6434
|
+
var DEFAULT_SUCCESS_TEXT = "Thanks! We'll be in touch.";
|
|
6435
|
+
function formSuccessKey(formKey) {
|
|
6436
|
+
return `${formKey}-success`;
|
|
6437
|
+
}
|
|
6438
|
+
function ensureSuccessTextEl(form, formKey, initialText) {
|
|
6439
|
+
let el = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
|
|
6440
|
+
if (el) return el;
|
|
6441
|
+
el = document.createElement("p");
|
|
6442
|
+
el.setAttribute(SUCCESS_TEXT_ATTR, "");
|
|
6443
|
+
el.setAttribute("data-ohw-editable", "text");
|
|
6444
|
+
el.setAttribute("data-ohw-key", formSuccessKey(formKey));
|
|
6445
|
+
el.innerHTML = initialText;
|
|
6446
|
+
el.style.display = "none";
|
|
6447
|
+
el.style.margin = "56px 4px 16px";
|
|
6448
|
+
form.appendChild(el);
|
|
6449
|
+
return el;
|
|
6450
|
+
}
|
|
6451
|
+
function successInitialFor(form, formKey, content) {
|
|
6452
|
+
return content[formSuccessKey(formKey)] || form.getAttribute("data-ohw-success-text") || DEFAULT_SUCCESS_TEXT;
|
|
6453
|
+
}
|
|
6454
|
+
function setFormViewState(form, formKey, state, initialText) {
|
|
6455
|
+
const success = ensureSuccessTextEl(form, formKey, initialText);
|
|
6456
|
+
Array.from(form.children).forEach((child) => {
|
|
6457
|
+
if (!(child instanceof HTMLElement) || child === success) return;
|
|
6458
|
+
if (state === "success") {
|
|
6459
|
+
if (!child.hasAttribute(HIDDEN_ATTR)) {
|
|
6460
|
+
child.setAttribute(HIDDEN_ATTR, child.style.display);
|
|
6461
|
+
child.style.display = "none";
|
|
6462
|
+
}
|
|
6463
|
+
} else if (child.hasAttribute(HIDDEN_ATTR)) {
|
|
6464
|
+
child.style.display = child.getAttribute(HIDDEN_ATTR) ?? "";
|
|
6465
|
+
child.removeAttribute(HIDDEN_ATTR);
|
|
6466
|
+
}
|
|
6467
|
+
});
|
|
6468
|
+
success.style.display = state === "success" ? "" : "none";
|
|
6469
|
+
}
|
|
6470
|
+
var BOUND_ATTR = "data-ohw-form-bound";
|
|
6471
|
+
var publishedFormContext = {
|
|
6472
|
+
apiUrl: "",
|
|
6473
|
+
subdomain: "",
|
|
6474
|
+
content: {}
|
|
6475
|
+
};
|
|
6476
|
+
function bindPublishedForms(apiUrl, subdomain, content = {}) {
|
|
6477
|
+
publishedFormContext = { apiUrl, subdomain, content };
|
|
6478
|
+
if (document.documentElement.hasAttribute(BOUND_ATTR)) return;
|
|
6479
|
+
document.documentElement.setAttribute(BOUND_ATTR, "");
|
|
6480
|
+
document.addEventListener(
|
|
6481
|
+
"submit",
|
|
6482
|
+
async (e) => {
|
|
6483
|
+
const target = e.target;
|
|
6484
|
+
const form = target?.closest(FORM_SELECTOR);
|
|
6485
|
+
if (!form || !(form instanceof HTMLFormElement)) return;
|
|
6486
|
+
const formKey = formKeyOf(form);
|
|
6487
|
+
if (!formKey) return;
|
|
6488
|
+
e.preventDefault();
|
|
6489
|
+
clearSubmitError(form);
|
|
6490
|
+
const filled = collectFormFields(form);
|
|
6491
|
+
if (!Object.values(filled).some((value) => value.trim() !== "")) {
|
|
6492
|
+
showSubmitError(form, "Please fill in at least one field.");
|
|
6493
|
+
return;
|
|
6494
|
+
}
|
|
6495
|
+
const submitButton = form.querySelector(
|
|
6496
|
+
'button[type="submit"], input[type="submit"], button:not([type])'
|
|
6497
|
+
);
|
|
6498
|
+
if (submitButton) submitButton.disabled = true;
|
|
6499
|
+
try {
|
|
6500
|
+
const { apiUrl: api, subdomain: site, content: latest } = publishedFormContext;
|
|
6501
|
+
const response = await fetch(`${api}/api/public/sites/${site}/forms/submissions`, {
|
|
6502
|
+
method: "POST",
|
|
6503
|
+
headers: { "Content-Type": "application/json" },
|
|
6504
|
+
body: JSON.stringify({
|
|
6505
|
+
formKey,
|
|
6506
|
+
fields: filled,
|
|
6507
|
+
hasLongText: formHasLongText(form)
|
|
6508
|
+
})
|
|
6509
|
+
});
|
|
6510
|
+
if (!response.ok) throw new Error(`submit failed: ${response.status}`);
|
|
6511
|
+
showSuccess(form, latest[formSuccessKey(formKey)]);
|
|
6512
|
+
} catch {
|
|
6513
|
+
showSubmitError(form);
|
|
6514
|
+
if (submitButton) submitButton.disabled = false;
|
|
6515
|
+
}
|
|
6516
|
+
},
|
|
6517
|
+
true
|
|
6518
|
+
);
|
|
6519
|
+
}
|
|
6520
|
+
|
|
6521
|
+
// src/lib/form-fields.ts
|
|
6522
|
+
var FIELD_DEFAULTS = {
|
|
6523
|
+
"short-text": { label: "Short text", placeholder: "Type placeholder text..." },
|
|
6524
|
+
"long-text": { label: "Long text", placeholder: "How can we help?" },
|
|
6525
|
+
email: { label: "Email", placeholder: "hello@example.com" },
|
|
6526
|
+
phone: { label: "Phone number", placeholder: "(555) 000-0000" }
|
|
6527
|
+
};
|
|
6528
|
+
var FIELD_TYPES = [
|
|
6529
|
+
{ type: "short-text", label: "Short text" },
|
|
6530
|
+
{ type: "long-text", label: "Long text" },
|
|
6531
|
+
{ type: "email", label: "Email" },
|
|
6532
|
+
{ type: "phone", label: "Phone" }
|
|
6533
|
+
];
|
|
6534
|
+
var FIELD_ATTR = "data-ohw-form-field";
|
|
6535
|
+
var FIELD_TYPE_ATTR = "data-ohw-field-type";
|
|
6536
|
+
var PLACEHOLDER_EDIT_ATTR = "data-ohw-placeholder-edit";
|
|
6537
|
+
function fieldsKey(formKey) {
|
|
6538
|
+
return `${formKey}-fields`;
|
|
6539
|
+
}
|
|
6540
|
+
function inputTagFor(type) {
|
|
6541
|
+
if (type === "long-text") return { tag: "textarea" };
|
|
6542
|
+
if (type === "email") return { tag: "input", inputType: "email" };
|
|
6543
|
+
if (type === "phone") return { tag: "input", inputType: "tel" };
|
|
6544
|
+
return { tag: "input", inputType: "text" };
|
|
6545
|
+
}
|
|
6546
|
+
function inferType(input) {
|
|
6547
|
+
if (input.tagName === "TEXTAREA") return "long-text";
|
|
6548
|
+
const type = input.type;
|
|
6549
|
+
if (type === "email") return "email";
|
|
6550
|
+
if (type === "tel") return "phone";
|
|
6551
|
+
return "short-text";
|
|
6552
|
+
}
|
|
6553
|
+
function ensureFieldLabel(wrapper, key) {
|
|
6554
|
+
const existing = fieldLabelOf(wrapper);
|
|
6555
|
+
if (existing) {
|
|
6556
|
+
if (!existing.hasAttribute("data-ohw-editable")) {
|
|
6557
|
+
existing.setAttribute("data-ohw-editable", "text");
|
|
6558
|
+
existing.setAttribute("data-ohw-key", `${key}-label`);
|
|
6559
|
+
}
|
|
6560
|
+
return existing;
|
|
6561
|
+
}
|
|
6562
|
+
const input = fieldInputOf(wrapper);
|
|
6563
|
+
const label = document.createElement("label");
|
|
6564
|
+
label.setAttribute("data-ohw-editable", "text");
|
|
6565
|
+
label.setAttribute("data-ohw-key", `${key}-label`);
|
|
6566
|
+
label.setAttribute("data-ohw-field-label", "");
|
|
6567
|
+
label.style.display = "block";
|
|
6568
|
+
label.style.marginBottom = "6px";
|
|
6569
|
+
label.style.fontSize = "13px";
|
|
6570
|
+
label.style.fontWeight = "500";
|
|
6571
|
+
label.style.lineHeight = "1.3";
|
|
6572
|
+
const fromPlaceholder = input?.getAttribute("placeholder")?.trim();
|
|
6573
|
+
const text = fromPlaceholder && fromPlaceholder.length < 40 ? fromPlaceholder : key.replace(/[-_]/g, " ");
|
|
6574
|
+
label.textContent = text;
|
|
6575
|
+
if (input && input.parentElement === wrapper) wrapper.insertBefore(label, input);
|
|
6576
|
+
else wrapper.insertBefore(label, wrapper.firstChild);
|
|
6577
|
+
return label;
|
|
6578
|
+
}
|
|
6579
|
+
function listFieldWrappers(form) {
|
|
6580
|
+
return Array.from(form.querySelectorAll(`[${FIELD_ATTR}]`));
|
|
6581
|
+
}
|
|
6582
|
+
function getFieldWrapper(el) {
|
|
6583
|
+
return el?.closest(`[${FIELD_ATTR}]`) ?? null;
|
|
6584
|
+
}
|
|
6585
|
+
function fieldInputOf(wrapper) {
|
|
6586
|
+
return wrapper.querySelector("input, textarea");
|
|
6587
|
+
}
|
|
6588
|
+
function fieldLabelOf(wrapper) {
|
|
6589
|
+
return wrapper.querySelector("label");
|
|
6590
|
+
}
|
|
6591
|
+
function fieldKeyOf(wrapper) {
|
|
6592
|
+
return wrapper.getAttribute(FIELD_ATTR) ?? "";
|
|
6593
|
+
}
|
|
6594
|
+
function fieldTypeOf(wrapper) {
|
|
6595
|
+
return wrapper.getAttribute(FIELD_TYPE_ATTR) ?? "short-text";
|
|
6596
|
+
}
|
|
6597
|
+
function isFieldRequired(wrapper) {
|
|
6598
|
+
return fieldInputOf(wrapper)?.hasAttribute("required") ?? false;
|
|
6599
|
+
}
|
|
6600
|
+
function markFormFields(form) {
|
|
6601
|
+
form.querySelectorAll("input, textarea").forEach((input) => {
|
|
6602
|
+
const type = input.type;
|
|
6603
|
+
if (type === "submit" || type === "button" || type === "reset" || type === "hidden") return;
|
|
6604
|
+
if (getFieldWrapper(input)) return;
|
|
6605
|
+
let wrapper = input;
|
|
6606
|
+
while (wrapper.parentElement && wrapper.parentElement !== form && wrapper.parentElement.querySelectorAll("input, textarea").length === 1) {
|
|
6607
|
+
wrapper = wrapper.parentElement;
|
|
6608
|
+
}
|
|
6609
|
+
if (wrapper === input) {
|
|
6610
|
+
const box = document.createElement("div");
|
|
6611
|
+
box.setAttribute("data-ohw-field-box", "");
|
|
6612
|
+
input.replaceWith(box);
|
|
6613
|
+
box.appendChild(input);
|
|
6614
|
+
wrapper = box;
|
|
6615
|
+
}
|
|
6616
|
+
const key = input.getAttribute("name") ?? input.getAttribute("data-ohw-key") ?? `field-${Date.now()}`;
|
|
6617
|
+
wrapper.setAttribute(FIELD_ATTR, key);
|
|
6618
|
+
wrapper.setAttribute(FIELD_TYPE_ATTR, inferType(input));
|
|
6619
|
+
ensureFieldLabel(wrapper, key);
|
|
6620
|
+
syncRequiredMark(wrapper);
|
|
6621
|
+
});
|
|
6622
|
+
return listFieldWrappers(form);
|
|
6623
|
+
}
|
|
6624
|
+
function readFieldsFromDom(form) {
|
|
6625
|
+
return listFieldWrappers(form).map((wrapper) => {
|
|
6626
|
+
const input = fieldInputOf(wrapper);
|
|
6627
|
+
return {
|
|
6628
|
+
key: fieldKeyOf(wrapper),
|
|
6629
|
+
type: fieldTypeOf(wrapper),
|
|
6630
|
+
label: fieldLabelText(fieldLabelOf(wrapper)).trim(),
|
|
6631
|
+
// While a field is selected its placeholder text lives in the value (see
|
|
6632
|
+
// beginPlaceholderEdit), so reading the attribute would store an empty one — whoever
|
|
6633
|
+
// happens to save at that moment must still record what the owner typed.
|
|
6634
|
+
placeholder: input ? input.hasAttribute(PLACEHOLDER_EDIT_ATTR) ? input.value : input.getAttribute("placeholder") ?? "" : "",
|
|
6635
|
+
required: Boolean(input?.hasAttribute("required"))
|
|
6636
|
+
};
|
|
6637
|
+
});
|
|
6638
|
+
}
|
|
6639
|
+
function parseFieldSpecs(raw) {
|
|
6640
|
+
if (!raw) return null;
|
|
6641
|
+
try {
|
|
6642
|
+
const parsed = JSON.parse(raw);
|
|
6643
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
6644
|
+
} catch {
|
|
6645
|
+
return null;
|
|
6646
|
+
}
|
|
6647
|
+
}
|
|
6648
|
+
function isDefaultText(value, pick) {
|
|
6649
|
+
const trimmed = value.trim().replace(/\s*\*$/, "");
|
|
6650
|
+
if (!trimmed) return true;
|
|
6651
|
+
return Object.values(FIELD_DEFAULTS).some((defaults) => pick(defaults) === trimmed);
|
|
6652
|
+
}
|
|
6653
|
+
function applyFieldType(wrapper, type) {
|
|
6654
|
+
const input = fieldInputOf(wrapper);
|
|
6655
|
+
if (!input) return;
|
|
6656
|
+
const defaults = FIELD_DEFAULTS[type];
|
|
6657
|
+
const placeholder = input.getAttribute("placeholder") ?? "";
|
|
6658
|
+
const label = fieldLabelOf(wrapper);
|
|
6659
|
+
const followsDefaults = {
|
|
6660
|
+
// A label the owner wrote stays; one that still reads as a type name (or as the old
|
|
6661
|
+
// placeholder the template shipped) follows the new type.
|
|
6662
|
+
label: isDefaultText(label?.textContent ?? "", (d) => d.label) || fieldLabelText(label).trim() === placeholder.trim()
|
|
6663
|
+
};
|
|
6664
|
+
const { tag, inputType } = inputTagFor(type);
|
|
6665
|
+
wrapper.setAttribute(FIELD_TYPE_ATTR, type);
|
|
6666
|
+
const shedSize = (el) => {
|
|
6667
|
+
if (type === "long-text") return;
|
|
6668
|
+
el.style.removeProperty("height");
|
|
6669
|
+
el.style.removeProperty("min-height");
|
|
6670
|
+
el.style.removeProperty("resize");
|
|
6671
|
+
el.removeAttribute("rows");
|
|
6672
|
+
};
|
|
6673
|
+
const applyDefaults = (el) => {
|
|
6674
|
+
el.setAttribute("placeholder", defaults.placeholder);
|
|
6675
|
+
if (label && followsDefaults.label) {
|
|
6676
|
+
label.textContent = defaults.label;
|
|
6677
|
+
}
|
|
6678
|
+
};
|
|
6679
|
+
if (input.tagName.toLowerCase() === tag) {
|
|
6680
|
+
if (inputType) input.type = inputType;
|
|
6681
|
+
shedSize(input);
|
|
6682
|
+
applyDefaults(input);
|
|
6683
|
+
return;
|
|
6684
|
+
}
|
|
6685
|
+
const next = document.createElement(tag);
|
|
6686
|
+
Array.from(input.attributes).forEach((attr) => {
|
|
6687
|
+
if (attr.name === "type") return;
|
|
6688
|
+
next.setAttribute(attr.name, attr.value);
|
|
6689
|
+
});
|
|
6690
|
+
if (inputType) next.setAttribute("type", inputType);
|
|
6691
|
+
shedSize(next);
|
|
6692
|
+
if (type === "long-text") next.setAttribute("rows", "4");
|
|
6693
|
+
input.replaceWith(next);
|
|
6694
|
+
applyDefaults(next);
|
|
6695
|
+
}
|
|
6696
|
+
var REQUIRED_MARK_ATTR = "data-ohw-field-required";
|
|
6697
|
+
function fieldLabelText(label) {
|
|
6698
|
+
if (!label) return "";
|
|
6699
|
+
return (label.textContent ?? "").replace(/\s*\*\s*$/, "").trimEnd();
|
|
6700
|
+
}
|
|
6701
|
+
function syncRequiredMark(wrapper) {
|
|
6702
|
+
const label = fieldLabelOf(wrapper);
|
|
6703
|
+
if (!label) return;
|
|
6704
|
+
label.querySelectorAll("[data-ohw-required-mark]").forEach((el) => el.remove());
|
|
6705
|
+
const words = fieldLabelText(label);
|
|
6706
|
+
if ((label.textContent ?? "") !== words) label.textContent = words;
|
|
6707
|
+
if (isFieldRequired(wrapper)) label.setAttribute(REQUIRED_MARK_ATTR, "");
|
|
6708
|
+
else label.removeAttribute(REQUIRED_MARK_ATTR);
|
|
6709
|
+
}
|
|
6710
|
+
function setFieldRequired(wrapper, required) {
|
|
6711
|
+
const input = fieldInputOf(wrapper);
|
|
6712
|
+
const label = fieldLabelOf(wrapper);
|
|
6713
|
+
if (!input) return;
|
|
6714
|
+
if (required) input.setAttribute("required", "");
|
|
6715
|
+
else input.removeAttribute("required");
|
|
6716
|
+
if (label) syncRequiredMark(wrapper);
|
|
6717
|
+
}
|
|
6718
|
+
function beginPlaceholderEdit(wrapper) {
|
|
6719
|
+
const input = fieldInputOf(wrapper);
|
|
6720
|
+
if (!input || input.hasAttribute(PLACEHOLDER_EDIT_ATTR)) return;
|
|
6721
|
+
input.setAttribute(PLACEHOLDER_EDIT_ATTR, "");
|
|
6722
|
+
input.value = input.getAttribute("placeholder") ?? "";
|
|
6723
|
+
input.setAttribute("placeholder", "");
|
|
6724
|
+
}
|
|
6725
|
+
function commitPlaceholderEdit(wrapper) {
|
|
6726
|
+
if (!wrapper) return false;
|
|
6727
|
+
const input = fieldInputOf(wrapper);
|
|
6728
|
+
if (!input || !input.hasAttribute(PLACEHOLDER_EDIT_ATTR)) return false;
|
|
6729
|
+
const typed = input.value;
|
|
6730
|
+
input.removeAttribute(PLACEHOLDER_EDIT_ATTR);
|
|
6731
|
+
input.value = "";
|
|
6732
|
+
const previous = input.getAttribute("placeholder") ?? "";
|
|
6733
|
+
input.setAttribute("placeholder", typed);
|
|
6734
|
+
return previous !== typed;
|
|
6735
|
+
}
|
|
6736
|
+
function setFieldPlaceholder(wrapper, placeholder) {
|
|
6737
|
+
fieldInputOf(wrapper)?.setAttribute("placeholder", placeholder);
|
|
6738
|
+
}
|
|
6739
|
+
function uniqueKey(form, base) {
|
|
6740
|
+
const taken = new Set(listFieldWrappers(form).map(fieldKeyOf));
|
|
6741
|
+
if (!taken.has(base)) return base;
|
|
6742
|
+
let n = 2;
|
|
6743
|
+
while (taken.has(`${base}-${n}`)) n += 1;
|
|
6744
|
+
return `${base}-${n}`;
|
|
6745
|
+
}
|
|
6746
|
+
function insertField(form, type) {
|
|
6747
|
+
const existing = listFieldWrappers(form);
|
|
6748
|
+
const source = existing[existing.length - 1] ?? null;
|
|
6749
|
+
const key = uniqueKey(form, type);
|
|
6750
|
+
let wrapper;
|
|
6751
|
+
if (source) {
|
|
6752
|
+
wrapper = source.cloneNode(true);
|
|
6753
|
+
source.after(wrapper);
|
|
6754
|
+
} else {
|
|
6755
|
+
wrapper = document.createElement("div");
|
|
6756
|
+
const label2 = document.createElement("label");
|
|
6757
|
+
const input2 = document.createElement("input");
|
|
6758
|
+
wrapper.append(label2, input2);
|
|
6759
|
+
const submit = form.querySelector('button, input[type="submit"]');
|
|
6760
|
+
if (submit) submit.before(wrapper);
|
|
6761
|
+
else form.appendChild(wrapper);
|
|
6762
|
+
}
|
|
6763
|
+
wrapper.setAttribute(FIELD_ATTR, key);
|
|
6764
|
+
wrapper.setAttribute(FIELD_TYPE_ATTR, type);
|
|
6765
|
+
applyFieldType(wrapper, type);
|
|
6766
|
+
const defaults = FIELD_DEFAULTS[type];
|
|
6767
|
+
const input = fieldInputOf(wrapper);
|
|
6768
|
+
if (input) {
|
|
6769
|
+
input.setAttribute("name", key);
|
|
6770
|
+
input.removeAttribute("required");
|
|
6771
|
+
input.setAttribute("placeholder", defaults.placeholder);
|
|
6772
|
+
input.value = "";
|
|
6773
|
+
}
|
|
6774
|
+
const label = ensureFieldLabel(wrapper, key);
|
|
6775
|
+
label.textContent = defaults.label;
|
|
6776
|
+
label.setAttribute("data-ohw-key", `${key}-label`);
|
|
6777
|
+
return wrapper;
|
|
6778
|
+
}
|
|
6779
|
+
function duplicateField(form, wrapper) {
|
|
6780
|
+
const copy = wrapper.cloneNode(true);
|
|
6781
|
+
const key = uniqueKey(form, `${fieldKeyOf(wrapper)}-copy`);
|
|
6782
|
+
copy.setAttribute(FIELD_ATTR, key);
|
|
6783
|
+
const input = fieldInputOf(copy);
|
|
6784
|
+
if (input) {
|
|
6785
|
+
input.setAttribute("name", key);
|
|
6786
|
+
input.removeAttribute("data-ohw-key");
|
|
6787
|
+
input.value = "";
|
|
6788
|
+
}
|
|
6789
|
+
const label = fieldLabelOf(copy);
|
|
6790
|
+
if (label) label.setAttribute("data-ohw-key", `${key}-label`);
|
|
6791
|
+
wrapper.after(copy);
|
|
6792
|
+
return copy;
|
|
6793
|
+
}
|
|
6794
|
+
function removeField(wrapper) {
|
|
6795
|
+
wrapper.remove();
|
|
6796
|
+
}
|
|
6797
|
+
function applyFieldOrder(form, keys) {
|
|
6798
|
+
const wrappers = listFieldWrappers(form);
|
|
6799
|
+
const byKey = new Map(wrappers.map((wrapper) => [fieldKeyOf(wrapper), wrapper]));
|
|
6800
|
+
const ordered = keys.map((key) => byKey.get(key)).filter((w) => Boolean(w));
|
|
6801
|
+
if (ordered.length !== wrappers.length) return;
|
|
6802
|
+
const slots = wrappers.map((wrapper) => {
|
|
6803
|
+
const slot = document.createComment("ohw-field-slot");
|
|
6804
|
+
wrapper.replaceWith(slot);
|
|
6805
|
+
return slot;
|
|
6806
|
+
});
|
|
6807
|
+
ordered.forEach((wrapper, index) => slots[index].replaceWith(wrapper));
|
|
6808
|
+
}
|
|
6809
|
+
function moveField(form, key, toIndex) {
|
|
6810
|
+
const keys = listFieldWrappers(form).map(fieldKeyOf);
|
|
6811
|
+
const from = keys.indexOf(key);
|
|
6812
|
+
if (from === -1) return;
|
|
6813
|
+
const rest = keys.filter((k) => k !== key);
|
|
6814
|
+
rest.splice(Math.max(0, Math.min(rest.length, toIndex)), 0, key);
|
|
6815
|
+
applyFieldOrder(form, rest);
|
|
6816
|
+
}
|
|
6817
|
+
function reconcileFieldsFromContent(form, content) {
|
|
6818
|
+
const formKey = form.getAttribute("data-ohw-key");
|
|
6819
|
+
if (!formKey) return;
|
|
6820
|
+
markFormFields(form);
|
|
6821
|
+
const stored = parseFieldSpecs(content[fieldsKey(formKey)]);
|
|
6822
|
+
if (!stored) return;
|
|
6823
|
+
const byKey = new Map(listFieldWrappers(form).map((wrapper) => [fieldKeyOf(wrapper), wrapper]));
|
|
6824
|
+
stored.forEach((spec) => {
|
|
6825
|
+
let wrapper = byKey.get(spec.key) ?? null;
|
|
6826
|
+
if (!wrapper) {
|
|
6827
|
+
wrapper = insertField(form, spec.type);
|
|
6828
|
+
if (!wrapper) return;
|
|
6829
|
+
wrapper.setAttribute(FIELD_ATTR, spec.key);
|
|
6830
|
+
const input = fieldInputOf(wrapper);
|
|
6831
|
+
if (input) {
|
|
6832
|
+
input.setAttribute("name", spec.key);
|
|
6833
|
+
}
|
|
6834
|
+
fieldLabelOf(wrapper)?.setAttribute("data-ohw-key", `${spec.key}-label`);
|
|
6835
|
+
byKey.set(spec.key, wrapper);
|
|
6836
|
+
}
|
|
6837
|
+
applyFieldType(wrapper, spec.type);
|
|
6838
|
+
setFieldRequired(wrapper, spec.required);
|
|
6839
|
+
setFieldPlaceholder(wrapper, spec.placeholder);
|
|
6840
|
+
const label = fieldLabelOf(wrapper);
|
|
6841
|
+
if (label && spec.label) label.textContent = spec.label.replace(/\s*\*\s*$/, "").trimEnd();
|
|
6842
|
+
syncRequiredMark(wrapper);
|
|
6843
|
+
});
|
|
6844
|
+
const wanted = new Set(stored.map((spec) => spec.key));
|
|
6845
|
+
listFieldWrappers(form).forEach((wrapper) => {
|
|
6846
|
+
if (!wanted.has(fieldKeyOf(wrapper))) wrapper.remove();
|
|
6847
|
+
});
|
|
6848
|
+
const currentOrder = listFieldWrappers(form).map(fieldKeyOf).join("\0");
|
|
6849
|
+
const storedOrder = stored.map((spec) => spec.key).join("\0");
|
|
6850
|
+
if (currentOrder !== storedOrder) {
|
|
6851
|
+
applyFieldOrder(form, stored.map((spec) => spec.key));
|
|
6852
|
+
}
|
|
6853
|
+
}
|
|
6854
|
+
|
|
6855
|
+
// src/ui/form-field-toolbar.tsx
|
|
6856
|
+
import { AtSign, Asterisk, ChevronDown as ChevronDown2, Copy as Copy2, MoreHorizontal as MoreHorizontal2, Phone, TextQuote, Trash2 as Trash22, Type } from "lucide-react";
|
|
6857
|
+
import { jsx as jsx13, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
6858
|
+
var TYPE_ICONS = {
|
|
6859
|
+
"short-text": Type,
|
|
6860
|
+
"long-text": TextQuote,
|
|
6861
|
+
email: AtSign,
|
|
6862
|
+
phone: Phone
|
|
6863
|
+
};
|
|
6864
|
+
function FormFieldToolbar({
|
|
6865
|
+
type,
|
|
6866
|
+
required,
|
|
6867
|
+
onTypeChange,
|
|
6868
|
+
onRequiredToggle,
|
|
6869
|
+
onDuplicate,
|
|
6870
|
+
onDelete
|
|
6871
|
+
}) {
|
|
6872
|
+
const TypeIcon = TYPE_ICONS[type];
|
|
6873
|
+
const typeLabel = FIELD_TYPES.find((entry) => entry.type === type)?.label ?? "Short text";
|
|
6874
|
+
return /* @__PURE__ */ jsxs6(
|
|
6875
|
+
"div",
|
|
6876
|
+
{
|
|
6877
|
+
"data-ohw-field-toolbar": "",
|
|
6878
|
+
className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
|
|
6879
|
+
children: [
|
|
6880
|
+
/* @__PURE__ */ jsxs6(DropdownMenu, { children: [
|
|
6881
|
+
/* @__PURE__ */ jsx13(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs6(
|
|
6882
|
+
"button",
|
|
6883
|
+
{
|
|
6884
|
+
type: "button",
|
|
6885
|
+
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted/70",
|
|
6886
|
+
"data-ohw-field-type-trigger": "",
|
|
6887
|
+
children: [
|
|
6888
|
+
/* @__PURE__ */ jsx13(TypeIcon, { size: 14, strokeWidth: 1.75, "aria-hidden": true }),
|
|
6889
|
+
typeLabel,
|
|
6890
|
+
/* @__PURE__ */ jsx13(ChevronDown2, { size: 13, className: "text-muted-foreground", "aria-hidden": true })
|
|
6891
|
+
]
|
|
6892
|
+
}
|
|
6893
|
+
) }),
|
|
6894
|
+
/* @__PURE__ */ jsx13(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
|
|
6895
|
+
const Icon = TYPE_ICONS[entry.type];
|
|
6896
|
+
return /* @__PURE__ */ jsxs6(
|
|
6897
|
+
DropdownMenuItem,
|
|
6898
|
+
{
|
|
6899
|
+
onSelect: () => onTypeChange(entry.type),
|
|
6900
|
+
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
|
|
6901
|
+
children: [
|
|
6902
|
+
/* @__PURE__ */ jsx13(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
6903
|
+
entry.label
|
|
6904
|
+
]
|
|
6905
|
+
},
|
|
6906
|
+
entry.type
|
|
6907
|
+
);
|
|
6908
|
+
}) })
|
|
6909
|
+
] }),
|
|
6910
|
+
/* @__PURE__ */ jsx13("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
6911
|
+
/* @__PURE__ */ jsxs6(
|
|
6912
|
+
"button",
|
|
6913
|
+
{
|
|
6914
|
+
type: "button",
|
|
6915
|
+
"aria-pressed": required,
|
|
6916
|
+
onClick: onRequiredToggle,
|
|
6917
|
+
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-medium transition-colors " + (required ? "bg-primary/10 text-primary" : "text-foreground hover:bg-muted/70"),
|
|
6918
|
+
"data-ohw-field-required": "",
|
|
6919
|
+
children: [
|
|
6920
|
+
/* @__PURE__ */ jsx13(Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
|
|
6921
|
+
"Required"
|
|
6922
|
+
]
|
|
6923
|
+
}
|
|
6924
|
+
),
|
|
6925
|
+
/* @__PURE__ */ jsx13("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
6926
|
+
/* @__PURE__ */ jsxs6(DropdownMenu, { children: [
|
|
6927
|
+
/* @__PURE__ */ jsx13(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx13(
|
|
6928
|
+
"button",
|
|
6929
|
+
{
|
|
6930
|
+
type: "button",
|
|
6931
|
+
title: "More",
|
|
6932
|
+
"aria-label": "More",
|
|
6933
|
+
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/70",
|
|
6934
|
+
children: /* @__PURE__ */ jsx13(MoreHorizontal2, { size: 15, "aria-hidden": true })
|
|
6935
|
+
}
|
|
6936
|
+
) }),
|
|
6937
|
+
/* @__PURE__ */ jsxs6(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
|
|
6938
|
+
/* @__PURE__ */ jsxs6(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
|
|
6939
|
+
/* @__PURE__ */ jsx13(Copy2, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
6940
|
+
"Duplicate"
|
|
6941
|
+
] }),
|
|
6942
|
+
/* @__PURE__ */ jsxs6(DropdownMenuItem, { variant: "destructive", onSelect: onDelete, className: "rounded-md py-2 text-[13px]", children: [
|
|
6943
|
+
/* @__PURE__ */ jsx13(Trash22, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
6944
|
+
"Delete"
|
|
6945
|
+
] })
|
|
6946
|
+
] })
|
|
6947
|
+
] })
|
|
6948
|
+
]
|
|
6949
|
+
}
|
|
6950
|
+
);
|
|
6951
|
+
}
|
|
6952
|
+
function FieldTypePicker({ onPick }) {
|
|
6953
|
+
return /* @__PURE__ */ jsx13(
|
|
6954
|
+
"div",
|
|
6955
|
+
{
|
|
6956
|
+
"data-ohw-field-type-picker": "",
|
|
6957
|
+
className: "pointer-events-auto grid w-[420px] grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
|
|
6958
|
+
children: FIELD_TYPES.map((entry) => {
|
|
6959
|
+
const Icon = TYPE_ICONS[entry.type];
|
|
6960
|
+
return /* @__PURE__ */ jsxs6(
|
|
6961
|
+
"button",
|
|
6962
|
+
{
|
|
6963
|
+
type: "button",
|
|
6964
|
+
onClick: () => onPick(entry.type),
|
|
6965
|
+
className: "flex h-[104px] flex-col items-center justify-center gap-3 rounded-xl border border-border text-[15px] font-medium text-foreground transition-colors hover:border-primary hover:bg-primary/5",
|
|
6966
|
+
children: [
|
|
6967
|
+
/* @__PURE__ */ jsx13(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
|
|
6968
|
+
entry.label
|
|
6969
|
+
]
|
|
6970
|
+
},
|
|
6971
|
+
entry.type
|
|
6972
|
+
);
|
|
6973
|
+
})
|
|
6974
|
+
}
|
|
6975
|
+
);
|
|
6976
|
+
}
|
|
6977
|
+
|
|
6733
6978
|
// src/ui/MediaOverlay.tsx
|
|
6734
6979
|
import * as React7 from "react";
|
|
6735
6980
|
import { Film, ImageIcon, Pause, Play, Volume2, VolumeX } from "lucide-react";
|
|
@@ -6737,7 +6982,7 @@ import { Film, ImageIcon, Pause, Play, Volume2, VolumeX } from "lucide-react";
|
|
|
6737
6982
|
// src/ui/button.tsx
|
|
6738
6983
|
import * as React6 from "react";
|
|
6739
6984
|
import { Slot } from "radix-ui";
|
|
6740
|
-
import { jsx as
|
|
6985
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
6741
6986
|
var buttonVariants = cva(
|
|
6742
6987
|
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium transition-colors outline-none disabled:pointer-events-none disabled:opacity-50 min-w-[80px] px-3 py-2",
|
|
6743
6988
|
{
|
|
@@ -6761,7 +7006,7 @@ var buttonVariants = cva(
|
|
|
6761
7006
|
var Button = React6.forwardRef(
|
|
6762
7007
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
6763
7008
|
const Comp = asChild ? Slot.Root : "button";
|
|
6764
|
-
return /* @__PURE__ */
|
|
7009
|
+
return /* @__PURE__ */ jsx14(
|
|
6765
7010
|
Comp,
|
|
6766
7011
|
{
|
|
6767
7012
|
ref,
|
|
@@ -6775,7 +7020,7 @@ var Button = React6.forwardRef(
|
|
|
6775
7020
|
Button.displayName = "Button";
|
|
6776
7021
|
|
|
6777
7022
|
// src/ui/MediaOverlay.tsx
|
|
6778
|
-
import { Fragment as Fragment4, jsx as
|
|
7023
|
+
import { Fragment as Fragment4, jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
6779
7024
|
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
6780
7025
|
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
6781
7026
|
var OVERLAY_BUTTON_STYLE = {
|
|
@@ -6833,7 +7078,7 @@ function MediaOverlay({
|
|
|
6833
7078
|
return () => anim.cancel();
|
|
6834
7079
|
}, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
|
|
6835
7080
|
if (isUploading) {
|
|
6836
|
-
return /* @__PURE__ */
|
|
7081
|
+
return /* @__PURE__ */ jsx15(
|
|
6837
7082
|
"div",
|
|
6838
7083
|
{
|
|
6839
7084
|
ref: skeletonRef,
|
|
@@ -6842,11 +7087,11 @@ function MediaOverlay({
|
|
|
6842
7087
|
"data-ohw-media-skeleton": "",
|
|
6843
7088
|
"aria-hidden": true,
|
|
6844
7089
|
style: { ...box, pointerEvents: "none" },
|
|
6845
|
-
children: /* @__PURE__ */
|
|
7090
|
+
children: /* @__PURE__ */ jsx15("style", { children: SKELETON_CSS })
|
|
6846
7091
|
}
|
|
6847
7092
|
);
|
|
6848
7093
|
}
|
|
6849
|
-
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */
|
|
7094
|
+
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ jsxs7(
|
|
6850
7095
|
"div",
|
|
6851
7096
|
{
|
|
6852
7097
|
"data-ohw-bridge": "",
|
|
@@ -6862,7 +7107,7 @@ function MediaOverlay({
|
|
|
6862
7107
|
},
|
|
6863
7108
|
onClick: (e) => e.stopPropagation(),
|
|
6864
7109
|
children: [
|
|
6865
|
-
/* @__PURE__ */
|
|
7110
|
+
/* @__PURE__ */ jsx15(
|
|
6866
7111
|
Button,
|
|
6867
7112
|
{
|
|
6868
7113
|
"data-ohw-media-overlay": "",
|
|
@@ -6877,10 +7122,10 @@ function MediaOverlay({
|
|
|
6877
7122
|
e.stopPropagation();
|
|
6878
7123
|
onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
|
|
6879
7124
|
},
|
|
6880
|
-
children: autoplay ? /* @__PURE__ */
|
|
7125
|
+
children: autoplay ? /* @__PURE__ */ jsx15(Pause, { size: 14 }) : /* @__PURE__ */ jsx15(Play, { size: 14 })
|
|
6881
7126
|
}
|
|
6882
7127
|
),
|
|
6883
|
-
/* @__PURE__ */
|
|
7128
|
+
/* @__PURE__ */ jsx15(
|
|
6884
7129
|
Button,
|
|
6885
7130
|
{
|
|
6886
7131
|
"data-ohw-media-overlay": "",
|
|
@@ -6895,15 +7140,15 @@ function MediaOverlay({
|
|
|
6895
7140
|
e.stopPropagation();
|
|
6896
7141
|
onVideoSettingsChange?.(hover.key, { muted: !muted });
|
|
6897
7142
|
},
|
|
6898
|
-
children: muted ? /* @__PURE__ */
|
|
7143
|
+
children: muted ? /* @__PURE__ */ jsx15(VolumeX, { size: 14 }) : /* @__PURE__ */ jsx15(Volume2, { size: 14 })
|
|
6899
7144
|
}
|
|
6900
7145
|
)
|
|
6901
7146
|
]
|
|
6902
7147
|
}
|
|
6903
7148
|
) : null;
|
|
6904
|
-
return /* @__PURE__ */
|
|
7149
|
+
return /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
6905
7150
|
settingsBar,
|
|
6906
|
-
/* @__PURE__ */
|
|
7151
|
+
/* @__PURE__ */ jsx15(
|
|
6907
7152
|
"div",
|
|
6908
7153
|
{
|
|
6909
7154
|
"data-ohw-bridge": "",
|
|
@@ -6920,7 +7165,7 @@ function MediaOverlay({
|
|
|
6920
7165
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
6921
7166
|
},
|
|
6922
7167
|
onClick: () => onReplace(hover.key),
|
|
6923
|
-
children: /* @__PURE__ */
|
|
7168
|
+
children: /* @__PURE__ */ jsxs7(
|
|
6924
7169
|
Button,
|
|
6925
7170
|
{
|
|
6926
7171
|
"data-ohw-media-overlay": "",
|
|
@@ -6938,7 +7183,7 @@ function MediaOverlay({
|
|
|
6938
7183
|
onReplace(hover.key);
|
|
6939
7184
|
},
|
|
6940
7185
|
children: [
|
|
6941
|
-
isVideo ? /* @__PURE__ */
|
|
7186
|
+
isVideo ? /* @__PURE__ */ jsx15(Film, { size: 14 }) : /* @__PURE__ */ jsx15(ImageIcon, { size: 14 }),
|
|
6942
7187
|
isVideo ? "Replace video" : "Replace image"
|
|
6943
7188
|
]
|
|
6944
7189
|
}
|
|
@@ -6950,7 +7195,7 @@ function MediaOverlay({
|
|
|
6950
7195
|
|
|
6951
7196
|
// src/ui/CarouselOverlay.tsx
|
|
6952
7197
|
import { GalleryHorizontal } from "lucide-react";
|
|
6953
|
-
import { jsx as
|
|
7198
|
+
import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
6954
7199
|
var OVERLAY_BUTTON_STYLE2 = {
|
|
6955
7200
|
pointerEvents: "auto",
|
|
6956
7201
|
fontFamily: "Inter, sans-serif",
|
|
@@ -6962,7 +7207,7 @@ function CarouselOverlay({
|
|
|
6962
7207
|
onEdit
|
|
6963
7208
|
}) {
|
|
6964
7209
|
const { rect } = hover;
|
|
6965
|
-
return /* @__PURE__ */
|
|
7210
|
+
return /* @__PURE__ */ jsx16(
|
|
6966
7211
|
"div",
|
|
6967
7212
|
{
|
|
6968
7213
|
"data-ohw-bridge": "",
|
|
@@ -6980,7 +7225,7 @@ function CarouselOverlay({
|
|
|
6980
7225
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
6981
7226
|
},
|
|
6982
7227
|
onClick: () => onEdit(hover.key),
|
|
6983
|
-
children: /* @__PURE__ */
|
|
7228
|
+
children: /* @__PURE__ */ jsxs8(
|
|
6984
7229
|
Button,
|
|
6985
7230
|
{
|
|
6986
7231
|
"data-ohw-carousel-overlay": "",
|
|
@@ -6994,7 +7239,7 @@ function CarouselOverlay({
|
|
|
6994
7239
|
onEdit(hover.key);
|
|
6995
7240
|
},
|
|
6996
7241
|
children: [
|
|
6997
|
-
/* @__PURE__ */
|
|
7242
|
+
/* @__PURE__ */ jsx16(GalleryHorizontal, { size: 14 }),
|
|
6998
7243
|
"Edit gallery"
|
|
6999
7244
|
]
|
|
7000
7245
|
}
|
|
@@ -7035,13 +7280,9 @@ function parseSectionsFromHtml(html) {
|
|
|
7035
7280
|
}
|
|
7036
7281
|
|
|
7037
7282
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
7038
|
-
import { Fragment as Fragment5, jsx as
|
|
7039
|
-
function
|
|
7040
|
-
const
|
|
7041
|
-
return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
|
|
7042
|
-
}
|
|
7043
|
-
function readRect(instanceId) {
|
|
7044
|
-
const el = findSectionElement(instanceId);
|
|
7283
|
+
import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
7284
|
+
function readRect(sectionId) {
|
|
7285
|
+
const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
|
|
7045
7286
|
if (!el) return null;
|
|
7046
7287
|
const r2 = el.getBoundingClientRect();
|
|
7047
7288
|
if (r2.width <= 0 || r2.height <= 0) return null;
|
|
@@ -7064,7 +7305,7 @@ function useLiveSectionRect(sectionId) {
|
|
|
7064
7305
|
const opts = { capture: true, passive: true };
|
|
7065
7306
|
window.addEventListener("scroll", update, opts);
|
|
7066
7307
|
window.addEventListener("resize", update);
|
|
7067
|
-
const el =
|
|
7308
|
+
const el = document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`);
|
|
7068
7309
|
const ro = el ? new ResizeObserver(update) : null;
|
|
7069
7310
|
if (el && ro) ro.observe(el);
|
|
7070
7311
|
const interval = setInterval(update, 500);
|
|
@@ -7077,14 +7318,6 @@ function useLiveSectionRect(sectionId) {
|
|
|
7077
7318
|
}, [sectionId]);
|
|
7078
7319
|
return rect;
|
|
7079
7320
|
}
|
|
7080
|
-
function computeSectionBoundaryFlags(instanceId) {
|
|
7081
|
-
const topLevel = Array.from(document.querySelectorAll("[data-ohw-section]")).filter(
|
|
7082
|
-
(el) => !el.parentElement?.closest("[data-ohw-section]")
|
|
7083
|
-
);
|
|
7084
|
-
const index = topLevel.findIndex((el) => (el.dataset.ohwInstance ?? el.dataset.ohwSection) === instanceId);
|
|
7085
|
-
if (index === -1) return { isFirst: true, isLast: true };
|
|
7086
|
-
return { isFirst: index === 0, isLast: index === topLevel.length - 1 };
|
|
7087
|
-
}
|
|
7088
7321
|
var PRIMARY2 = "#0885FE";
|
|
7089
7322
|
function edgeAwareRadius(rect) {
|
|
7090
7323
|
const container = window.innerWidth <= 480 ? 16 : 24;
|
|
@@ -7103,8 +7336,8 @@ function ReviewButton({
|
|
|
7103
7336
|
color
|
|
7104
7337
|
}) {
|
|
7105
7338
|
const [hover, setHover] = useState4(false);
|
|
7106
|
-
return /* @__PURE__ */
|
|
7107
|
-
/* @__PURE__ */
|
|
7339
|
+
return /* @__PURE__ */ jsxs9("div", { style: { position: "relative" }, children: [
|
|
7340
|
+
/* @__PURE__ */ jsx17(
|
|
7108
7341
|
"button",
|
|
7109
7342
|
{
|
|
7110
7343
|
type: "button",
|
|
@@ -7128,7 +7361,7 @@ function ReviewButton({
|
|
|
7128
7361
|
children
|
|
7129
7362
|
}
|
|
7130
7363
|
),
|
|
7131
|
-
hover && /* @__PURE__ */
|
|
7364
|
+
hover && /* @__PURE__ */ jsx17(
|
|
7132
7365
|
"div",
|
|
7133
7366
|
{
|
|
7134
7367
|
style: {
|
|
@@ -7158,7 +7391,6 @@ function AiSectionOverlay({
|
|
|
7158
7391
|
}) {
|
|
7159
7392
|
const [selectedId, setSelectedId] = useState4(null);
|
|
7160
7393
|
const [reviewId, setReviewId] = useState4(null);
|
|
7161
|
-
const [reviewButtonsHidden, setReviewButtonsHidden] = useState4(false);
|
|
7162
7394
|
const reviewIdRef = useRef4(null);
|
|
7163
7395
|
reviewIdRef.current = reviewId;
|
|
7164
7396
|
const selectedIdRef = useRef4(null);
|
|
@@ -7167,7 +7399,7 @@ function AiSectionOverlay({
|
|
|
7167
7399
|
(el) => {
|
|
7168
7400
|
postToParent2({
|
|
7169
7401
|
type: "ow:section-selected",
|
|
7170
|
-
sectionId: el
|
|
7402
|
+
sectionId: el?.dataset.ohwSection ?? null,
|
|
7171
7403
|
sectionLabel: el ? el.dataset.ohwSectionLabel ?? titleCaseSectionId(el.dataset.ohwSection ?? "") : null
|
|
7172
7404
|
});
|
|
7173
7405
|
},
|
|
@@ -7176,7 +7408,7 @@ function AiSectionOverlay({
|
|
|
7176
7408
|
const selectFromElement = useCallback2(
|
|
7177
7409
|
(el, options) => {
|
|
7178
7410
|
const sectionEl = el?.closest("[data-ohw-section]") ?? null;
|
|
7179
|
-
const id = sectionEl
|
|
7411
|
+
const id = sectionEl?.dataset.ohwSection ?? null;
|
|
7180
7412
|
if (id === selectedIdRef.current) return;
|
|
7181
7413
|
setSelectedId(id);
|
|
7182
7414
|
if (options?.report !== false) report(sectionEl);
|
|
@@ -7217,10 +7449,9 @@ function AiSectionOverlay({
|
|
|
7217
7449
|
}
|
|
7218
7450
|
const found = readRect(sectionId) != null;
|
|
7219
7451
|
setReviewId(found ? sectionId : null);
|
|
7220
|
-
setReviewButtonsHidden(e.data.hideButtons === true);
|
|
7221
7452
|
postToParent2({ type: "ow:ai-review-started", sectionId, found });
|
|
7222
7453
|
if (found) {
|
|
7223
|
-
document.querySelector(`[data-ohw-
|
|
7454
|
+
document.querySelector(`[data-ohw-section="${CSS.escape(sectionId)}"]`)?.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
|
7224
7455
|
}
|
|
7225
7456
|
}
|
|
7226
7457
|
};
|
|
@@ -7239,7 +7470,7 @@ function AiSectionOverlay({
|
|
|
7239
7470
|
return;
|
|
7240
7471
|
}
|
|
7241
7472
|
const sec = t.closest("[data-ohw-section]");
|
|
7242
|
-
setHoveredId(sec
|
|
7473
|
+
setHoveredId(sec?.dataset.ohwSection ?? null);
|
|
7243
7474
|
};
|
|
7244
7475
|
const onLeave = () => setHoveredId(null);
|
|
7245
7476
|
document.addEventListener("mousemove", onMove, { passive: true });
|
|
@@ -7271,31 +7502,11 @@ function AiSectionOverlay({
|
|
|
7271
7502
|
},
|
|
7272
7503
|
[postToParent2]
|
|
7273
7504
|
);
|
|
7274
|
-
const
|
|
7275
|
-
const selectionRect = useLiveSectionRect(activeSelectionId);
|
|
7505
|
+
const selectionRect = useLiveSectionRect(reviewId ? null : selectedId);
|
|
7276
7506
|
const reviewRect = useLiveSectionRect(reviewId);
|
|
7277
7507
|
const hoverRect = useLiveSectionRect(reviewId || hoveredId === selectedId ? null : hoveredId);
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
postToParent2({ type: "ow:section-rect", instanceId: null, rect: null });
|
|
7281
|
-
return;
|
|
7282
|
-
}
|
|
7283
|
-
const { isFirst, isLast } = computeSectionBoundaryFlags(activeSelectionId);
|
|
7284
|
-
postToParent2({
|
|
7285
|
-
type: "ow:section-rect",
|
|
7286
|
-
instanceId: activeSelectionId,
|
|
7287
|
-
rect: {
|
|
7288
|
-
top: selectionRect.top + window.scrollY,
|
|
7289
|
-
left: selectionRect.left + window.scrollX,
|
|
7290
|
-
width: selectionRect.width,
|
|
7291
|
-
height: selectionRect.height
|
|
7292
|
-
},
|
|
7293
|
-
isFirst,
|
|
7294
|
-
isLast
|
|
7295
|
-
});
|
|
7296
|
-
}, [activeSelectionId, selectionRect, postToParent2]);
|
|
7297
|
-
return /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
7298
|
-
hoverRect && /* @__PURE__ */ jsx16(
|
|
7508
|
+
return /* @__PURE__ */ jsxs9(Fragment5, { children: [
|
|
7509
|
+
hoverRect && /* @__PURE__ */ jsx17(
|
|
7299
7510
|
"div",
|
|
7300
7511
|
{
|
|
7301
7512
|
"data-ohw-ai-section-hover": "",
|
|
@@ -7313,7 +7524,7 @@ function AiSectionOverlay({
|
|
|
7313
7524
|
}
|
|
7314
7525
|
}
|
|
7315
7526
|
),
|
|
7316
|
-
selectionRect && /* @__PURE__ */
|
|
7527
|
+
selectionRect && /* @__PURE__ */ jsx17(
|
|
7317
7528
|
"div",
|
|
7318
7529
|
{
|
|
7319
7530
|
"data-ohw-ai-section-selected": "",
|
|
@@ -7331,7 +7542,7 @@ function AiSectionOverlay({
|
|
|
7331
7542
|
}
|
|
7332
7543
|
}
|
|
7333
7544
|
),
|
|
7334
|
-
reviewRect && /* @__PURE__ */
|
|
7545
|
+
reviewRect && /* @__PURE__ */ jsx17(
|
|
7335
7546
|
"div",
|
|
7336
7547
|
{
|
|
7337
7548
|
"data-ohw-ai-review": "",
|
|
@@ -7344,16 +7555,13 @@ function AiSectionOverlay({
|
|
|
7344
7555
|
border: `2px solid ${PRIMARY2}`,
|
|
7345
7556
|
borderRadius: edgeAwareRadius(reviewRect),
|
|
7346
7557
|
zIndex: 2147483200,
|
|
7347
|
-
// The veil itself: swallows clicks so the section stays locked until decided.
|
|
7348
|
-
// stopPropagation only guards the bubble phase; the bridge's capture-phase click
|
|
7349
|
-
// handlers additionally bail on `[data-ohw-ai-review]`, without which a click on
|
|
7350
|
-
// Accept/Discard resolves to the media beneath and opens the file picker.
|
|
7558
|
+
// The veil itself: swallows clicks so the section stays locked until decided.
|
|
7351
7559
|
background: "rgba(8, 133, 254, 0.04)",
|
|
7352
7560
|
pointerEvents: "auto",
|
|
7353
7561
|
cursor: "default"
|
|
7354
7562
|
},
|
|
7355
7563
|
onClick: (e) => e.stopPropagation(),
|
|
7356
|
-
children:
|
|
7564
|
+
children: /* @__PURE__ */ jsxs9(
|
|
7357
7565
|
"div",
|
|
7358
7566
|
{
|
|
7359
7567
|
style: {
|
|
@@ -7366,8 +7574,8 @@ function AiSectionOverlay({
|
|
|
7366
7574
|
paddingTop: 12
|
|
7367
7575
|
},
|
|
7368
7576
|
children: [
|
|
7369
|
-
/* @__PURE__ */
|
|
7370
|
-
/* @__PURE__ */
|
|
7577
|
+
/* @__PURE__ */ jsx17(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ jsx17(Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
|
|
7578
|
+
/* @__PURE__ */ jsx17(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ jsx17(X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
|
|
7371
7579
|
]
|
|
7372
7580
|
}
|
|
7373
7581
|
)
|
|
@@ -7727,22 +7935,22 @@ import { useEffect as useEffect8 } from "react";
|
|
|
7727
7935
|
import * as React8 from "react";
|
|
7728
7936
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
7729
7937
|
import { X as X2 } from "lucide-react";
|
|
7730
|
-
import { jsx as
|
|
7938
|
+
import { jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
7731
7939
|
function Dialog2({
|
|
7732
7940
|
...props
|
|
7733
7941
|
}) {
|
|
7734
|
-
return /* @__PURE__ */
|
|
7942
|
+
return /* @__PURE__ */ jsx18(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
|
|
7735
7943
|
}
|
|
7736
7944
|
function DialogPortal({
|
|
7737
7945
|
...props
|
|
7738
7946
|
}) {
|
|
7739
|
-
return /* @__PURE__ */
|
|
7947
|
+
return /* @__PURE__ */ jsx18(DialogPrimitive.Portal, { ...props });
|
|
7740
7948
|
}
|
|
7741
7949
|
function DialogOverlay({
|
|
7742
7950
|
className,
|
|
7743
7951
|
...props
|
|
7744
7952
|
}) {
|
|
7745
|
-
return /* @__PURE__ */
|
|
7953
|
+
return /* @__PURE__ */ jsx18(
|
|
7746
7954
|
DialogPrimitive.Overlay,
|
|
7747
7955
|
{
|
|
7748
7956
|
"data-slot": "dialog-overlay",
|
|
@@ -7755,9 +7963,9 @@ function DialogOverlay({
|
|
|
7755
7963
|
var DialogContent = React8.forwardRef(
|
|
7756
7964
|
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
7757
7965
|
const positionMode = container ? "absolute" : "fixed";
|
|
7758
|
-
return /* @__PURE__ */
|
|
7759
|
-
/* @__PURE__ */
|
|
7760
|
-
/* @__PURE__ */
|
|
7966
|
+
return /* @__PURE__ */ jsxs10(DialogPortal, { container: container ?? void 0, children: [
|
|
7967
|
+
/* @__PURE__ */ jsx18(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
7968
|
+
/* @__PURE__ */ jsxs10(
|
|
7761
7969
|
DialogPrimitive.Content,
|
|
7762
7970
|
{
|
|
7763
7971
|
ref,
|
|
@@ -7773,13 +7981,13 @@ var DialogContent = React8.forwardRef(
|
|
|
7773
7981
|
...props,
|
|
7774
7982
|
children: [
|
|
7775
7983
|
children,
|
|
7776
|
-
showCloseButton ? /* @__PURE__ */
|
|
7984
|
+
showCloseButton ? /* @__PURE__ */ jsx18(
|
|
7777
7985
|
DialogPrimitive.Close,
|
|
7778
7986
|
{
|
|
7779
7987
|
type: "button",
|
|
7780
7988
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
7781
7989
|
"aria-label": "Close",
|
|
7782
|
-
children: /* @__PURE__ */
|
|
7990
|
+
children: /* @__PURE__ */ jsx18(X2, { size: 16, "aria-hidden": true })
|
|
7783
7991
|
}
|
|
7784
7992
|
) : null
|
|
7785
7993
|
]
|
|
@@ -7793,13 +8001,13 @@ function DialogHeader({
|
|
|
7793
8001
|
className,
|
|
7794
8002
|
...props
|
|
7795
8003
|
}) {
|
|
7796
|
-
return /* @__PURE__ */
|
|
8004
|
+
return /* @__PURE__ */ jsx18("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
7797
8005
|
}
|
|
7798
8006
|
function DialogFooter({
|
|
7799
8007
|
className,
|
|
7800
8008
|
...props
|
|
7801
8009
|
}) {
|
|
7802
|
-
return /* @__PURE__ */
|
|
8010
|
+
return /* @__PURE__ */ jsx18(
|
|
7803
8011
|
"div",
|
|
7804
8012
|
{
|
|
7805
8013
|
className: cn("flex items-center justify-end gap-2", className),
|
|
@@ -7807,7 +8015,7 @@ function DialogFooter({
|
|
|
7807
8015
|
}
|
|
7808
8016
|
);
|
|
7809
8017
|
}
|
|
7810
|
-
var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
8018
|
+
var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
|
|
7811
8019
|
DialogPrimitive.Title,
|
|
7812
8020
|
{
|
|
7813
8021
|
ref,
|
|
@@ -7819,7 +8027,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
7819
8027
|
}
|
|
7820
8028
|
));
|
|
7821
8029
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
7822
|
-
var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
8030
|
+
var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx18(
|
|
7823
8031
|
DialogPrimitive.Description,
|
|
7824
8032
|
{
|
|
7825
8033
|
ref,
|
|
@@ -7835,19 +8043,19 @@ import { Info, X as X4 } from "lucide-react";
|
|
|
7835
8043
|
|
|
7836
8044
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
7837
8045
|
import { ArrowRight as ArrowRight2, File, GalleryVertical } from "lucide-react";
|
|
7838
|
-
import { jsx as
|
|
8046
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
7839
8047
|
function DestinationBreadcrumb({
|
|
7840
8048
|
pageTitle,
|
|
7841
8049
|
sectionLabel
|
|
7842
8050
|
}) {
|
|
7843
|
-
return /* @__PURE__ */
|
|
7844
|
-
/* @__PURE__ */
|
|
7845
|
-
/* @__PURE__ */
|
|
7846
|
-
/* @__PURE__ */
|
|
7847
|
-
/* @__PURE__ */
|
|
7848
|
-
/* @__PURE__ */
|
|
8051
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex w-full flex-col gap-2", children: [
|
|
8052
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
8053
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-3", children: [
|
|
8054
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
|
|
8055
|
+
/* @__PURE__ */ jsx19(File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
8056
|
+
/* @__PURE__ */ jsx19("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
7849
8057
|
] }),
|
|
7850
|
-
/* @__PURE__ */
|
|
8058
|
+
/* @__PURE__ */ jsx19(
|
|
7851
8059
|
ArrowRight2,
|
|
7852
8060
|
{
|
|
7853
8061
|
size: 16,
|
|
@@ -7855,8 +8063,8 @@ function DestinationBreadcrumb({
|
|
|
7855
8063
|
"aria-hidden": true
|
|
7856
8064
|
}
|
|
7857
8065
|
),
|
|
7858
|
-
/* @__PURE__ */
|
|
7859
|
-
/* @__PURE__ */
|
|
8066
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
8067
|
+
/* @__PURE__ */ jsx19(
|
|
7860
8068
|
GalleryVertical,
|
|
7861
8069
|
{
|
|
7862
8070
|
size: 16,
|
|
@@ -7864,7 +8072,7 @@ function DestinationBreadcrumb({
|
|
|
7864
8072
|
"aria-hidden": true
|
|
7865
8073
|
}
|
|
7866
8074
|
),
|
|
7867
|
-
/* @__PURE__ */
|
|
8075
|
+
/* @__PURE__ */ jsx19("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
7868
8076
|
] })
|
|
7869
8077
|
] })
|
|
7870
8078
|
] });
|
|
@@ -7872,22 +8080,22 @@ function DestinationBreadcrumb({
|
|
|
7872
8080
|
|
|
7873
8081
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
7874
8082
|
import { GalleryVertical as GalleryVertical2 } from "lucide-react";
|
|
7875
|
-
import { jsx as
|
|
8083
|
+
import { jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
7876
8084
|
function SectionTreeItem({
|
|
7877
8085
|
section,
|
|
7878
8086
|
onSelect,
|
|
7879
8087
|
selected
|
|
7880
8088
|
}) {
|
|
7881
8089
|
const interactive = Boolean(onSelect);
|
|
7882
|
-
return /* @__PURE__ */
|
|
7883
|
-
/* @__PURE__ */
|
|
8090
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
8091
|
+
/* @__PURE__ */ jsx20(
|
|
7884
8092
|
"div",
|
|
7885
8093
|
{
|
|
7886
8094
|
className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
7887
8095
|
"aria-hidden": true
|
|
7888
8096
|
}
|
|
7889
8097
|
),
|
|
7890
|
-
/* @__PURE__ */
|
|
8098
|
+
/* @__PURE__ */ jsxs12(
|
|
7891
8099
|
"div",
|
|
7892
8100
|
{
|
|
7893
8101
|
role: interactive ? "button" : void 0,
|
|
@@ -7905,7 +8113,7 @@ function SectionTreeItem({
|
|
|
7905
8113
|
interactive && selected && "border-primary"
|
|
7906
8114
|
),
|
|
7907
8115
|
children: [
|
|
7908
|
-
/* @__PURE__ */
|
|
8116
|
+
/* @__PURE__ */ jsx20(
|
|
7909
8117
|
GalleryVertical2,
|
|
7910
8118
|
{
|
|
7911
8119
|
size: 16,
|
|
@@ -7913,7 +8121,7 @@ function SectionTreeItem({
|
|
|
7913
8121
|
"aria-hidden": true
|
|
7914
8122
|
}
|
|
7915
8123
|
),
|
|
7916
|
-
/* @__PURE__ */
|
|
8124
|
+
/* @__PURE__ */ jsx20("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
7917
8125
|
]
|
|
7918
8126
|
}
|
|
7919
8127
|
)
|
|
@@ -7925,10 +8133,10 @@ import { useEffect as useEffect5, useId as useId2, useRef as useRef5, useState a
|
|
|
7925
8133
|
|
|
7926
8134
|
// src/ui/input.tsx
|
|
7927
8135
|
import * as React9 from "react";
|
|
7928
|
-
import { jsx as
|
|
8136
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
7929
8137
|
var Input = React9.forwardRef(
|
|
7930
8138
|
({ className, type, ...props }, ref) => {
|
|
7931
|
-
return /* @__PURE__ */
|
|
8139
|
+
return /* @__PURE__ */ jsx21(
|
|
7932
8140
|
"input",
|
|
7933
8141
|
{
|
|
7934
8142
|
type,
|
|
@@ -7947,9 +8155,9 @@ Input.displayName = "Input";
|
|
|
7947
8155
|
|
|
7948
8156
|
// src/ui/label.tsx
|
|
7949
8157
|
import { Label as LabelPrimitive } from "radix-ui";
|
|
7950
|
-
import { jsx as
|
|
8158
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
7951
8159
|
function Label({ className, ...props }) {
|
|
7952
|
-
return /* @__PURE__ */
|
|
8160
|
+
return /* @__PURE__ */ jsx22(
|
|
7953
8161
|
LabelPrimitive.Root,
|
|
7954
8162
|
{
|
|
7955
8163
|
"data-slot": "label",
|
|
@@ -7960,12 +8168,12 @@ function Label({ className, ...props }) {
|
|
|
7960
8168
|
}
|
|
7961
8169
|
|
|
7962
8170
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
7963
|
-
import { ChevronDown as
|
|
7964
|
-
import { jsx as
|
|
8171
|
+
import { ChevronDown as ChevronDown3, File as File2, X as X3 } from "lucide-react";
|
|
8172
|
+
import { jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7965
8173
|
function FieldChevron({
|
|
7966
8174
|
onClick
|
|
7967
8175
|
}) {
|
|
7968
|
-
return /* @__PURE__ */
|
|
8176
|
+
return /* @__PURE__ */ jsx23(
|
|
7969
8177
|
"button",
|
|
7970
8178
|
{
|
|
7971
8179
|
type: "button",
|
|
@@ -7973,7 +8181,7 @@ function FieldChevron({
|
|
|
7973
8181
|
onClick,
|
|
7974
8182
|
"aria-label": "Open page list",
|
|
7975
8183
|
tabIndex: -1,
|
|
7976
|
-
children: /* @__PURE__ */
|
|
8184
|
+
children: /* @__PURE__ */ jsx23(ChevronDown3, { size: 16 })
|
|
7977
8185
|
}
|
|
7978
8186
|
);
|
|
7979
8187
|
}
|
|
@@ -8034,11 +8242,11 @@ function UrlOrPageInput({
|
|
|
8034
8242
|
"data-ohw-link-field flex h-[36px] w-full items-center overflow-hidden rounded-md border bg-background pl-3 pr-3 py-2 outline-none transition-[border-color,box-shadow]",
|
|
8035
8243
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
8036
8244
|
);
|
|
8037
|
-
return /* @__PURE__ */
|
|
8038
|
-
/* @__PURE__ */
|
|
8039
|
-
/* @__PURE__ */
|
|
8040
|
-
/* @__PURE__ */
|
|
8041
|
-
selectedPage ? /* @__PURE__ */
|
|
8245
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
8246
|
+
/* @__PURE__ */ jsx23(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
8247
|
+
/* @__PURE__ */ jsxs13("div", { ref: rootRef, className: "relative w-full", children: [
|
|
8248
|
+
/* @__PURE__ */ jsxs13("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
8249
|
+
selectedPage ? /* @__PURE__ */ jsx23("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ jsx23(
|
|
8042
8250
|
File2,
|
|
8043
8251
|
{
|
|
8044
8252
|
size: 16,
|
|
@@ -8046,7 +8254,7 @@ function UrlOrPageInput({
|
|
|
8046
8254
|
"aria-hidden": true
|
|
8047
8255
|
}
|
|
8048
8256
|
) }) : null,
|
|
8049
|
-
readOnly ? /* @__PURE__ */
|
|
8257
|
+
readOnly ? /* @__PURE__ */ jsx23("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ jsx23(
|
|
8050
8258
|
Input,
|
|
8051
8259
|
{
|
|
8052
8260
|
ref: inputRef,
|
|
@@ -8072,7 +8280,7 @@ function UrlOrPageInput({
|
|
|
8072
8280
|
)
|
|
8073
8281
|
}
|
|
8074
8282
|
),
|
|
8075
|
-
selectedPage && !readOnly ? /* @__PURE__ */
|
|
8283
|
+
selectedPage && !readOnly ? /* @__PURE__ */ jsx23(
|
|
8076
8284
|
"button",
|
|
8077
8285
|
{
|
|
8078
8286
|
type: "button",
|
|
@@ -8080,26 +8288,26 @@ function UrlOrPageInput({
|
|
|
8080
8288
|
onMouseDown: clearSelection,
|
|
8081
8289
|
"aria-label": "Clear selected page",
|
|
8082
8290
|
tabIndex: -1,
|
|
8083
|
-
children: /* @__PURE__ */
|
|
8291
|
+
children: /* @__PURE__ */ jsx23(X3, { size: 16, "aria-hidden": true })
|
|
8084
8292
|
}
|
|
8085
8293
|
) : null,
|
|
8086
|
-
!readOnly ? /* @__PURE__ */
|
|
8294
|
+
!readOnly ? /* @__PURE__ */ jsx23(FieldChevron, { onClick: toggleDropdown }) : null
|
|
8087
8295
|
] }),
|
|
8088
|
-
dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */
|
|
8296
|
+
dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ jsx23(
|
|
8089
8297
|
"div",
|
|
8090
8298
|
{
|
|
8091
8299
|
"data-ohw-link-page-dropdown": "",
|
|
8092
8300
|
className: "absolute left-0 right-0 top-[calc(100%+4px)] z-50 max-h-48 overflow-auto rounded-lg border border-border bg-popover py-1 shadow-lg",
|
|
8093
8301
|
onMouseDown: (e) => e.preventDefault(),
|
|
8094
|
-
children: filteredPages.map((page) => /* @__PURE__ */
|
|
8302
|
+
children: filteredPages.map((page) => /* @__PURE__ */ jsxs13(
|
|
8095
8303
|
"button",
|
|
8096
8304
|
{
|
|
8097
8305
|
type: "button",
|
|
8098
8306
|
className: "flex h-9 w-full items-center gap-2 border-0 bg-transparent px-3 text-left text-sm leading-5 text-foreground outline-none hover:bg-muted",
|
|
8099
8307
|
onClick: () => onPageSelect(page),
|
|
8100
8308
|
children: [
|
|
8101
|
-
/* @__PURE__ */
|
|
8102
|
-
/* @__PURE__ */
|
|
8309
|
+
/* @__PURE__ */ jsx23(File2, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
8310
|
+
/* @__PURE__ */ jsx23("span", { className: "truncate", children: page.title })
|
|
8103
8311
|
]
|
|
8104
8312
|
},
|
|
8105
8313
|
page.path
|
|
@@ -8107,34 +8315,34 @@ function UrlOrPageInput({
|
|
|
8107
8315
|
}
|
|
8108
8316
|
) : null
|
|
8109
8317
|
] }),
|
|
8110
|
-
urlError ? /* @__PURE__ */
|
|
8318
|
+
urlError ? /* @__PURE__ */ jsx23("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
|
|
8111
8319
|
] });
|
|
8112
8320
|
}
|
|
8113
8321
|
|
|
8114
8322
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
8115
|
-
import { Fragment as Fragment6, jsx as
|
|
8323
|
+
import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
8116
8324
|
function LinkEditorPanel({ state, onClose }) {
|
|
8117
8325
|
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
8118
|
-
return /* @__PURE__ */
|
|
8119
|
-
/* @__PURE__ */
|
|
8326
|
+
return /* @__PURE__ */ jsxs14(Fragment6, { children: [
|
|
8327
|
+
/* @__PURE__ */ jsx24(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx24(
|
|
8120
8328
|
"button",
|
|
8121
8329
|
{
|
|
8122
8330
|
type: "button",
|
|
8123
8331
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
8124
8332
|
"aria-label": "Close",
|
|
8125
8333
|
onClick: onClose,
|
|
8126
|
-
children: /* @__PURE__ */
|
|
8334
|
+
children: /* @__PURE__ */ jsx24(X4, { size: 16, "aria-hidden": true })
|
|
8127
8335
|
}
|
|
8128
8336
|
) }),
|
|
8129
|
-
/* @__PURE__ */
|
|
8130
|
-
/* @__PURE__ */
|
|
8131
|
-
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */
|
|
8337
|
+
/* @__PURE__ */ jsx24(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ jsx24(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
8338
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
8339
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ jsx24(
|
|
8132
8340
|
DestinationBreadcrumb,
|
|
8133
8341
|
{
|
|
8134
8342
|
pageTitle: state.selectedPage.title,
|
|
8135
8343
|
sectionLabel: state.selectedSection.label
|
|
8136
8344
|
}
|
|
8137
|
-
) : /* @__PURE__ */
|
|
8345
|
+
) : /* @__PURE__ */ jsx24(
|
|
8138
8346
|
UrlOrPageInput,
|
|
8139
8347
|
{
|
|
8140
8348
|
value: state.searchValue,
|
|
@@ -8147,8 +8355,8 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8147
8355
|
urlError: state.urlError
|
|
8148
8356
|
}
|
|
8149
8357
|
),
|
|
8150
|
-
state.showChooseSection ? /* @__PURE__ */
|
|
8151
|
-
/* @__PURE__ */
|
|
8358
|
+
state.showChooseSection ? /* @__PURE__ */ jsxs14("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
8359
|
+
/* @__PURE__ */ jsx24(
|
|
8152
8360
|
Button,
|
|
8153
8361
|
{
|
|
8154
8362
|
type: "button",
|
|
@@ -8159,15 +8367,15 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8159
8367
|
children: "Choose a section"
|
|
8160
8368
|
}
|
|
8161
8369
|
),
|
|
8162
|
-
/* @__PURE__ */
|
|
8163
|
-
/* @__PURE__ */
|
|
8164
|
-
/* @__PURE__ */
|
|
8370
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
8371
|
+
/* @__PURE__ */ jsx24(Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
8372
|
+
/* @__PURE__ */ jsx24("span", { children: "Pick a section this link should scroll to." })
|
|
8165
8373
|
] })
|
|
8166
8374
|
] }) : null,
|
|
8167
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */
|
|
8375
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ jsx24(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
8168
8376
|
] }),
|
|
8169
|
-
/* @__PURE__ */
|
|
8170
|
-
/* @__PURE__ */
|
|
8377
|
+
/* @__PURE__ */ jsxs14(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
8378
|
+
/* @__PURE__ */ jsx24(
|
|
8171
8379
|
Button,
|
|
8172
8380
|
{
|
|
8173
8381
|
type: "button",
|
|
@@ -8182,7 +8390,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8182
8390
|
children: state.secondaryLabel
|
|
8183
8391
|
}
|
|
8184
8392
|
),
|
|
8185
|
-
/* @__PURE__ */
|
|
8393
|
+
/* @__PURE__ */ jsx24(
|
|
8186
8394
|
Button,
|
|
8187
8395
|
{
|
|
8188
8396
|
type: "button",
|
|
@@ -8205,7 +8413,7 @@ import { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMem
|
|
|
8205
8413
|
import { createPortal } from "react-dom";
|
|
8206
8414
|
import { ArrowLeft as ArrowLeft2, Check as Check2 } from "lucide-react";
|
|
8207
8415
|
import { usePathname, useRouter as useRouter2 } from "next/navigation";
|
|
8208
|
-
import { jsx as
|
|
8416
|
+
import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
8209
8417
|
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
8210
8418
|
function rectsEqual(a, b) {
|
|
8211
8419
|
if (a.size !== b.size) return false;
|
|
@@ -8434,7 +8642,7 @@ function SectionPickerOverlay({
|
|
|
8434
8642
|
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
8435
8643
|
if (!portalRoot) return null;
|
|
8436
8644
|
return createPortal(
|
|
8437
|
-
/* @__PURE__ */
|
|
8645
|
+
/* @__PURE__ */ jsxs15(
|
|
8438
8646
|
"div",
|
|
8439
8647
|
{
|
|
8440
8648
|
"data-ohw-section-picker": "",
|
|
@@ -8444,12 +8652,12 @@ function SectionPickerOverlay({
|
|
|
8444
8652
|
role: "dialog",
|
|
8445
8653
|
"aria-label": "Choose a section",
|
|
8446
8654
|
children: [
|
|
8447
|
-
/* @__PURE__ */
|
|
8655
|
+
/* @__PURE__ */ jsx25(
|
|
8448
8656
|
"div",
|
|
8449
8657
|
{
|
|
8450
8658
|
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
8451
8659
|
style: { top: chromeClip.top + 20 },
|
|
8452
|
-
children: /* @__PURE__ */
|
|
8660
|
+
children: /* @__PURE__ */ jsxs15(
|
|
8453
8661
|
Button,
|
|
8454
8662
|
{
|
|
8455
8663
|
type: "button",
|
|
@@ -8458,14 +8666,14 @@ function SectionPickerOverlay({
|
|
|
8458
8666
|
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
8459
8667
|
onClick: onBack,
|
|
8460
8668
|
children: [
|
|
8461
|
-
/* @__PURE__ */
|
|
8669
|
+
/* @__PURE__ */ jsx25(ArrowLeft2, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
8462
8670
|
"Back"
|
|
8463
8671
|
]
|
|
8464
8672
|
}
|
|
8465
8673
|
)
|
|
8466
8674
|
}
|
|
8467
8675
|
),
|
|
8468
|
-
/* @__PURE__ */
|
|
8676
|
+
/* @__PURE__ */ jsx25(
|
|
8469
8677
|
"div",
|
|
8470
8678
|
{
|
|
8471
8679
|
className: "pointer-events-none fixed left-1/2 z-[2] rounded-lg px-4 py-3 text-xs leading-4 tracking-[0.18px] text-white shadow-md",
|
|
@@ -8478,7 +8686,7 @@ function SectionPickerOverlay({
|
|
|
8478
8686
|
children: "Click on section to select"
|
|
8479
8687
|
}
|
|
8480
8688
|
),
|
|
8481
|
-
!isOnTargetPage ? /* @__PURE__ */
|
|
8689
|
+
!isOnTargetPage ? /* @__PURE__ */ jsx25(
|
|
8482
8690
|
"div",
|
|
8483
8691
|
{
|
|
8484
8692
|
className: "pointer-events-none fixed left-1/2 z-[1] -translate-x-1/2 rounded-md px-3 py-2 text-sm text-muted-foreground shadow-sm",
|
|
@@ -8486,14 +8694,14 @@ function SectionPickerOverlay({
|
|
|
8486
8694
|
children: "Loading page preview\u2026"
|
|
8487
8695
|
}
|
|
8488
8696
|
) : null,
|
|
8489
|
-
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */
|
|
8697
|
+
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ jsx25("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ jsx25("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
|
|
8490
8698
|
isOnTargetPage ? liveSections.map((section) => {
|
|
8491
8699
|
const rect = rects.get(section.id);
|
|
8492
8700
|
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
8493
8701
|
const isSelected = selectedId === section.id;
|
|
8494
8702
|
const isHovered = hoveredId === section.id;
|
|
8495
8703
|
const isLit = isSelected || isHovered;
|
|
8496
|
-
return /* @__PURE__ */
|
|
8704
|
+
return /* @__PURE__ */ jsxs15(
|
|
8497
8705
|
"button",
|
|
8498
8706
|
{
|
|
8499
8707
|
type: "button",
|
|
@@ -8508,7 +8716,7 @@ function SectionPickerOverlay({
|
|
|
8508
8716
|
"aria-label": `Select section ${section.label}`,
|
|
8509
8717
|
onClick: () => handleSelect(section),
|
|
8510
8718
|
children: [
|
|
8511
|
-
isLit ? /* @__PURE__ */
|
|
8719
|
+
isLit ? /* @__PURE__ */ jsx25(
|
|
8512
8720
|
"span",
|
|
8513
8721
|
{
|
|
8514
8722
|
className: "pointer-events-none absolute",
|
|
@@ -8521,13 +8729,13 @@ function SectionPickerOverlay({
|
|
|
8521
8729
|
"aria-hidden": true
|
|
8522
8730
|
}
|
|
8523
8731
|
) : null,
|
|
8524
|
-
isSelected ? /* @__PURE__ */
|
|
8732
|
+
isSelected ? /* @__PURE__ */ jsx25(
|
|
8525
8733
|
"span",
|
|
8526
8734
|
{
|
|
8527
8735
|
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
8528
8736
|
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
8529
8737
|
"aria-hidden": true,
|
|
8530
|
-
children: /* @__PURE__ */
|
|
8738
|
+
children: /* @__PURE__ */ jsx25(Check2, { className: "size-5" })
|
|
8531
8739
|
}
|
|
8532
8740
|
) : null
|
|
8533
8741
|
]
|
|
@@ -8707,7 +8915,7 @@ function useLinkModalState({
|
|
|
8707
8915
|
}
|
|
8708
8916
|
|
|
8709
8917
|
// src/ui/link-modal/LinkPopover.tsx
|
|
8710
|
-
import { Fragment as Fragment7, jsx as
|
|
8918
|
+
import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
8711
8919
|
function postToParent(data) {
|
|
8712
8920
|
window.parent?.postMessage(data, "*");
|
|
8713
8921
|
}
|
|
@@ -8803,15 +9011,15 @@ function LinkPopover({
|
|
|
8803
9011
|
);
|
|
8804
9012
|
};
|
|
8805
9013
|
}, [open, sectionPickerActive]);
|
|
8806
|
-
return /* @__PURE__ */
|
|
8807
|
-
/* @__PURE__ */
|
|
9014
|
+
return /* @__PURE__ */ jsxs16(Fragment7, { children: [
|
|
9015
|
+
/* @__PURE__ */ jsx26(
|
|
8808
9016
|
Dialog2,
|
|
8809
9017
|
{
|
|
8810
9018
|
open: open && !sectionPickerActive,
|
|
8811
9019
|
onOpenChange: (next) => {
|
|
8812
9020
|
if (!next) onClose?.();
|
|
8813
9021
|
},
|
|
8814
|
-
children: /* @__PURE__ */
|
|
9022
|
+
children: /* @__PURE__ */ jsx26(
|
|
8815
9023
|
DialogContent,
|
|
8816
9024
|
{
|
|
8817
9025
|
ref: panelRef,
|
|
@@ -8821,12 +9029,12 @@ function LinkPopover({
|
|
|
8821
9029
|
"data-ohw-bridge": "",
|
|
8822
9030
|
showCloseButton: false,
|
|
8823
9031
|
className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
|
|
8824
|
-
children: /* @__PURE__ */
|
|
9032
|
+
children: /* @__PURE__ */ jsx26(LinkEditorPanel, { state, onClose })
|
|
8825
9033
|
}
|
|
8826
9034
|
)
|
|
8827
9035
|
}
|
|
8828
9036
|
),
|
|
8829
|
-
sectionPickerActive && state.selectedPage ? /* @__PURE__ */
|
|
9037
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ jsx26(
|
|
8830
9038
|
SectionPickerOverlay,
|
|
8831
9039
|
{
|
|
8832
9040
|
pagePath: state.selectedPage.path,
|
|
@@ -10052,13 +10260,14 @@ function listSocialItems(row) {
|
|
|
10052
10260
|
return isSocialItem(anchor) ? anchor : null;
|
|
10053
10261
|
}).filter((item) => item !== null);
|
|
10054
10262
|
}
|
|
10055
|
-
function socialRowUnit(item) {
|
|
10056
|
-
const row = findSocialsRow(item);
|
|
10263
|
+
function socialRowUnit(item, knownRow) {
|
|
10264
|
+
const row = knownRow ?? findSocialsRow(item);
|
|
10265
|
+
if (!row || !row.contains(item)) return null;
|
|
10057
10266
|
let node = item;
|
|
10058
10267
|
while (node.parentElement && node.parentElement !== row) {
|
|
10059
10268
|
node = node.parentElement;
|
|
10060
10269
|
}
|
|
10061
|
-
return node;
|
|
10270
|
+
return node.parentElement === row ? node : null;
|
|
10062
10271
|
}
|
|
10063
10272
|
function listSocialsRows(root = document) {
|
|
10064
10273
|
const rows = /* @__PURE__ */ new Set();
|
|
@@ -10077,7 +10286,8 @@ function markSocialsRows(root = document) {
|
|
|
10077
10286
|
listSocialsRows(root).forEach((row) => {
|
|
10078
10287
|
row.setAttribute(SOCIALS_ROW_ATTR, "");
|
|
10079
10288
|
const items = listSocialItems(row);
|
|
10080
|
-
|
|
10289
|
+
const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
|
|
10290
|
+
if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
|
|
10081
10291
|
items.forEach((item, index) => {
|
|
10082
10292
|
item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
|
|
10083
10293
|
const iconKey = socialIconKey(item);
|
|
@@ -10221,7 +10431,8 @@ function removeSocialItem(item, content) {
|
|
|
10221
10431
|
const previousContent = Object.fromEntries(
|
|
10222
10432
|
removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
|
|
10223
10433
|
);
|
|
10224
|
-
const unit = socialRowUnit(item);
|
|
10434
|
+
const unit = socialRowUnit(item, row);
|
|
10435
|
+
if (!unit) return null;
|
|
10225
10436
|
const nextSibling = unit.nextElementSibling;
|
|
10226
10437
|
unit.remove();
|
|
10227
10438
|
markSocialsRows(row.ownerDocument);
|
|
@@ -10244,7 +10455,9 @@ function applySocialsOrder(order, root = document) {
|
|
|
10244
10455
|
const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
|
|
10245
10456
|
wanted.forEach((key) => {
|
|
10246
10457
|
const item = byKey.get(key);
|
|
10247
|
-
if (item)
|
|
10458
|
+
if (!item) return;
|
|
10459
|
+
const unit = socialRowUnit(item, row);
|
|
10460
|
+
if (unit) row.appendChild(unit);
|
|
10248
10461
|
});
|
|
10249
10462
|
});
|
|
10250
10463
|
markSocialsRows(root);
|
|
@@ -10274,7 +10487,7 @@ function reconcileSocialsFromContent(content, root = document) {
|
|
|
10274
10487
|
});
|
|
10275
10488
|
if (surviving.length) {
|
|
10276
10489
|
present.forEach((item) => {
|
|
10277
|
-
if (!surviving.includes(item)) socialRowUnit(item)
|
|
10490
|
+
if (!surviving.includes(item)) socialRowUnit(item)?.remove();
|
|
10278
10491
|
});
|
|
10279
10492
|
}
|
|
10280
10493
|
});
|
|
@@ -11253,296 +11466,42 @@ function deleteFooterColumn(column) {
|
|
|
11253
11466
|
};
|
|
11254
11467
|
}
|
|
11255
11468
|
|
|
11256
|
-
// src/lib/
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
}
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
}
|
|
11274
|
-
function textKeyForRoot(root) {
|
|
11275
|
-
return isFooterLogoRoot(root) ? "footer-logo-text" : "nav-logo-text";
|
|
11276
|
-
}
|
|
11277
|
-
function ensureLogoHrefKey(root) {
|
|
11278
|
-
if (!(root instanceof HTMLAnchorElement)) return;
|
|
11279
|
-
if (root.hasAttribute("data-ohw-href-key")) return;
|
|
11280
|
-
root.setAttribute("data-ohw-href-key", isFooterLogoRoot(root) ? "footer-logo-href" : "nav-logo-href");
|
|
11281
|
-
}
|
|
11282
|
-
function applyLogoIdentity(text, isPlaceholder) {
|
|
11283
|
-
const display = resolveLogoDisplayText(text);
|
|
11284
|
-
const placeholder = isPlaceholder || !text.trim() || display === PLACEHOLDER_BUSINESS_NAME;
|
|
11285
|
-
for (const key of LOGO_TEXT_KEYS) {
|
|
11286
|
-
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
11287
|
-
if (el.textContent !== display) el.textContent = display;
|
|
11288
|
-
});
|
|
11289
|
-
}
|
|
11290
|
-
for (const key of LOGO_IMAGE_KEYS) {
|
|
11291
|
-
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
11292
|
-
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
11293
|
-
if (img) img.alt = display;
|
|
11469
|
+
// src/lib/add-footer-column.ts
|
|
11470
|
+
function buildFooterColumnEditContentPatch(result) {
|
|
11471
|
+
return {
|
|
11472
|
+
[result.headingKey]: result.heading,
|
|
11473
|
+
[result.hrefKey]: result.href,
|
|
11474
|
+
[result.labelKey]: result.label,
|
|
11475
|
+
[FOOTER_ORDER_KEY]: JSON.stringify(result.order)
|
|
11476
|
+
};
|
|
11477
|
+
}
|
|
11478
|
+
function addFooterColumnWithPersist({
|
|
11479
|
+
postToParent: postToParent2
|
|
11480
|
+
}) {
|
|
11481
|
+
if (!canAddFooterColumn()) {
|
|
11482
|
+
postToParent2({
|
|
11483
|
+
type: "ow:toast",
|
|
11484
|
+
title: `Maximum ${MAX_FOOTER_COLUMNS} columns`,
|
|
11485
|
+
toastType: "error"
|
|
11294
11486
|
});
|
|
11487
|
+
return null;
|
|
11295
11488
|
}
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
}
|
|
11302
|
-
function applyLogoImage(url, alt) {
|
|
11303
|
-
const displayAlt = resolveLogoDisplayText(alt);
|
|
11304
|
-
document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
|
|
11305
|
-
ensureLogoHrefKey(root);
|
|
11306
|
-
const imageKey = imageKeyForRoot(root);
|
|
11307
|
-
const textKey = textKeyForRoot(root);
|
|
11308
|
-
let img = root.querySelector(`img[data-ohw-key="${imageKey}"]`) ?? (root.querySelector(`[data-ohw-key="${imageKey}"]`) instanceof HTMLImageElement ? root.querySelector(`[data-ohw-key="${imageKey}"]`) : null) ?? root.querySelector("img");
|
|
11309
|
-
let textEl = root.querySelector(`[data-ohw-key="${textKey}"]`) ?? root.querySelector('[data-ohw-key="logo-text"]');
|
|
11310
|
-
if (url) {
|
|
11311
|
-
if (!img) {
|
|
11312
|
-
img = document.createElement("img");
|
|
11313
|
-
img.setAttribute("data-ohw-editable", "image");
|
|
11314
|
-
img.setAttribute("data-ohw-key", imageKey);
|
|
11315
|
-
img.alt = displayAlt;
|
|
11316
|
-
img.style.height = "";
|
|
11317
|
-
img.style.maxHeight = "none";
|
|
11318
|
-
img.style.width = "auto";
|
|
11319
|
-
img.style.display = "block";
|
|
11320
|
-
img.style.objectFit = "contain";
|
|
11321
|
-
root.insertBefore(img, root.firstChild);
|
|
11322
|
-
} else {
|
|
11323
|
-
img.setAttribute("data-ohw-editable", "image");
|
|
11324
|
-
img.setAttribute("data-ohw-key", imageKey);
|
|
11325
|
-
}
|
|
11326
|
-
img.removeAttribute("srcset");
|
|
11327
|
-
img.removeAttribute("sizes");
|
|
11328
|
-
img.src = url;
|
|
11329
|
-
img.alt = displayAlt;
|
|
11330
|
-
img.style.display = "block";
|
|
11331
|
-
if (textEl) textEl.style.display = "none";
|
|
11332
|
-
root.removeAttribute("data-ohw-placeholder");
|
|
11333
|
-
return;
|
|
11334
|
-
}
|
|
11335
|
-
if (img) {
|
|
11336
|
-
img.removeAttribute("src");
|
|
11337
|
-
img.removeAttribute("srcset");
|
|
11338
|
-
img.removeAttribute("sizes");
|
|
11339
|
-
img.alt = displayAlt;
|
|
11340
|
-
img.style.display = "none";
|
|
11341
|
-
}
|
|
11342
|
-
if (!textEl) {
|
|
11343
|
-
textEl = document.createElement("span");
|
|
11344
|
-
textEl.setAttribute("data-ohw-editable", "plain");
|
|
11345
|
-
textEl.setAttribute("data-ohw-key", textKey);
|
|
11346
|
-
root.appendChild(textEl);
|
|
11347
|
-
}
|
|
11348
|
-
textEl.style.display = "";
|
|
11349
|
-
if (textEl.textContent !== displayAlt) textEl.textContent = displayAlt;
|
|
11350
|
-
if (!displayAlt.trim() || displayAlt === PLACEHOLDER_BUSINESS_NAME) {
|
|
11351
|
-
root.setAttribute("data-ohw-placeholder", "");
|
|
11352
|
-
} else {
|
|
11353
|
-
root.removeAttribute("data-ohw-placeholder");
|
|
11354
|
-
}
|
|
11355
|
-
});
|
|
11356
|
-
}
|
|
11357
|
-
function applyLogoHref(href) {
|
|
11358
|
-
const target = href.trim() || "/";
|
|
11359
|
-
document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
|
|
11360
|
-
ensureLogoHrefKey(root);
|
|
11361
|
-
if (root instanceof HTMLAnchorElement) {
|
|
11362
|
-
root.setAttribute("href", target);
|
|
11363
|
-
}
|
|
11364
|
-
});
|
|
11365
|
-
for (const key of LOGO_HREF_KEYS) setStoredLinkHref(key, target);
|
|
11366
|
-
}
|
|
11367
|
-
function readLogoIdentityFromDom() {
|
|
11368
|
-
let imageUrl = null;
|
|
11369
|
-
for (const key of LOGO_IMAGE_KEYS) {
|
|
11370
|
-
const el = document.querySelector(`[data-ohw-key="${key}"]`);
|
|
11371
|
-
const img = el instanceof HTMLImageElement ? el : el?.querySelector("img");
|
|
11372
|
-
const attrSrc = img?.getAttribute("src")?.trim() ?? "";
|
|
11373
|
-
if (attrSrc && !attrSrc.startsWith("data:") && img && img.style.display !== "none") {
|
|
11374
|
-
imageUrl = img.currentSrc || img.src;
|
|
11375
|
-
break;
|
|
11376
|
-
}
|
|
11377
|
-
}
|
|
11378
|
-
let text = PLACEHOLDER_BUSINESS_NAME;
|
|
11379
|
-
let isPlaceholder = true;
|
|
11380
|
-
for (const key of LOGO_TEXT_KEYS) {
|
|
11381
|
-
const el = document.querySelector(`[data-ohw-key="${key}"]`);
|
|
11382
|
-
if (el?.textContent?.trim()) {
|
|
11383
|
-
text = el.textContent.trim();
|
|
11384
|
-
const logoRoot2 = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
11385
|
-
isPlaceholder = logoRoot2?.hasAttribute("data-ohw-placeholder") === true || text === PLACEHOLDER_BUSINESS_NAME;
|
|
11386
|
-
break;
|
|
11387
|
-
}
|
|
11388
|
-
}
|
|
11389
|
-
if (imageUrl) {
|
|
11390
|
-
const logoImg = document.querySelector(
|
|
11391
|
-
'[data-ohw-key="nav-logo-image"], [data-ohw-key="footer-logo"]'
|
|
11392
|
-
);
|
|
11393
|
-
const alt = logoImg?.alt?.trim() || text;
|
|
11394
|
-
isPlaceholder = false;
|
|
11395
|
-
const hrefEl = document.querySelector(
|
|
11396
|
-
'a[data-ohw-role="logo"], a[data-ohw-logo], [data-ohw-role="logo"]'
|
|
11397
|
-
);
|
|
11398
|
-
const href2 = (hrefEl instanceof HTMLAnchorElement ? hrefEl.getAttribute("href") : null) || hrefEl?.closest("a")?.getAttribute("href") || "/";
|
|
11399
|
-
return { text, isPlaceholder, imageUrl, href: href2, alt };
|
|
11400
|
-
}
|
|
11401
|
-
const logoRoot = document.querySelector('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
11402
|
-
const href = (logoRoot instanceof HTMLAnchorElement ? logoRoot.getAttribute("href") : null) || logoRoot?.closest("a")?.getAttribute("href") || "/";
|
|
11403
|
-
return { text, isPlaceholder, imageUrl: null, href, alt: text };
|
|
11404
|
-
}
|
|
11405
|
-
function applyLogoFromContent(content) {
|
|
11406
|
-
const hasLogoIdentity = LOGO_PLACEHOLDER_KEY in content || LOGO_TEXT_KEYS.some((key) => key in content) || LOGO_IMAGE_KEYS.some((key) => key in content) || LOGO_ALT_KEY in content || LOGO_HREF_KEYS.some((key) => key in content);
|
|
11407
|
-
if (!hasLogoIdentity) return false;
|
|
11408
|
-
const logoText = content[LOGO_TEXT_KEYS[0]] ?? content[LOGO_TEXT_KEYS[1]] ?? readLogoIdentityFromDom().text;
|
|
11409
|
-
const logoAlt = content[LOGO_ALT_KEY] ?? logoText;
|
|
11410
|
-
const rawLogoImage = content[LOGO_IMAGE_URL_KEY] ?? content["footer-logo"] ?? content["footer-logo-image"] ?? null;
|
|
11411
|
-
const logoImageUrl = typeof rawLogoImage === "string" && rawLogoImage.trim() ? rawLogoImage.trim() : null;
|
|
11412
|
-
const imageExplicitlyCleared = LOGO_IMAGE_KEYS.some((key) => key in content) && !logoImageUrl;
|
|
11413
|
-
const logoIsPlaceholder = LOGO_PLACEHOLDER_KEY in content ? content[LOGO_PLACEHOLDER_KEY] !== "false" : !logoImageUrl && (!logoText.trim() || logoText === PLACEHOLDER_BUSINESS_NAME);
|
|
11414
|
-
if (logoImageUrl) {
|
|
11415
|
-
applyLogoImage(logoImageUrl, logoAlt);
|
|
11416
|
-
} else {
|
|
11417
|
-
if (imageExplicitlyCleared) applyLogoImage(null, logoAlt);
|
|
11418
|
-
applyLogoIdentity(logoText, logoIsPlaceholder);
|
|
11419
|
-
}
|
|
11420
|
-
const logoHref = content["nav-logo-href"] ?? content["footer-logo-href"] ?? content["logo-href"];
|
|
11421
|
-
if (typeof logoHref === "string" && logoHref.trim()) {
|
|
11422
|
-
applyLogoHref(logoHref);
|
|
11423
|
-
}
|
|
11424
|
-
return true;
|
|
11425
|
-
}
|
|
11426
|
-
|
|
11427
|
-
// src/lib/logo-size.ts
|
|
11428
|
-
var LOGO_SIZE_DEFAULTS = {
|
|
11429
|
-
navbar: 28,
|
|
11430
|
-
footer: 32
|
|
11431
|
-
};
|
|
11432
|
-
var LOGO_SIZE_MIN = 16;
|
|
11433
|
-
var LOGO_SIZE_MAX = 80;
|
|
11434
|
-
var LOGO_SIZE_DESKTOP_KEYS = {
|
|
11435
|
-
navbar: "nav-logo-size",
|
|
11436
|
-
footer: "footer-logo-size"
|
|
11437
|
-
};
|
|
11438
|
-
var LOGO_SIZE_MOBILE_KEYS = {
|
|
11439
|
-
navbar: "nav-logo-size-mobile",
|
|
11440
|
-
footer: "footer-logo-size-mobile"
|
|
11441
|
-
};
|
|
11442
|
-
var LOGO_SIZE_KEYS = [
|
|
11443
|
-
LOGO_SIZE_DESKTOP_KEYS.navbar,
|
|
11444
|
-
LOGO_SIZE_DESKTOP_KEYS.footer,
|
|
11445
|
-
LOGO_SIZE_MOBILE_KEYS.navbar,
|
|
11446
|
-
LOGO_SIZE_MOBILE_KEYS.footer
|
|
11447
|
-
];
|
|
11448
|
-
function isFooterLogoRoot2(root) {
|
|
11449
|
-
return Boolean(root.closest("footer") || root.closest('[data-ohw-section="footer"]'));
|
|
11450
|
-
}
|
|
11451
|
-
function getLogoPlacement(root) {
|
|
11452
|
-
return isFooterLogoRoot2(root) ? "footer" : "navbar";
|
|
11453
|
-
}
|
|
11454
|
-
function parseLogoSizePx(raw, fallback) {
|
|
11455
|
-
if (raw == null || raw === "") return fallback;
|
|
11456
|
-
const n = Number.parseFloat(raw);
|
|
11457
|
-
if (!Number.isFinite(n)) return fallback;
|
|
11458
|
-
return Math.min(LOGO_SIZE_MAX, Math.max(LOGO_SIZE_MIN, Math.round(n)));
|
|
11459
|
-
}
|
|
11460
|
-
function isMobileLogoSizeFollowing(content, placement) {
|
|
11461
|
-
const raw = content[LOGO_SIZE_MOBILE_KEYS[placement]];
|
|
11462
|
-
return raw == null || raw.trim() === "";
|
|
11463
|
-
}
|
|
11464
|
-
function resolveDesktopLogoSize(content, placement) {
|
|
11465
|
-
return parseLogoSizePx(content[LOGO_SIZE_DESKTOP_KEYS[placement]], LOGO_SIZE_DEFAULTS[placement]);
|
|
11466
|
-
}
|
|
11467
|
-
function resolveMobileLogoSize(content, placement) {
|
|
11468
|
-
if (isMobileLogoSizeFollowing(content, placement)) {
|
|
11469
|
-
return resolveDesktopLogoSize(content, placement);
|
|
11470
|
-
}
|
|
11471
|
-
return parseLogoSizePx(
|
|
11472
|
-
content[LOGO_SIZE_MOBILE_KEYS[placement]],
|
|
11473
|
-
resolveDesktopLogoSize(content, placement)
|
|
11474
|
-
);
|
|
11475
|
-
}
|
|
11476
|
-
function setRootSizeVars(root, desktopPx, mobilePx, following) {
|
|
11477
|
-
root.style.setProperty("--ohw-logo-size", `${desktopPx}px`);
|
|
11478
|
-
if (following) {
|
|
11479
|
-
root.style.removeProperty("--ohw-logo-size-mobile");
|
|
11480
|
-
} else {
|
|
11481
|
-
root.style.setProperty("--ohw-logo-size-mobile", `${mobilePx}px`);
|
|
11482
|
-
}
|
|
11483
|
-
root.querySelectorAll("img").forEach((img) => {
|
|
11484
|
-
img.style.height = "";
|
|
11485
|
-
img.style.maxHeight = "none";
|
|
11486
|
-
img.style.width = "auto";
|
|
11487
|
-
img.style.objectFit = "contain";
|
|
11488
|
-
});
|
|
11489
|
-
}
|
|
11490
|
-
function applyLogoSizes(content) {
|
|
11491
|
-
document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
|
|
11492
|
-
const placement = getLogoPlacement(root);
|
|
11493
|
-
const desktop = resolveDesktopLogoSize(content, placement);
|
|
11494
|
-
const following = isMobileLogoSizeFollowing(content, placement);
|
|
11495
|
-
const mobile = following ? desktop : resolveMobileLogoSize(content, placement);
|
|
11496
|
-
setRootSizeVars(root, desktop, mobile, following);
|
|
11497
|
-
});
|
|
11498
|
-
}
|
|
11499
|
-
function applyLogoSizeToPlacement(placement, desktopPx, mobilePx, following) {
|
|
11500
|
-
document.querySelectorAll('[data-ohw-role="logo"], [data-ohw-logo]').forEach((root) => {
|
|
11501
|
-
if (getLogoPlacement(root) !== placement) return;
|
|
11502
|
-
setRootSizeVars(root, desktopPx, mobilePx, following);
|
|
11489
|
+
const result = insertFooterColumn();
|
|
11490
|
+
const patch = buildFooterColumnEditContentPatch(result);
|
|
11491
|
+
setStoredLinkHref(result.hrefKey, result.href);
|
|
11492
|
+
postToParent2({
|
|
11493
|
+
type: "ow:change",
|
|
11494
|
+
nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
|
|
11503
11495
|
});
|
|
11504
|
-
}
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
const img = logoEl.querySelector('img[data-ohw-key="nav-logo-image"], img[data-ohw-key="footer-logo"], img[data-ohw-key="footer-logo-image"]') ?? logoEl.querySelector("img");
|
|
11508
|
-
if (!img) return false;
|
|
11509
|
-
const src = img.getAttribute("src")?.trim() ?? "";
|
|
11510
|
-
if (!src || src.startsWith("data:")) return false;
|
|
11511
|
-
if (img.style.display === "none") return false;
|
|
11512
|
-
return true;
|
|
11513
|
-
}
|
|
11514
|
-
function getLogoInteractionRect(logoEl) {
|
|
11515
|
-
if (logoHasUploadedImage(logoEl)) {
|
|
11516
|
-
const img = logoEl.querySelector('img[data-ohw-key="nav-logo-image"], img[data-ohw-key="footer-logo"], img[data-ohw-key="footer-logo-image"]') ?? logoEl.querySelector("img");
|
|
11517
|
-
if (img) {
|
|
11518
|
-
const r2 = img.getBoundingClientRect();
|
|
11519
|
-
if (r2.width > 0 && r2.height > 0) return r2;
|
|
11520
|
-
}
|
|
11521
|
-
}
|
|
11522
|
-
const text = logoEl.querySelector(
|
|
11523
|
-
'[data-ohw-key="nav-logo-text"], [data-ohw-key="footer-logo-text"]'
|
|
11524
|
-
);
|
|
11525
|
-
if (text) {
|
|
11526
|
-
const style = window.getComputedStyle(text);
|
|
11527
|
-
if (style.display !== "none" && style.visibility !== "hidden") {
|
|
11528
|
-
const r2 = text.getBoundingClientRect();
|
|
11529
|
-
if (r2.width > 0 && r2.height > 0) return r2;
|
|
11530
|
-
}
|
|
11531
|
-
}
|
|
11532
|
-
return logoEl.getBoundingClientRect();
|
|
11533
|
-
}
|
|
11534
|
-
function readLogoSizeState(content, placement) {
|
|
11535
|
-
const desktopPx = resolveDesktopLogoSize(content, placement);
|
|
11536
|
-
const mobileFollowing = isMobileLogoSizeFollowing(content, placement);
|
|
11537
|
-
const mobilePx = mobileFollowing ? desktopPx : resolveMobileLogoSize(content, placement);
|
|
11538
|
-
return { desktopPx, mobilePx, mobileFollowing };
|
|
11496
|
+
postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
|
|
11497
|
+
enforceLinkHrefs();
|
|
11498
|
+
return result;
|
|
11539
11499
|
}
|
|
11540
11500
|
|
|
11541
11501
|
// src/lib/site-wide-scope.ts
|
|
11542
11502
|
function getLogoElement(el) {
|
|
11543
11503
|
const marked = el.closest('[data-ohw-role="logo"], [data-ohw-logo]');
|
|
11544
11504
|
if (marked) return marked;
|
|
11545
|
-
if (el.closest('[data-ohw-editable="icon"]')) return null;
|
|
11546
11505
|
const root = el.closest("nav, [data-ohw-nav-root], footer");
|
|
11547
11506
|
if (!root) return null;
|
|
11548
11507
|
const anchor = el.closest("a");
|
|
@@ -11576,38 +11535,6 @@ function isSiteWideScopeActive(args) {
|
|
|
11576
11535
|
return isSiteWideElement(args.selected) || isSiteWideElement(args.hoveredItem) || isSiteWideElement(args.hoveredNavContainer) || isSiteWideElement(args.active);
|
|
11577
11536
|
}
|
|
11578
11537
|
|
|
11579
|
-
// src/lib/add-footer-column.ts
|
|
11580
|
-
function buildFooterColumnEditContentPatch(result) {
|
|
11581
|
-
return {
|
|
11582
|
-
[result.headingKey]: result.heading,
|
|
11583
|
-
[result.hrefKey]: result.href,
|
|
11584
|
-
[result.labelKey]: result.label,
|
|
11585
|
-
[FOOTER_ORDER_KEY]: JSON.stringify(result.order)
|
|
11586
|
-
};
|
|
11587
|
-
}
|
|
11588
|
-
function addFooterColumnWithPersist({
|
|
11589
|
-
postToParent: postToParent2
|
|
11590
|
-
}) {
|
|
11591
|
-
if (!canAddFooterColumn()) {
|
|
11592
|
-
postToParent2({
|
|
11593
|
-
type: "ow:toast",
|
|
11594
|
-
title: `Maximum ${MAX_FOOTER_COLUMNS} columns`,
|
|
11595
|
-
toastType: "error"
|
|
11596
|
-
});
|
|
11597
|
-
return null;
|
|
11598
|
-
}
|
|
11599
|
-
const result = insertFooterColumn();
|
|
11600
|
-
const patch = buildFooterColumnEditContentPatch(result);
|
|
11601
|
-
setStoredLinkHref(result.hrefKey, result.href);
|
|
11602
|
-
postToParent2({
|
|
11603
|
-
type: "ow:change",
|
|
11604
|
-
nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
|
|
11605
|
-
});
|
|
11606
|
-
postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
|
|
11607
|
-
enforceLinkHrefs();
|
|
11608
|
-
return result;
|
|
11609
|
-
}
|
|
11610
|
-
|
|
11611
11538
|
// src/ui/FloatingPanel.tsx
|
|
11612
11539
|
import {
|
|
11613
11540
|
useCallback as useCallback5,
|
|
@@ -11617,7 +11544,7 @@ import {
|
|
|
11617
11544
|
useState as useState8
|
|
11618
11545
|
} from "react";
|
|
11619
11546
|
import { X as X5 } from "lucide-react";
|
|
11620
|
-
import { jsx as
|
|
11547
|
+
import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
11621
11548
|
var PANEL_WIDTH = 256;
|
|
11622
11549
|
var EDGE_MARGIN = 16;
|
|
11623
11550
|
function getVisibleClip(parentScroll) {
|
|
@@ -11732,7 +11659,7 @@ function FloatingPanel({
|
|
|
11732
11659
|
}, [open]);
|
|
11733
11660
|
useEffect9(() => () => document.documentElement.removeAttribute("data-ohw-panel-dragging"), []);
|
|
11734
11661
|
if (!open) return null;
|
|
11735
|
-
return /* @__PURE__ */
|
|
11662
|
+
return /* @__PURE__ */ jsxs17(
|
|
11736
11663
|
"div",
|
|
11737
11664
|
{
|
|
11738
11665
|
ref: panelRef,
|
|
@@ -11749,7 +11676,7 @@ function FloatingPanel({
|
|
|
11749
11676
|
onPointerDown: (e) => e.stopPropagation(),
|
|
11750
11677
|
onClick: (e) => e.stopPropagation(),
|
|
11751
11678
|
children: [
|
|
11752
|
-
/* @__PURE__ */
|
|
11679
|
+
/* @__PURE__ */ jsxs17(
|
|
11753
11680
|
"div",
|
|
11754
11681
|
{
|
|
11755
11682
|
"data-ohw-floating-panel-header": "",
|
|
@@ -11759,14 +11686,14 @@ function FloatingPanel({
|
|
|
11759
11686
|
onPointerUp: endDrag,
|
|
11760
11687
|
onPointerCancel: endDrag,
|
|
11761
11688
|
children: [
|
|
11762
|
-
/* @__PURE__ */
|
|
11763
|
-
/* @__PURE__ */
|
|
11764
|
-
icon ? /* @__PURE__ */
|
|
11765
|
-
/* @__PURE__ */
|
|
11689
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
|
|
11690
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-2", children: [
|
|
11691
|
+
icon ? /* @__PURE__ */ jsx27("span", { className: "shrink-0 text-foreground", children: icon }) : null,
|
|
11692
|
+
/* @__PURE__ */ jsx27("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
|
|
11766
11693
|
] }),
|
|
11767
|
-
context ? /* @__PURE__ */
|
|
11694
|
+
context ? /* @__PURE__ */ jsx27("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
|
|
11768
11695
|
] }),
|
|
11769
|
-
/* @__PURE__ */
|
|
11696
|
+
/* @__PURE__ */ jsx27(
|
|
11770
11697
|
"button",
|
|
11771
11698
|
{
|
|
11772
11699
|
type: "button",
|
|
@@ -11778,13 +11705,13 @@ function FloatingPanel({
|
|
|
11778
11705
|
onClose();
|
|
11779
11706
|
},
|
|
11780
11707
|
onPointerDown: (e) => e.stopPropagation(),
|
|
11781
|
-
children: /* @__PURE__ */
|
|
11708
|
+
children: /* @__PURE__ */ jsx27(X5, { size: 16, "aria-hidden": true })
|
|
11782
11709
|
}
|
|
11783
11710
|
)
|
|
11784
11711
|
]
|
|
11785
11712
|
}
|
|
11786
11713
|
),
|
|
11787
|
-
/* @__PURE__ */
|
|
11714
|
+
/* @__PURE__ */ jsx27(
|
|
11788
11715
|
"div",
|
|
11789
11716
|
{
|
|
11790
11717
|
"data-ohw-floating-panel-body": "",
|
|
@@ -11797,117 +11724,6 @@ function FloatingPanel({
|
|
|
11797
11724
|
);
|
|
11798
11725
|
}
|
|
11799
11726
|
|
|
11800
|
-
// src/ui/logo-size-panel.tsx
|
|
11801
|
-
import { ArrowUpRight, Link as Link2 } from "lucide-react";
|
|
11802
|
-
import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
11803
|
-
function SizeSlider({
|
|
11804
|
-
value,
|
|
11805
|
-
onChange
|
|
11806
|
-
}) {
|
|
11807
|
-
const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
|
|
11808
|
-
return /* @__PURE__ */ jsxs17("div", { className: "flex w-full flex-col gap-3", children: [
|
|
11809
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
|
|
11810
|
-
/* @__PURE__ */ jsx27("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
|
|
11811
|
-
/* @__PURE__ */ jsxs17("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
|
|
11812
|
-
value,
|
|
11813
|
-
" px"
|
|
11814
|
-
] })
|
|
11815
|
-
] }),
|
|
11816
|
-
/* @__PURE__ */ jsxs17("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
|
|
11817
|
-
/* @__PURE__ */ jsx27(
|
|
11818
|
-
"div",
|
|
11819
|
-
{
|
|
11820
|
-
className: "absolute inset-y-0 left-0 rounded-full bg-primary",
|
|
11821
|
-
style: { width: `${pct}%` }
|
|
11822
|
-
}
|
|
11823
|
-
),
|
|
11824
|
-
/* @__PURE__ */ jsx27(
|
|
11825
|
-
"input",
|
|
11826
|
-
{
|
|
11827
|
-
type: "range",
|
|
11828
|
-
min: LOGO_SIZE_MIN,
|
|
11829
|
-
max: LOGO_SIZE_MAX,
|
|
11830
|
-
step: 1,
|
|
11831
|
-
value,
|
|
11832
|
-
"aria-label": "Logo size",
|
|
11833
|
-
className: cn(
|
|
11834
|
-
"absolute inset-0 h-full w-full cursor-pointer appearance-none bg-transparent",
|
|
11835
|
-
"[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-5",
|
|
11836
|
-
"[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:border-2",
|
|
11837
|
-
"[&::-webkit-slider-thumb]:border-primary [&::-webkit-slider-thumb]:bg-background",
|
|
11838
|
-
"[&::-moz-range-thumb]:size-5 [&::-moz-range-thumb]:rounded-full",
|
|
11839
|
-
"[&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-primary",
|
|
11840
|
-
"[&::-moz-range-thumb]:bg-background"
|
|
11841
|
-
),
|
|
11842
|
-
onChange: (e) => onChange(Number(e.target.value))
|
|
11843
|
-
}
|
|
11844
|
-
)
|
|
11845
|
-
] })
|
|
11846
|
-
] });
|
|
11847
|
-
}
|
|
11848
|
-
function LogoSizePanel({
|
|
11849
|
-
viewport,
|
|
11850
|
-
sizePx,
|
|
11851
|
-
mobileFollowing = true,
|
|
11852
|
-
onSizeChange,
|
|
11853
|
-
onCustomizeMobile,
|
|
11854
|
-
onResetMobile,
|
|
11855
|
-
onUpdateEverywhere,
|
|
11856
|
-
className
|
|
11857
|
-
}) {
|
|
11858
|
-
const showFollowing = viewport === "mobile" && mobileFollowing;
|
|
11859
|
-
const showMobileSlider = viewport === "mobile" && !mobileFollowing;
|
|
11860
|
-
const showDesktopSlider = viewport === "desktop";
|
|
11861
|
-
return /* @__PURE__ */ jsxs17("div", { className: cn("flex w-full flex-col gap-4", className), children: [
|
|
11862
|
-
showFollowing ? /* @__PURE__ */ jsxs17("div", { className: "flex w-full flex-col gap-2", children: [
|
|
11863
|
-
/* @__PURE__ */ jsxs17("div", { className: "flex items-start gap-1", children: [
|
|
11864
|
-
/* @__PURE__ */ jsx27(Link2, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
|
|
11865
|
-
/* @__PURE__ */ jsx27("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
|
|
11866
|
-
] }),
|
|
11867
|
-
/* @__PURE__ */ jsx27("p", { className: "text-sm leading-5 text-muted-foreground", children: "Mobile uses the desktop size until you customize it. Change the desktop size and it follows automatically." }),
|
|
11868
|
-
/* @__PURE__ */ jsx27(
|
|
11869
|
-
Button,
|
|
11870
|
-
{
|
|
11871
|
-
type: "button",
|
|
11872
|
-
variant: "outline",
|
|
11873
|
-
size: "sm",
|
|
11874
|
-
className: "h-9 w-full min-w-0 cursor-pointer",
|
|
11875
|
-
onClick: onCustomizeMobile,
|
|
11876
|
-
children: "Customize for mobile"
|
|
11877
|
-
}
|
|
11878
|
-
)
|
|
11879
|
-
] }) : null,
|
|
11880
|
-
showDesktopSlider || showMobileSlider ? /* @__PURE__ */ jsx27(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
|
|
11881
|
-
showMobileSlider ? /* @__PURE__ */ jsx27(
|
|
11882
|
-
Button,
|
|
11883
|
-
{
|
|
11884
|
-
type: "button",
|
|
11885
|
-
variant: "outline",
|
|
11886
|
-
size: "sm",
|
|
11887
|
-
className: "h-9 w-full min-w-0 cursor-pointer",
|
|
11888
|
-
onClick: onResetMobile,
|
|
11889
|
-
children: "Reset to desktop size"
|
|
11890
|
-
}
|
|
11891
|
-
) : null,
|
|
11892
|
-
/* @__PURE__ */ jsx27("div", { className: "h-px w-full bg-border", role: "separator" }),
|
|
11893
|
-
/* @__PURE__ */ jsxs17(
|
|
11894
|
-
Button,
|
|
11895
|
-
{
|
|
11896
|
-
type: "button",
|
|
11897
|
-
variant: "outline",
|
|
11898
|
-
size: "sm",
|
|
11899
|
-
className: "h-9 w-full min-w-0 cursor-pointer gap-1",
|
|
11900
|
-
onClick: onUpdateEverywhere,
|
|
11901
|
-
children: [
|
|
11902
|
-
"Update logo everywhere",
|
|
11903
|
-
/* @__PURE__ */ jsx27(ArrowUpRight, { size: 16, "aria-hidden": true })
|
|
11904
|
-
]
|
|
11905
|
-
}
|
|
11906
|
-
),
|
|
11907
|
-
/* @__PURE__ */ jsx27("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
|
|
11908
|
-
] });
|
|
11909
|
-
}
|
|
11910
|
-
|
|
11911
11727
|
// src/ui/socials-display-panel.tsx
|
|
11912
11728
|
import { jsx as jsx28, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
11913
11729
|
function DisplaySwitch({
|
|
@@ -12676,8 +12492,10 @@ function getLinkHref3(el) {
|
|
|
12676
12492
|
}
|
|
12677
12493
|
function collectEditableNodes(extraContent, root = document) {
|
|
12678
12494
|
const isScoped = root !== document;
|
|
12679
|
-
const editableEls = Array.from(
|
|
12680
|
-
|
|
12495
|
+
const editableEls = Array.from(
|
|
12496
|
+
root.querySelectorAll('[data-ohw-editable]:not([data-ohw-editable="form"])')
|
|
12497
|
+
);
|
|
12498
|
+
if (isScoped && root instanceof HTMLElement && root.matches('[data-ohw-editable]:not([data-ohw-editable="form"])')) {
|
|
12681
12499
|
editableEls.unshift(root);
|
|
12682
12500
|
}
|
|
12683
12501
|
const nodes = editableEls.map((el) => {
|
|
@@ -12752,18 +12570,6 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
12752
12570
|
}
|
|
12753
12571
|
if (extraContent && !isScoped) {
|
|
12754
12572
|
applyNavFooterDeleteOverrides(byKey, extraContent);
|
|
12755
|
-
for (const key of LOGO_IMAGE_KEYS) {
|
|
12756
|
-
if (!(key in extraContent)) continue;
|
|
12757
|
-
byKey.set(key, { key, type: "image", text: extraContent[key] ?? "" });
|
|
12758
|
-
}
|
|
12759
|
-
for (const key of [LOGO_PLACEHOLDER_KEY, LOGO_ALT_KEY]) {
|
|
12760
|
-
if (!(key in extraContent)) continue;
|
|
12761
|
-
byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
|
|
12762
|
-
}
|
|
12763
|
-
for (const key of LOGO_SIZE_KEYS) {
|
|
12764
|
-
if (!(key in extraContent)) continue;
|
|
12765
|
-
byKey.set(key, { key, type: "meta", text: extraContent[key] ?? "" });
|
|
12766
|
-
}
|
|
12767
12573
|
}
|
|
12768
12574
|
return Array.from(byKey.values());
|
|
12769
12575
|
}
|
|
@@ -13137,7 +12943,7 @@ function Badge({ className, variant, ...props }) {
|
|
|
13137
12943
|
}
|
|
13138
12944
|
|
|
13139
12945
|
// src/OhhwellsBridge.tsx
|
|
13140
|
-
import { Link as
|
|
12946
|
+
import { Link as Link2, Plus as Plus4, Settings } from "lucide-react";
|
|
13141
12947
|
import { Fragment as Fragment8, jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
13142
12948
|
var PRIMARY3 = "#0885FE";
|
|
13143
12949
|
var IMAGE_FADE_MS = 300;
|
|
@@ -13232,10 +13038,21 @@ function parseSchedulingInsertAfter(insertAfter) {
|
|
|
13232
13038
|
insertBefore: insertAfter.slice(idx + INSERT_BEFORE_MARKER.length)
|
|
13233
13039
|
};
|
|
13234
13040
|
}
|
|
13235
|
-
function
|
|
13236
|
-
|
|
13237
|
-
const
|
|
13238
|
-
|
|
13041
|
+
function resolveSchedulingInsert(insertAfter, explicitInsertBefore) {
|
|
13042
|
+
const parsed = parseSchedulingInsertAfter(insertAfter);
|
|
13043
|
+
const insertBefore = explicitInsertBefore ?? parsed.insertBefore;
|
|
13044
|
+
const effectiveInsertAfter = insertBefore && parsed.insertBefore === null ? `${insertAfter}${INSERT_BEFORE_MARKER}${insertBefore}` : insertAfter;
|
|
13045
|
+
return { effectiveInsertAfter, insertBefore };
|
|
13046
|
+
}
|
|
13047
|
+
function getSchedulingMountPoint(insertAfter) {
|
|
13048
|
+
const { anchor } = parseSchedulingInsertAfter(insertAfter);
|
|
13049
|
+
let anchorEl = document.querySelector(`[data-ohw-section="${anchor}"]`);
|
|
13050
|
+
if (!anchorEl && anchor === "scheduling") {
|
|
13051
|
+
const widgets = Array.from(document.querySelectorAll('[data-ohw-section^="scheduling-"]'));
|
|
13052
|
+
anchorEl = widgets.at(-1) ?? null;
|
|
13053
|
+
}
|
|
13054
|
+
if (!anchorEl) return null;
|
|
13055
|
+
return anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
13239
13056
|
}
|
|
13240
13057
|
function schedulingMountDepth(insertAfter) {
|
|
13241
13058
|
if (!insertAfter.includes(INSERT_BEFORE_MARKER)) return 0;
|
|
@@ -13252,7 +13069,8 @@ function getPageSchedulingEntries(raw) {
|
|
|
13252
13069
|
}
|
|
13253
13070
|
}
|
|
13254
13071
|
function isSchedulingWidgetMissing(entry) {
|
|
13255
|
-
|
|
13072
|
+
const { effectiveInsertAfter } = resolveSchedulingInsert(entry.insertAfter);
|
|
13073
|
+
return !document.querySelector(`[data-ohw-section="${schedulingSectionId(effectiveInsertAfter)}"]`);
|
|
13256
13074
|
}
|
|
13257
13075
|
function hasMissingSchedulingWidgets(entries) {
|
|
13258
13076
|
return entries.some(isSchedulingWidgetMissing);
|
|
@@ -13282,17 +13100,16 @@ function initSectionsFromContent(content, removeExisting = false) {
|
|
|
13282
13100
|
} catch {
|
|
13283
13101
|
}
|
|
13284
13102
|
}
|
|
13285
|
-
function mountSchedulingWidget(
|
|
13286
|
-
const
|
|
13287
|
-
const sectionId = schedulingSectionId(
|
|
13103
|
+
function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId, explicitInsertBefore) {
|
|
13104
|
+
const { effectiveInsertAfter, insertBefore } = resolveSchedulingInsert(insertAfter, explicitInsertBefore);
|
|
13105
|
+
const sectionId = schedulingSectionId(effectiveInsertAfter);
|
|
13288
13106
|
if (document.querySelector(`[data-ohw-section="${sectionId}"]`)) return false;
|
|
13289
|
-
const
|
|
13290
|
-
if (!
|
|
13291
|
-
const mountPoint = anchorEl.closest('[data-ohw-section-container="scheduling"]') ?? anchorEl;
|
|
13107
|
+
const mountPoint = getSchedulingMountPoint(effectiveInsertAfter);
|
|
13108
|
+
if (!mountPoint) return false;
|
|
13292
13109
|
const container = document.createElement("div");
|
|
13293
13110
|
container.dataset.ohwSectionContainer = "scheduling";
|
|
13294
|
-
if (
|
|
13295
|
-
const beforeAnchor = document.querySelector(`[data-ohw-section="${
|
|
13111
|
+
if (insertBefore) {
|
|
13112
|
+
const beforeAnchor = document.querySelector(`[data-ohw-section="${insertBefore}"]`);
|
|
13296
13113
|
const beforePoint = beforeAnchor?.closest('[data-ohw-section-container="scheduling"]') ?? beforeAnchor;
|
|
13297
13114
|
if (!beforePoint) return false;
|
|
13298
13115
|
beforePoint.insertAdjacentElement("beforebegin", container);
|
|
@@ -13303,25 +13120,19 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
|
|
|
13303
13120
|
}
|
|
13304
13121
|
tail.insertAdjacentElement("afterend", container);
|
|
13305
13122
|
}
|
|
13306
|
-
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13310
|
-
|
|
13311
|
-
|
|
13312
|
-
|
|
13313
|
-
|
|
13314
|
-
|
|
13315
|
-
|
|
13316
|
-
|
|
13317
|
-
|
|
13318
|
-
|
|
13319
|
-
});
|
|
13320
|
-
} catch (err) {
|
|
13321
|
-
console.error("[ow:scheduling] render threw", err);
|
|
13322
|
-
container.remove();
|
|
13323
|
-
return false;
|
|
13324
|
-
}
|
|
13123
|
+
const root = createRoot2(container);
|
|
13124
|
+
flushSync2(() => {
|
|
13125
|
+
root.render(
|
|
13126
|
+
/* @__PURE__ */ jsx33(
|
|
13127
|
+
SchedulingWidget,
|
|
13128
|
+
{
|
|
13129
|
+
notifyOnConnect,
|
|
13130
|
+
initialScheduleId: scheduleId,
|
|
13131
|
+
insertAfter: effectiveInsertAfter
|
|
13132
|
+
}
|
|
13133
|
+
)
|
|
13134
|
+
);
|
|
13135
|
+
});
|
|
13325
13136
|
const tracker = getSectionsTracker();
|
|
13326
13137
|
let sections = [];
|
|
13327
13138
|
try {
|
|
@@ -13329,12 +13140,10 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
|
|
|
13329
13140
|
} catch {
|
|
13330
13141
|
}
|
|
13331
13142
|
const inEditor = typeof window !== "undefined" && window.self !== window.top;
|
|
13332
|
-
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter ===
|
|
13143
|
+
if (inEditor && !sections.find((s) => s.type === "scheduling" && s.insertAfter === effectiveInsertAfter)) {
|
|
13333
13144
|
sections.push({
|
|
13334
13145
|
type: "scheduling",
|
|
13335
|
-
insertAfter:
|
|
13336
|
-
anchorId,
|
|
13337
|
-
beforeId: beforeId ?? null,
|
|
13146
|
+
insertAfter: effectiveInsertAfter,
|
|
13338
13147
|
pagePath: window.location.pathname,
|
|
13339
13148
|
...scheduleId ? { scheduleId } : {}
|
|
13340
13149
|
});
|
|
@@ -13348,8 +13157,7 @@ function mountSchedulingEntries(entries, notifyOnConnect = false) {
|
|
|
13348
13157
|
for (let i = pending.length - 1; i >= 0; i--) {
|
|
13349
13158
|
const entry = pending[i];
|
|
13350
13159
|
const shouldNotify = typeof notifyOnConnect === "function" ? notifyOnConnect(entry) : notifyOnConnect;
|
|
13351
|
-
|
|
13352
|
-
if (mountSchedulingWidget(anchorId, shouldNotify, entry.scheduleId ?? null, beforeId, entry.insertAfter)) {
|
|
13160
|
+
if (mountSchedulingWidget(entry.insertAfter, shouldNotify, entry.scheduleId)) {
|
|
13353
13161
|
pending.splice(i, 1);
|
|
13354
13162
|
}
|
|
13355
13163
|
}
|
|
@@ -13422,7 +13230,11 @@ function isIconEditable(el) {
|
|
|
13422
13230
|
return el.dataset.ohwEditable === "icon";
|
|
13423
13231
|
}
|
|
13424
13232
|
var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
|
|
13425
|
-
var
|
|
13233
|
+
var EDITOR_CHROME_SELECTOR = '[data-ohw-toolbar], [data-ohw-form-toolbar], [data-ohw-field-toolbar], [data-ohw-item-toolbar], [data-ohw-more-menu], [data-ohw-state-toggle], [data-ohw-max-badge], [data-slot="dropdown-menu-content"], [data-slot="dropdown-menu-item"]';
|
|
13234
|
+
function isOverEditorChrome(x, y) {
|
|
13235
|
+
return document.elementsFromPoint(x, y).some((el) => el instanceof HTMLElement && el.matches(EDITOR_CHROME_SELECTOR));
|
|
13236
|
+
}
|
|
13237
|
+
var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"]):not([data-ohw-editable="form"])';
|
|
13426
13238
|
function getVideoEl2(el) {
|
|
13427
13239
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
13428
13240
|
}
|
|
@@ -13493,13 +13305,6 @@ function isInsideLinkEditor(target) {
|
|
|
13493
13305
|
target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest("[data-ohw-more-menu]") || target.closest('[data-slot="dropdown-menu-content"]') || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
|
|
13494
13306
|
);
|
|
13495
13307
|
}
|
|
13496
|
-
function isInsideFloatingPanel(target) {
|
|
13497
|
-
return Boolean(target.closest("[data-ohw-floating-panel]"));
|
|
13498
|
-
}
|
|
13499
|
-
function isPointOverFloatingPanel(clientX, clientY) {
|
|
13500
|
-
const el = document.elementFromPoint(clientX, clientY);
|
|
13501
|
-
return Boolean(el instanceof Element && el.closest("[data-ohw-floating-panel]"));
|
|
13502
|
-
}
|
|
13503
13308
|
function getHrefKeyFromElement(el) {
|
|
13504
13309
|
if (!el) return null;
|
|
13505
13310
|
const anchor = el.closest("[data-ohw-href-key]");
|
|
@@ -13547,7 +13352,8 @@ function isNavItemPointerTarget(el) {
|
|
|
13547
13352
|
function getNavigationItemAnchor(el) {
|
|
13548
13353
|
const anchor = el.matches("[data-ohw-href-key]") ? el : el.closest("[data-ohw-href-key]");
|
|
13549
13354
|
if (!anchor) return null;
|
|
13550
|
-
if (!anchor.querySelector('[data-ohw-editable="text"]') && !getSocialItem(anchor))
|
|
13355
|
+
if (!anchor.matches('[data-ohw-editable="text"], [data-ohw-editable="plain"]') && !anchor.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') && !getSocialItem(anchor))
|
|
13356
|
+
return null;
|
|
13551
13357
|
if (!isNavItemPointerTarget(anchor)) return null;
|
|
13552
13358
|
return anchor;
|
|
13553
13359
|
}
|
|
@@ -13737,7 +13543,7 @@ function getNavigationSelectionParent(el) {
|
|
|
13737
13543
|
if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup2(el))) {
|
|
13738
13544
|
return getFooterLinksContainer();
|
|
13739
13545
|
}
|
|
13740
|
-
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") ||
|
|
13546
|
+
if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-nav-drawer") || isFooterLinksContainer(el)) {
|
|
13741
13547
|
return getNavigationRoot(el);
|
|
13742
13548
|
}
|
|
13743
13549
|
return null;
|
|
@@ -14294,7 +14100,7 @@ function FloatingToolbar({
|
|
|
14294
14100
|
e.preventDefault();
|
|
14295
14101
|
e.stopPropagation();
|
|
14296
14102
|
},
|
|
14297
|
-
children: /* @__PURE__ */ jsx33(
|
|
14103
|
+
children: /* @__PURE__ */ jsx33(Link2, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
14298
14104
|
}
|
|
14299
14105
|
) : null
|
|
14300
14106
|
] })
|
|
@@ -14330,7 +14136,6 @@ function StateToggle({
|
|
|
14330
14136
|
);
|
|
14331
14137
|
}
|
|
14332
14138
|
var contentCache = /* @__PURE__ */ new Map();
|
|
14333
|
-
var fetchedContentPaths = /* @__PURE__ */ new Set();
|
|
14334
14139
|
function resolveSubdomain(subdomainFromQuery) {
|
|
14335
14140
|
if (subdomainFromQuery) return subdomainFromQuery;
|
|
14336
14141
|
if (typeof window !== "undefined") {
|
|
@@ -14425,14 +14230,8 @@ function OhhwellsBridge() {
|
|
|
14425
14230
|
});
|
|
14426
14231
|
const selectFrameRef = useRef9(() => {
|
|
14427
14232
|
});
|
|
14428
|
-
const selectLogoRef = useRef9(() => {
|
|
14429
|
-
});
|
|
14430
|
-
const openLogoSizePanelRef = useRef9(() => {
|
|
14431
|
-
});
|
|
14432
14233
|
const deselectRef = useRef9(() => {
|
|
14433
14234
|
});
|
|
14434
|
-
const closeFloatingPanelOnlyRef = useRef9(() => {
|
|
14435
|
-
});
|
|
14436
14235
|
const reselectNavigationItemRef = useRef9(() => {
|
|
14437
14236
|
});
|
|
14438
14237
|
const commitNavigationTextEditRef = useRef9(() => {
|
|
@@ -14448,6 +14247,182 @@ function OhhwellsBridge() {
|
|
|
14448
14247
|
const sectionsLoadedRef = useRef9(false);
|
|
14449
14248
|
const pendingScheduleConfigRequests = useRef9([]);
|
|
14450
14249
|
const [toolbarRect, setToolbarRect] = useState11(null);
|
|
14250
|
+
const [formPickRect, setFormPickRect] = useState11(null);
|
|
14251
|
+
const formPickElRef = useRef9(null);
|
|
14252
|
+
const [formViewState, setFormViewStateUi] = useState11("default");
|
|
14253
|
+
const [formPickCount, setFormPickCount] = useState11(null);
|
|
14254
|
+
const [formHoverRect, setFormHoverRect] = useState11(null);
|
|
14255
|
+
const formHoverElRef = useRef9(null);
|
|
14256
|
+
const [fieldPickRect, setFieldPickRect] = useState11(null);
|
|
14257
|
+
const fieldPickElRef = useRef9(null);
|
|
14258
|
+
const [fieldPickState, setFieldPickState] = useState11(null);
|
|
14259
|
+
const [fieldTypePickerOpen, setFieldTypePickerOpen] = useState11(false);
|
|
14260
|
+
const clearFormPick = useCallback7(() => {
|
|
14261
|
+
const form = formPickElRef.current;
|
|
14262
|
+
const editing = fieldPickElRef.current;
|
|
14263
|
+
if (commitPlaceholderEdit(editing) && editing) {
|
|
14264
|
+
const owner = editing.closest('[data-ohw-editable="form"]');
|
|
14265
|
+
if (owner) persistFieldsRef.current(owner);
|
|
14266
|
+
}
|
|
14267
|
+
if (form) {
|
|
14268
|
+
const key = formKeyOf(form);
|
|
14269
|
+
if (key) setFormViewState(form, key, "default", successInitialFor(form, key, editContentRef.current));
|
|
14270
|
+
}
|
|
14271
|
+
setFormViewStateUi("default");
|
|
14272
|
+
setFormPickCount(null);
|
|
14273
|
+
setFieldTypePickerOpen(false);
|
|
14274
|
+
fieldPickElRef.current = null;
|
|
14275
|
+
setFieldPickRect(null);
|
|
14276
|
+
setFieldPickState(null);
|
|
14277
|
+
formPickElRef.current = null;
|
|
14278
|
+
setFormPickRect(null);
|
|
14279
|
+
}, []);
|
|
14280
|
+
const clearFieldPick = useCallback7(() => {
|
|
14281
|
+
const wrapper = fieldPickElRef.current;
|
|
14282
|
+
if (commitPlaceholderEdit(wrapper) && wrapper) {
|
|
14283
|
+
const form = wrapper.closest('[data-ohw-editable="form"]');
|
|
14284
|
+
if (form) persistFieldsRef.current(form);
|
|
14285
|
+
}
|
|
14286
|
+
fieldPickElRef.current = null;
|
|
14287
|
+
setFieldPickRect(null);
|
|
14288
|
+
setFieldPickState(null);
|
|
14289
|
+
}, []);
|
|
14290
|
+
const persistFieldsRef = useRef9(() => {
|
|
14291
|
+
});
|
|
14292
|
+
const persistFields = useCallback7(
|
|
14293
|
+
(form) => {
|
|
14294
|
+
const key = formKeyOf(form);
|
|
14295
|
+
if (!key) return;
|
|
14296
|
+
const json = JSON.stringify(readFieldsFromDom(form));
|
|
14297
|
+
editContentRef.current = { ...editContentRef.current, [fieldsKey(key)]: json };
|
|
14298
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: fieldsKey(key), text: json }] });
|
|
14299
|
+
},
|
|
14300
|
+
[]
|
|
14301
|
+
);
|
|
14302
|
+
persistFieldsRef.current = persistFields;
|
|
14303
|
+
const selectField = useCallback7((wrapper) => {
|
|
14304
|
+
if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
|
|
14305
|
+
commitPlaceholderEdit(fieldPickElRef.current);
|
|
14306
|
+
}
|
|
14307
|
+
syncRequiredMark(wrapper);
|
|
14308
|
+
beginPlaceholderEdit(wrapper);
|
|
14309
|
+
formHoverElRef.current = null;
|
|
14310
|
+
setFormHoverRect(null);
|
|
14311
|
+
fieldPickElRef.current = wrapper;
|
|
14312
|
+
setFieldPickRect(wrapper.getBoundingClientRect());
|
|
14313
|
+
setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
|
|
14314
|
+
setFieldTypePickerOpen(false);
|
|
14315
|
+
}, []);
|
|
14316
|
+
const withSelectedField = useCallback7(
|
|
14317
|
+
(run) => {
|
|
14318
|
+
const wrapper = fieldPickElRef.current;
|
|
14319
|
+
const form = formPickElRef.current;
|
|
14320
|
+
if (!wrapper || !form) return;
|
|
14321
|
+
commitPlaceholderEdit(wrapper);
|
|
14322
|
+
run(form, wrapper);
|
|
14323
|
+
persistFields(form);
|
|
14324
|
+
beginPlaceholderEdit(wrapper);
|
|
14325
|
+
setFormPickRect(form.getBoundingClientRect());
|
|
14326
|
+
},
|
|
14327
|
+
[persistFields]
|
|
14328
|
+
);
|
|
14329
|
+
const handleFieldTypeChange = useCallback7(
|
|
14330
|
+
(type) => withSelectedField((_form, wrapper) => {
|
|
14331
|
+
applyFieldType(wrapper, type);
|
|
14332
|
+
selectField(wrapper);
|
|
14333
|
+
}),
|
|
14334
|
+
[selectField, withSelectedField]
|
|
14335
|
+
);
|
|
14336
|
+
const handleFieldRequiredToggle = useCallback7(
|
|
14337
|
+
() => withSelectedField((_form, wrapper) => {
|
|
14338
|
+
setFieldRequired(wrapper, !isFieldRequired(wrapper));
|
|
14339
|
+
selectField(wrapper);
|
|
14340
|
+
}),
|
|
14341
|
+
[selectField, withSelectedField]
|
|
14342
|
+
);
|
|
14343
|
+
const handleFieldDuplicate = useCallback7(
|
|
14344
|
+
() => withSelectedField((form, wrapper) => {
|
|
14345
|
+
const copy = duplicateField(form, wrapper);
|
|
14346
|
+
selectField(copy);
|
|
14347
|
+
}),
|
|
14348
|
+
[selectField, withSelectedField]
|
|
14349
|
+
);
|
|
14350
|
+
const handleFieldDelete = useCallback7(
|
|
14351
|
+
() => withSelectedField((_form, wrapper) => {
|
|
14352
|
+
removeField(wrapper);
|
|
14353
|
+
clearFieldPick();
|
|
14354
|
+
postToParentRef.current({ type: "ow:toast", title: "Form field deleted" });
|
|
14355
|
+
}),
|
|
14356
|
+
[clearFieldPick, withSelectedField]
|
|
14357
|
+
);
|
|
14358
|
+
const handleAddField = useCallback7(
|
|
14359
|
+
(type) => {
|
|
14360
|
+
const form = formPickElRef.current;
|
|
14361
|
+
if (!form) return;
|
|
14362
|
+
const wrapper = insertField(form, type);
|
|
14363
|
+
setFieldTypePickerOpen(false);
|
|
14364
|
+
if (!wrapper) return;
|
|
14365
|
+
persistFields(form);
|
|
14366
|
+
setFormPickRect(null);
|
|
14367
|
+
requestAnimationFrame(() => {
|
|
14368
|
+
selectField(wrapper);
|
|
14369
|
+
wrapper.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
14370
|
+
});
|
|
14371
|
+
},
|
|
14372
|
+
[persistFields, selectField]
|
|
14373
|
+
);
|
|
14374
|
+
const fieldDragRef = useRef9(null);
|
|
14375
|
+
const buildFieldDropSlots = useCallback7((form, draggedKey) => {
|
|
14376
|
+
const others = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== draggedKey);
|
|
14377
|
+
const slots = others.map((el) => {
|
|
14378
|
+
const rect = el.getBoundingClientRect();
|
|
14379
|
+
return { top: rect.top, left: rect.left, width: rect.width };
|
|
14380
|
+
});
|
|
14381
|
+
const last = others[others.length - 1];
|
|
14382
|
+
if (last) {
|
|
14383
|
+
const rect = last.getBoundingClientRect();
|
|
14384
|
+
slots.push({ top: rect.bottom, left: rect.left, width: rect.width });
|
|
14385
|
+
}
|
|
14386
|
+
return slots;
|
|
14387
|
+
}, []);
|
|
14388
|
+
const handleFieldDragStart = useCallback7(() => {
|
|
14389
|
+
const wrapper = fieldPickElRef.current;
|
|
14390
|
+
const form = formPickElRef.current;
|
|
14391
|
+
if (!wrapper || !form) return;
|
|
14392
|
+
const key = fieldKeyOf(wrapper);
|
|
14393
|
+
fieldDragRef.current = { key, form };
|
|
14394
|
+
setFieldDragging(true);
|
|
14395
|
+
setFieldDropSlots(buildFieldDropSlots(form, key));
|
|
14396
|
+
}, [buildFieldDropSlots]);
|
|
14397
|
+
const handleFieldDragEnd = useCallback7(() => {
|
|
14398
|
+
fieldDragRef.current = null;
|
|
14399
|
+
setFieldDropIndex(null);
|
|
14400
|
+
setFieldDropSlots([]);
|
|
14401
|
+
setFieldDragging(false);
|
|
14402
|
+
}, []);
|
|
14403
|
+
const [fieldDropIndex, setFieldDropIndex] = useState11(null);
|
|
14404
|
+
const [fieldDropSlots, setFieldDropSlots] = useState11([]);
|
|
14405
|
+
const [fieldDragging, setFieldDragging] = useState11(false);
|
|
14406
|
+
const clearFormPickRef = useRef9(clearFormPick);
|
|
14407
|
+
clearFormPickRef.current = clearFormPick;
|
|
14408
|
+
useEffect12(() => {
|
|
14409
|
+
const el = fieldPickElRef.current;
|
|
14410
|
+
if (!el || fieldPickRect === null) return;
|
|
14411
|
+
const observer = new ResizeObserver(() => {
|
|
14412
|
+
if (fieldPickElRef.current === el) setFieldPickRect(el.getBoundingClientRect());
|
|
14413
|
+
});
|
|
14414
|
+
observer.observe(el);
|
|
14415
|
+
return () => observer.disconnect();
|
|
14416
|
+
}, [fieldPickRect !== null, fieldPickState]);
|
|
14417
|
+
useEffect12(() => {
|
|
14418
|
+
const el = formPickElRef.current;
|
|
14419
|
+
if (!el || formPickRect === null) return;
|
|
14420
|
+
const observer = new ResizeObserver(() => {
|
|
14421
|
+
if (formPickElRef.current === el) setFormPickRect(el.getBoundingClientRect());
|
|
14422
|
+
});
|
|
14423
|
+
observer.observe(el);
|
|
14424
|
+
return () => observer.disconnect();
|
|
14425
|
+
}, [formPickRect !== null, formViewState]);
|
|
14451
14426
|
const [toolbarVariant, setToolbarVariant] = useState11("none");
|
|
14452
14427
|
const toolbarVariantRef = useRef9("none");
|
|
14453
14428
|
toolbarVariantRef.current = toolbarVariant;
|
|
@@ -14469,7 +14444,7 @@ function OhhwellsBridge() {
|
|
|
14469
14444
|
useEffect12(() => {
|
|
14470
14445
|
const sync = () => {
|
|
14471
14446
|
const el = document.querySelector(
|
|
14472
|
-
|
|
14447
|
+
'[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
|
|
14473
14448
|
);
|
|
14474
14449
|
const target = el && !el.closest("[data-ohw-href-key]") ? el : null;
|
|
14475
14450
|
if (!target) {
|
|
@@ -14493,6 +14468,11 @@ function OhhwellsBridge() {
|
|
|
14493
14468
|
const [isItemDragging, setIsItemDragging] = useState11(false);
|
|
14494
14469
|
const [isFooterFrameSelection, setIsFooterFrameSelection] = useState11(false);
|
|
14495
14470
|
isFooterFrameSelectionRef.current = isFooterFrameSelection;
|
|
14471
|
+
const [floatingPanel, setFloatingPanel] = useState11(null);
|
|
14472
|
+
const floatingPanelOpenRef = useRef9(false);
|
|
14473
|
+
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
14474
|
+
const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
|
|
14475
|
+
const [parentScrollSnap, setParentScrollSnap] = useState11(null);
|
|
14496
14476
|
const [navDropdownPreviewOpen, setNavDropdownPreviewOpen] = useState11(null);
|
|
14497
14477
|
const [footerHeadingVisible, setFooterHeadingVisible] = useState11(null);
|
|
14498
14478
|
const footerDragRef = useRef9(null);
|
|
@@ -14507,16 +14487,7 @@ function OhhwellsBridge() {
|
|
|
14507
14487
|
const addNavAfterAnchorRef = useRef9(null);
|
|
14508
14488
|
const editContentRef = useRef9({});
|
|
14509
14489
|
const aiSectionsRef = useRef9("");
|
|
14510
|
-
const brandKitRef = useRef9("");
|
|
14511
|
-
const stylesRef = useRef9("");
|
|
14512
14490
|
const pendingDeleteUndoRef = useRef9(null);
|
|
14513
|
-
const [floatingPanel, setFloatingPanel] = useState11(null);
|
|
14514
|
-
const floatingPanelOpenRef = useRef9(false);
|
|
14515
|
-
const setFloatingPanelRef = useRef9(setFloatingPanel);
|
|
14516
|
-
const [floatingPanelPos, setFloatingPanelPos] = useState11(null);
|
|
14517
|
-
const [logoSizeDraft, setLogoSizeDraft] = useState11(null);
|
|
14518
|
-
const [editorViewport, setEditorViewport] = useState11("desktop");
|
|
14519
|
-
const [parentScrollSnap, setParentScrollSnap] = useState11(null);
|
|
14520
14491
|
const [sitePages, setSitePages] = useState11([]);
|
|
14521
14492
|
const [sectionsByPath, setSectionsByPath] = useState11({});
|
|
14522
14493
|
const sectionsPrefetchGenRef = useRef9(0);
|
|
@@ -14525,18 +14496,7 @@ function OhhwellsBridge() {
|
|
|
14525
14496
|
const linkPopoverOpenRef = useRef9(false);
|
|
14526
14497
|
const linkPopoverGraceUntilRef = useRef9(0);
|
|
14527
14498
|
setLinkPopoverRef.current = setLinkPopover;
|
|
14528
|
-
setFloatingPanelRef.current = setFloatingPanel;
|
|
14529
14499
|
linkPopoverSessionRef.current = linkPopover;
|
|
14530
|
-
floatingPanelOpenRef.current = Boolean(floatingPanel);
|
|
14531
|
-
useEffect12(() => {
|
|
14532
|
-
const syncViewport = () => {
|
|
14533
|
-
const next = window.innerWidth <= 480 ? "mobile" : "desktop";
|
|
14534
|
-
setEditorViewport((prev) => prev === next ? prev : next);
|
|
14535
|
-
};
|
|
14536
|
-
syncViewport();
|
|
14537
|
-
window.addEventListener("resize", syncViewport);
|
|
14538
|
-
return () => window.removeEventListener("resize", syncViewport);
|
|
14539
|
-
}, []);
|
|
14540
14500
|
const {
|
|
14541
14501
|
navDragRef,
|
|
14542
14502
|
navDropSlots,
|
|
@@ -14705,7 +14665,9 @@ function OhhwellsBridge() {
|
|
|
14705
14665
|
const deactivate = useCallback7(() => {
|
|
14706
14666
|
const el = activeElRef.current;
|
|
14707
14667
|
if (!el) return;
|
|
14708
|
-
const
|
|
14668
|
+
const isFormBlock = el.dataset.ohwEditable === "form";
|
|
14669
|
+
const isFormControl = el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement;
|
|
14670
|
+
const key = isFormBlock || isFormControl ? void 0 : el.dataset.ohwKey;
|
|
14709
14671
|
if (key) {
|
|
14710
14672
|
const timer = autoSaveTimers.current.get(key);
|
|
14711
14673
|
if (timer !== void 0) {
|
|
@@ -14722,6 +14684,12 @@ function OhhwellsBridge() {
|
|
|
14722
14684
|
}
|
|
14723
14685
|
el.removeAttribute("contenteditable");
|
|
14724
14686
|
el.removeAttribute("data-ohw-editing");
|
|
14687
|
+
const labelField = getFieldWrapper(el);
|
|
14688
|
+
if (labelField) {
|
|
14689
|
+
syncRequiredMark(labelField);
|
|
14690
|
+
const owner = labelField.closest('[data-ohw-editable="form"]');
|
|
14691
|
+
if (owner) persistFieldsRef.current(owner);
|
|
14692
|
+
}
|
|
14725
14693
|
activeElRef.current = null;
|
|
14726
14694
|
setNavGroupForceOpen(null, false);
|
|
14727
14695
|
setReorderHrefKey(null);
|
|
@@ -14761,8 +14729,6 @@ function OhhwellsBridge() {
|
|
|
14761
14729
|
setHoveredNavContainerRect(null);
|
|
14762
14730
|
hoveredItemElRef.current = null;
|
|
14763
14731
|
setHoveredItemRect(null);
|
|
14764
|
-
setFloatingPanel(null);
|
|
14765
|
-
setLogoSizeDraft(null);
|
|
14766
14732
|
if (!activeElRef.current) {
|
|
14767
14733
|
setNavGroupForceOpen(null, false);
|
|
14768
14734
|
setToolbarRect(null);
|
|
@@ -14877,6 +14843,12 @@ function OhhwellsBridge() {
|
|
|
14877
14843
|
}
|
|
14878
14844
|
el.removeAttribute("contenteditable");
|
|
14879
14845
|
el.removeAttribute("data-ohw-editing");
|
|
14846
|
+
const labelField = getFieldWrapper(el);
|
|
14847
|
+
if (labelField) {
|
|
14848
|
+
syncRequiredMark(labelField);
|
|
14849
|
+
const owner = labelField.closest('[data-ohw-editable="form"]');
|
|
14850
|
+
if (owner) persistFieldsRef.current(owner);
|
|
14851
|
+
}
|
|
14880
14852
|
activeElRef.current = null;
|
|
14881
14853
|
setMaxBadge(null);
|
|
14882
14854
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
@@ -15468,8 +15440,6 @@ function OhhwellsBridge() {
|
|
|
15468
15440
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
15469
15441
|
setToolbarShowEditLink(false);
|
|
15470
15442
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
15471
|
-
setFloatingPanel(null);
|
|
15472
|
-
setLogoSizeDraft(null);
|
|
15473
15443
|
}, [deactivate, markSelected]);
|
|
15474
15444
|
const selectFrame = useCallback7((el) => {
|
|
15475
15445
|
if (!isNavigationContainer(el)) return;
|
|
@@ -15519,51 +15489,7 @@ function OhhwellsBridge() {
|
|
|
15519
15489
|
setToolbarRect(el.getBoundingClientRect());
|
|
15520
15490
|
setToolbarShowEditLink(false);
|
|
15521
15491
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
15522
|
-
setFloatingPanel(null);
|
|
15523
|
-
setLogoSizeDraft(null);
|
|
15524
15492
|
}, [deactivate, markSelected, postToParent2]);
|
|
15525
|
-
const selectLogo = useCallback7(
|
|
15526
|
-
(logoEl) => {
|
|
15527
|
-
if (activeElRef.current) deactivate();
|
|
15528
|
-
selectedElRef.current = logoEl;
|
|
15529
|
-
selectedHrefKeyRef.current = null;
|
|
15530
|
-
selectedFooterColAttrRef.current = null;
|
|
15531
|
-
markSelected(logoEl);
|
|
15532
|
-
setSelectedIsCta(false);
|
|
15533
|
-
setSelectedIsSocial(false);
|
|
15534
|
-
setSelectedIsSocialsRow(false);
|
|
15535
|
-
clearHrefKeyHover(logoEl);
|
|
15536
|
-
hoveredNavContainerRef.current = null;
|
|
15537
|
-
setHoveredNavContainerRect(null);
|
|
15538
|
-
setHoveredItemRect(null);
|
|
15539
|
-
hoveredItemElRef.current = null;
|
|
15540
|
-
siblingHintElRef.current = null;
|
|
15541
|
-
setSiblingHintRect(null);
|
|
15542
|
-
setSiblingHintRects([]);
|
|
15543
|
-
setIsItemDragging(false);
|
|
15544
|
-
setReorderHrefKey(null);
|
|
15545
|
-
setReorderDragDisabled(false);
|
|
15546
|
-
setIsFooterFrameSelection(false);
|
|
15547
|
-
setToolbarVariant("logo");
|
|
15548
|
-
setToolbarRect(getLogoInteractionRect(logoEl));
|
|
15549
|
-
setToolbarShowEditLink(false);
|
|
15550
|
-
setActiveCommands(/* @__PURE__ */ new Set());
|
|
15551
|
-
},
|
|
15552
|
-
[deactivate, markSelected]
|
|
15553
|
-
);
|
|
15554
|
-
const openLogoSizePanel = useCallback7((logoEl) => {
|
|
15555
|
-
const placement = getLogoPlacement(logoEl);
|
|
15556
|
-
const draft = readLogoSizeState(editContentRef.current, placement);
|
|
15557
|
-
setLogoSizeDraft(draft);
|
|
15558
|
-
setParentScrollSnap(parentScrollRef.current);
|
|
15559
|
-
setFloatingPanel({
|
|
15560
|
-
key: `logo-size:${placement}`,
|
|
15561
|
-
title: "Logo",
|
|
15562
|
-
context: placement === "navbar" ? "Navbar" : "Footer",
|
|
15563
|
-
kind: "logo-size",
|
|
15564
|
-
placement
|
|
15565
|
-
});
|
|
15566
|
-
}, []);
|
|
15567
15493
|
const openSocialsDisplayPanel = useCallback7((row) => {
|
|
15568
15494
|
setParentScrollSnap(parentScrollRef.current);
|
|
15569
15495
|
setFloatingPanel({
|
|
@@ -15599,53 +15525,13 @@ function OhhwellsBridge() {
|
|
|
15599
15525
|
);
|
|
15600
15526
|
const closeFloatingPanelOnly = useCallback7(() => {
|
|
15601
15527
|
setFloatingPanel(null);
|
|
15602
|
-
setLogoSizeDraft(null);
|
|
15603
15528
|
}, []);
|
|
15529
|
+
const closeFloatingPanelOnlyRef = useRef9(closeFloatingPanelOnly);
|
|
15530
|
+
closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
|
|
15604
15531
|
const closeFloatingPanelAndDeselect = useCallback7(() => {
|
|
15605
15532
|
setFloatingPanel(null);
|
|
15606
|
-
setLogoSizeDraft(null);
|
|
15607
15533
|
deselectRef.current();
|
|
15608
15534
|
}, []);
|
|
15609
|
-
const persistLogoSizeDraft = useCallback7(
|
|
15610
|
-
(placement, draft) => {
|
|
15611
|
-
const desktopKey = LOGO_SIZE_DESKTOP_KEYS[placement];
|
|
15612
|
-
const mobileKey = LOGO_SIZE_MOBILE_KEYS[placement];
|
|
15613
|
-
const nodes = [
|
|
15614
|
-
{ key: desktopKey, text: String(draft.desktopPx) }
|
|
15615
|
-
];
|
|
15616
|
-
if (draft.mobileFollowing) {
|
|
15617
|
-
nodes.push({ key: mobileKey, text: "" });
|
|
15618
|
-
} else {
|
|
15619
|
-
nodes.push({ key: mobileKey, text: String(draft.mobilePx) });
|
|
15620
|
-
}
|
|
15621
|
-
editContentRef.current = {
|
|
15622
|
-
...editContentRef.current,
|
|
15623
|
-
[desktopKey]: String(draft.desktopPx),
|
|
15624
|
-
[mobileKey]: draft.mobileFollowing ? "" : String(draft.mobilePx)
|
|
15625
|
-
};
|
|
15626
|
-
applyLogoSizeToPlacement(
|
|
15627
|
-
placement,
|
|
15628
|
-
draft.desktopPx,
|
|
15629
|
-
draft.mobileFollowing ? draft.desktopPx : draft.mobilePx,
|
|
15630
|
-
draft.mobileFollowing
|
|
15631
|
-
);
|
|
15632
|
-
postToParent2({ type: "ow:change", nodes });
|
|
15633
|
-
requestAnimationFrame(() => {
|
|
15634
|
-
const selected = selectedElRef.current;
|
|
15635
|
-
if (!selected || toolbarVariantRef.current !== "logo") return;
|
|
15636
|
-
const rect = getLogoInteractionRect(selected);
|
|
15637
|
-
setToolbarRect(rect);
|
|
15638
|
-
if (glowElRef.current) {
|
|
15639
|
-
const GAP = SELECTION_CHROME_GAP2;
|
|
15640
|
-
glowElRef.current.style.top = `${rect.top - GAP}px`;
|
|
15641
|
-
glowElRef.current.style.left = `${rect.left - GAP}px`;
|
|
15642
|
-
glowElRef.current.style.width = `${rect.width + GAP * 2}px`;
|
|
15643
|
-
glowElRef.current.style.height = `${rect.height + GAP * 2}px`;
|
|
15644
|
-
}
|
|
15645
|
-
});
|
|
15646
|
-
},
|
|
15647
|
-
[postToParent2]
|
|
15648
|
-
);
|
|
15649
15535
|
const activate = useCallback7((el, options) => {
|
|
15650
15536
|
if (activeElRef.current === el) return;
|
|
15651
15537
|
if (isIconEditable(el)) return;
|
|
@@ -15726,10 +15612,7 @@ function OhhwellsBridge() {
|
|
|
15726
15612
|
deactivateRef.current = deactivate;
|
|
15727
15613
|
selectRef.current = select;
|
|
15728
15614
|
selectFrameRef.current = selectFrame;
|
|
15729
|
-
selectLogoRef.current = selectLogo;
|
|
15730
|
-
openLogoSizePanelRef.current = openLogoSizePanel;
|
|
15731
15615
|
deselectRef.current = deselect;
|
|
15732
|
-
closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
|
|
15733
15616
|
const lastSiteWideScopeRef = useRef9(null);
|
|
15734
15617
|
useEffect12(() => {
|
|
15735
15618
|
if (!isEditMode) {
|
|
@@ -15768,23 +15651,9 @@ function OhhwellsBridge() {
|
|
|
15768
15651
|
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
15769
15652
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
15770
15653
|
}
|
|
15771
|
-
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
15772
|
-
brandKitRef.current = content[BRAND_KIT_KEY];
|
|
15773
|
-
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
15774
|
-
}
|
|
15775
|
-
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
15776
|
-
stylesRef.current = content[STYLE_STORE_KEY];
|
|
15777
|
-
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
15778
|
-
}
|
|
15779
|
-
applyBrandChrome(content);
|
|
15780
15654
|
for (const [key, val] of Object.entries(content)) {
|
|
15781
15655
|
if (key === "__ohw_sections") continue;
|
|
15782
15656
|
if (key === AI_SECTIONS_KEY) continue;
|
|
15783
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
15784
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
15785
|
-
if (key === BRAND_KIT_KEY) continue;
|
|
15786
|
-
if (key === STYLE_STORE_KEY) continue;
|
|
15787
|
-
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
15788
15657
|
if (applyVideoSettingNode(key, val)) continue;
|
|
15789
15658
|
if (applyCarouselNode(key, val)) continue;
|
|
15790
15659
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -15813,14 +15682,13 @@ function OhhwellsBridge() {
|
|
|
15813
15682
|
applyLinkHref(el, val);
|
|
15814
15683
|
} else if (el.dataset.ohwEditable === "icon") {
|
|
15815
15684
|
applyIconMarkup(el, val);
|
|
15685
|
+
} else if (el.dataset.ohwEditable === "form") {
|
|
15816
15686
|
} else if (el.innerHTML !== val) {
|
|
15817
15687
|
el.innerHTML = val;
|
|
15818
15688
|
}
|
|
15819
15689
|
});
|
|
15820
15690
|
applyLinkByKey(key, val);
|
|
15821
15691
|
}
|
|
15822
|
-
applyLogoFromContent(content);
|
|
15823
|
-
applyLogoSizes(content);
|
|
15824
15692
|
reconcileNavbarItemsFromContent(content);
|
|
15825
15693
|
reconcileFooterOrderFromContent(content);
|
|
15826
15694
|
reconcileSocialsFromContent(content);
|
|
@@ -15841,9 +15709,7 @@ function OhhwellsBridge() {
|
|
|
15841
15709
|
let cancelled = false;
|
|
15842
15710
|
setFetchState("loading");
|
|
15843
15711
|
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
15844
|
-
|
|
15845
|
-
fetchedContentPaths.add(`${subdomain}::${initialPath}`);
|
|
15846
|
-
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(initialPath)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
15712
|
+
fetch(`${apiUrl}/api/public/sites/${subdomain}/content`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
15847
15713
|
if (cancelled) return;
|
|
15848
15714
|
const content = data?.content ?? {};
|
|
15849
15715
|
contentCache.set(subdomain, content);
|
|
@@ -15856,6 +15722,102 @@ function OhhwellsBridge() {
|
|
|
15856
15722
|
cancelled = true;
|
|
15857
15723
|
};
|
|
15858
15724
|
}, [subdomain, isEditMode]);
|
|
15725
|
+
useEffect12(() => {
|
|
15726
|
+
if (!isEditMode) return;
|
|
15727
|
+
const resolveIndex = (form, clientY) => {
|
|
15728
|
+
const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
|
|
15729
|
+
for (let i = 0; i < wrappers.length; i += 1) {
|
|
15730
|
+
const rect = wrappers[i].getBoundingClientRect();
|
|
15731
|
+
if (clientY < rect.top + rect.height / 2) return i;
|
|
15732
|
+
}
|
|
15733
|
+
return wrappers.length;
|
|
15734
|
+
};
|
|
15735
|
+
const onDragOver = (e) => {
|
|
15736
|
+
const session = fieldDragRef.current;
|
|
15737
|
+
if (!session) return;
|
|
15738
|
+
e.preventDefault();
|
|
15739
|
+
e.stopPropagation();
|
|
15740
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
15741
|
+
setFieldDropSlots(buildFieldDropSlots(session.form, session.key));
|
|
15742
|
+
setFieldDropIndex(resolveIndex(session.form, e.clientY));
|
|
15743
|
+
};
|
|
15744
|
+
const onDrop = (e) => {
|
|
15745
|
+
const session = fieldDragRef.current;
|
|
15746
|
+
if (!session) return;
|
|
15747
|
+
e.preventDefault();
|
|
15748
|
+
e.stopPropagation();
|
|
15749
|
+
moveField(session.form, session.key, resolveIndex(session.form, e.clientY));
|
|
15750
|
+
persistFields(session.form);
|
|
15751
|
+
const moved = listFieldWrappers(session.form).find((el) => fieldKeyOf(el) === session.key);
|
|
15752
|
+
if (moved) selectField(moved);
|
|
15753
|
+
setFormPickRect(session.form.getBoundingClientRect());
|
|
15754
|
+
fieldDragRef.current = null;
|
|
15755
|
+
setFieldDropIndex(null);
|
|
15756
|
+
setFieldDropSlots([]);
|
|
15757
|
+
setFieldDragging(false);
|
|
15758
|
+
};
|
|
15759
|
+
window.addEventListener("dragover", onDragOver, true);
|
|
15760
|
+
window.addEventListener("drop", onDrop, true);
|
|
15761
|
+
return () => {
|
|
15762
|
+
window.removeEventListener("dragover", onDragOver, true);
|
|
15763
|
+
window.removeEventListener("drop", onDrop, true);
|
|
15764
|
+
};
|
|
15765
|
+
}, [buildFieldDropSlots, isEditMode, persistFields, selectField]);
|
|
15766
|
+
useEffect12(() => {
|
|
15767
|
+
if (!isEditMode) return;
|
|
15768
|
+
const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
15769
|
+
markFormFields(form);
|
|
15770
|
+
});
|
|
15771
|
+
mark();
|
|
15772
|
+
const observer = new MutationObserver(() => mark());
|
|
15773
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
15774
|
+
observer.observe(form, { childList: true, subtree: true, characterData: true });
|
|
15775
|
+
});
|
|
15776
|
+
return () => observer.disconnect();
|
|
15777
|
+
}, [isEditMode, fetchState, pathname]);
|
|
15778
|
+
useEffect12(() => {
|
|
15779
|
+
if (!isEditMode) return;
|
|
15780
|
+
let saveTimer = null;
|
|
15781
|
+
const onInput = (e) => {
|
|
15782
|
+
const input = e.target;
|
|
15783
|
+
if (!input || !("value" in input)) return;
|
|
15784
|
+
const wrapper = getFieldWrapper(input);
|
|
15785
|
+
if (!wrapper || wrapper !== fieldPickElRef.current) return;
|
|
15786
|
+
if (saveTimer) clearTimeout(saveTimer);
|
|
15787
|
+
const owner = wrapper.closest('[data-ohw-editable="form"]');
|
|
15788
|
+
saveTimer = setTimeout(() => {
|
|
15789
|
+
const form = owner ?? formPickElRef.current;
|
|
15790
|
+
if (!form) return;
|
|
15791
|
+
const previous = input.getAttribute("placeholder");
|
|
15792
|
+
input.setAttribute("placeholder", input.value);
|
|
15793
|
+
persistFields(form);
|
|
15794
|
+
input.setAttribute("placeholder", previous ?? "");
|
|
15795
|
+
}, 400);
|
|
15796
|
+
};
|
|
15797
|
+
document.addEventListener("input", onInput, true);
|
|
15798
|
+
return () => document.removeEventListener("input", onInput, true);
|
|
15799
|
+
}, [isEditMode, persistFields]);
|
|
15800
|
+
useEffect12(() => {
|
|
15801
|
+
if (isEditMode || fetchState !== "done") return;
|
|
15802
|
+
const content = contentCache.get(subdomain) ?? {};
|
|
15803
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
15804
|
+
reconcileFieldsFromContent(form, content);
|
|
15805
|
+
});
|
|
15806
|
+
}, [isEditMode, fetchState, subdomain]);
|
|
15807
|
+
useEffect12(() => {
|
|
15808
|
+
if (!isEditMode) return;
|
|
15809
|
+
const swallow = (e) => {
|
|
15810
|
+
const target = e.target;
|
|
15811
|
+
if (target && getFormElement(target)) e.preventDefault();
|
|
15812
|
+
};
|
|
15813
|
+
document.addEventListener("submit", swallow, true);
|
|
15814
|
+
return () => document.removeEventListener("submit", swallow, true);
|
|
15815
|
+
}, [isEditMode]);
|
|
15816
|
+
useEffect12(() => {
|
|
15817
|
+
if (isEditMode || fetchState !== "done") return;
|
|
15818
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
15819
|
+
bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
|
|
15820
|
+
}, [isEditMode, fetchState, subdomain]);
|
|
15859
15821
|
useEffect12(() => {
|
|
15860
15822
|
if (!subdomain || isEditMode) return;
|
|
15861
15823
|
let debounceTimer = null;
|
|
@@ -15867,21 +15829,8 @@ function OhhwellsBridge() {
|
|
|
15867
15829
|
initSectionInstancesFromContent(content, window.location.pathname);
|
|
15868
15830
|
observer?.disconnect();
|
|
15869
15831
|
try {
|
|
15870
|
-
applyBrandChrome(content);
|
|
15871
|
-
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
15872
|
-
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
15873
|
-
}
|
|
15874
|
-
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
15875
|
-
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
15876
|
-
}
|
|
15877
15832
|
for (const [key, val] of Object.entries(content)) {
|
|
15878
15833
|
if (key === "__ohw_sections") continue;
|
|
15879
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
15880
|
-
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
15881
|
-
if (key === BRAND_KIT_KEY) continue;
|
|
15882
|
-
if (key === STYLE_STORE_KEY) continue;
|
|
15883
|
-
if (key === STYLE_STORE_KEY) continue;
|
|
15884
|
-
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
15885
15834
|
if (applyVideoSettingNode(key, val)) continue;
|
|
15886
15835
|
if (applyCarouselNode(key, val)) continue;
|
|
15887
15836
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -15896,17 +15845,23 @@ function OhhwellsBridge() {
|
|
|
15896
15845
|
if (video && video.src !== val) applyVideoSrc(video, val);
|
|
15897
15846
|
} else if (el.dataset.ohwEditable === "link") {
|
|
15898
15847
|
applyLinkHref(el, val);
|
|
15848
|
+
} else if (el.dataset.ohwEditable === "form") {
|
|
15899
15849
|
} else if (el.innerHTML !== val) {
|
|
15900
15850
|
el.innerHTML = val;
|
|
15901
15851
|
}
|
|
15902
15852
|
});
|
|
15903
15853
|
applyLinkByKey(key, val);
|
|
15904
15854
|
}
|
|
15905
|
-
applyLogoFromContent(content);
|
|
15906
15855
|
reconcileNavbarItemsFromContent(content);
|
|
15907
15856
|
reconcileFooterOrderFromContent(content);
|
|
15908
15857
|
reconcileSocialsFromContent(content);
|
|
15909
15858
|
applySocialsDisplayFromContent(content);
|
|
15859
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
15860
|
+
if (!form.querySelector("[data-ohw-form-success]")) {
|
|
15861
|
+
reconcileFieldsFromContent(form, content);
|
|
15862
|
+
}
|
|
15863
|
+
listFieldWrappers(form).forEach(syncRequiredMark);
|
|
15864
|
+
});
|
|
15910
15865
|
} finally {
|
|
15911
15866
|
observer?.observe(document.body, { childList: true, subtree: true });
|
|
15912
15867
|
}
|
|
@@ -15917,17 +15872,6 @@ function OhhwellsBridge() {
|
|
|
15917
15872
|
debounceTimer = setTimeout(applyFromCache, 150);
|
|
15918
15873
|
};
|
|
15919
15874
|
applyFromCache();
|
|
15920
|
-
const pathCacheKey = `${subdomain}::${pathname}`;
|
|
15921
|
-
if (!fetchedContentPaths.has(pathCacheKey)) {
|
|
15922
|
-
fetchedContentPaths.add(pathCacheKey);
|
|
15923
|
-
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
15924
|
-
fetch(`${apiUrl}/api/public/sites/${subdomain}/content?path=${encodeURIComponent(pathname)}`, { cache: "no-store" }).then((r2) => r2.ok ? r2.json() : null).then((data) => {
|
|
15925
|
-
if (!data?.content) return;
|
|
15926
|
-
contentCache.set(subdomain, data.content);
|
|
15927
|
-
applyFromCache();
|
|
15928
|
-
}).catch(() => {
|
|
15929
|
-
});
|
|
15930
|
-
}
|
|
15931
15875
|
observer = new MutationObserver(scheduleApply);
|
|
15932
15876
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
15933
15877
|
return () => {
|
|
@@ -16021,31 +15965,26 @@ function OhhwellsBridge() {
|
|
|
16021
15965
|
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
16022
15966
|
useEffect12(() => {
|
|
16023
15967
|
if (!isEditMode) return;
|
|
16024
|
-
let lastPosted = 0;
|
|
16025
15968
|
const measure = () => {
|
|
16026
15969
|
const h = document.body.scrollHeight;
|
|
16027
|
-
if (h > 50
|
|
16028
|
-
lastPosted = h;
|
|
16029
|
-
postToParent2({ type: "ow:height", height: h });
|
|
16030
|
-
}
|
|
16031
|
-
};
|
|
16032
|
-
let raf = null;
|
|
16033
|
-
const schedule = () => {
|
|
16034
|
-
if (raf != null) return;
|
|
16035
|
-
raf = requestAnimationFrame(() => {
|
|
16036
|
-
raf = null;
|
|
16037
|
-
measure();
|
|
16038
|
-
});
|
|
15970
|
+
if (h > 50) postToParent2({ type: "ow:height", height: h });
|
|
16039
15971
|
};
|
|
16040
15972
|
const t1 = setTimeout(measure, 50);
|
|
16041
15973
|
const t2 = setTimeout(measure, 500);
|
|
16042
|
-
|
|
16043
|
-
|
|
15974
|
+
let lastWidth = window.innerWidth;
|
|
15975
|
+
let resizeTimer = null;
|
|
15976
|
+
const handleResize = () => {
|
|
15977
|
+
if (window.innerWidth === lastWidth) return;
|
|
15978
|
+
lastWidth = window.innerWidth;
|
|
15979
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
15980
|
+
resizeTimer = setTimeout(measure, 150);
|
|
15981
|
+
};
|
|
15982
|
+
window.addEventListener("resize", handleResize);
|
|
16044
15983
|
return () => {
|
|
16045
15984
|
clearTimeout(t1);
|
|
16046
15985
|
clearTimeout(t2);
|
|
16047
|
-
if (
|
|
16048
|
-
|
|
15986
|
+
if (resizeTimer) clearTimeout(resizeTimer);
|
|
15987
|
+
window.removeEventListener("resize", handleResize);
|
|
16049
15988
|
};
|
|
16050
15989
|
}, [pathname, isEditMode, postToParent2]);
|
|
16051
15990
|
useEffect12(() => {
|
|
@@ -16089,7 +16028,9 @@ function OhhwellsBridge() {
|
|
|
16089
16028
|
[style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
16090
16029
|
[style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
16091
16030
|
[style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
16092
|
-
|
|
16031
|
+
/* Not the form: it is a layout container (flex/grid with gaps), and forcing block
|
|
16032
|
+
crushed its fields together (OHH-490). */
|
|
16033
|
+
[data-ohw-editable]:not([data-ohw-editable="form"]) {
|
|
16093
16034
|
display: block;
|
|
16094
16035
|
}
|
|
16095
16036
|
/* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
|
|
@@ -16115,6 +16056,35 @@ function OhhwellsBridge() {
|
|
|
16115
16056
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
16116
16057
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
16117
16058
|
[data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
|
|
16059
|
+
/* A form field is a design surface in the editor: its input takes the pointer so the
|
|
16060
|
+
field can be picked and hovered from anywhere inside it (OHH-642). */
|
|
16061
|
+
[data-ohw-editable="form"] [data-ohw-form-field] input,
|
|
16062
|
+
[data-ohw-editable="form"] [data-ohw-form-field] textarea,
|
|
16063
|
+
[data-ohw-editable="form"] [data-ohw-form-field] label {
|
|
16064
|
+
pointer-events: auto !important;
|
|
16065
|
+
cursor: pointer !important;
|
|
16066
|
+
}
|
|
16067
|
+
/* While a field is selected its placeholder is being written in the value, so the
|
|
16068
|
+
text reads as a placeholder rather than as an answer (OHH-642). */
|
|
16069
|
+
/* A field is a design surface here: dragging its corner resized it past the form and
|
|
16070
|
+
left the chrome behind. Height stays adjustable, width does not (OHH-642). */
|
|
16071
|
+
[data-ohw-editable="form"] [data-ohw-form-field] textarea {
|
|
16072
|
+
resize: vertical !important;
|
|
16073
|
+
max-width: 100% !important;
|
|
16074
|
+
}
|
|
16075
|
+
[data-ohw-editable="form"] [data-ohw-form-field] input,
|
|
16076
|
+
[data-ohw-editable="form"] [data-ohw-form-field] textarea {
|
|
16077
|
+
box-sizing: border-box !important;
|
|
16078
|
+
width: 100% !important;
|
|
16079
|
+
}
|
|
16080
|
+
/* Somewhere to click the block itself, on every side (OHH-642) \u2014 editor only. */
|
|
16081
|
+
[data-ohw-editable="form"] {
|
|
16082
|
+
padding: 18px !important;
|
|
16083
|
+
}
|
|
16084
|
+
[data-ohw-placeholder-edit] {
|
|
16085
|
+
color: color-mix(in srgb, currentColor 55%, transparent) !important;
|
|
16086
|
+
cursor: text !important;
|
|
16087
|
+
}
|
|
16118
16088
|
/* Text hover chrome is drawn by the overlay (see hoveredTextRect) \u2014 the CSS outline
|
|
16119
16089
|
that used to draw it dashes denser than the overlay border, so identical specs
|
|
16120
16090
|
still read as two different frames (OHH-695). The attribute stays: hover paths
|
|
@@ -16195,12 +16165,53 @@ function OhhwellsBridge() {
|
|
|
16195
16165
|
return;
|
|
16196
16166
|
}
|
|
16197
16167
|
const target = e.target;
|
|
16198
|
-
if (target.closest("[data-ohw-ai-review]")) return;
|
|
16199
16168
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
16200
16169
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
16201
16170
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
16202
16171
|
if (isInsideLinkEditor(target)) return;
|
|
16203
|
-
if (
|
|
16172
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
16173
|
+
if (target.closest(
|
|
16174
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
16175
|
+
)) {
|
|
16176
|
+
return;
|
|
16177
|
+
}
|
|
16178
|
+
{
|
|
16179
|
+
const formEl = getFormElement(target);
|
|
16180
|
+
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
16181
|
+
if (formEl && formKeyOf(formEl) && !onSuccessText) {
|
|
16182
|
+
const fieldEl = getFieldWrapper(target);
|
|
16183
|
+
if (fieldEl) {
|
|
16184
|
+
const label = target.closest("label");
|
|
16185
|
+
if (label && fieldPickElRef.current === fieldEl) return;
|
|
16186
|
+
e.preventDefault();
|
|
16187
|
+
e.stopPropagation();
|
|
16188
|
+
deactivateRef.current();
|
|
16189
|
+
deselectRef.current();
|
|
16190
|
+
formPickElRef.current = formEl;
|
|
16191
|
+
setFormPickRect(null);
|
|
16192
|
+
selectField(fieldEl);
|
|
16193
|
+
if (!label) fieldEl.querySelector("input, textarea")?.focus();
|
|
16194
|
+
return;
|
|
16195
|
+
}
|
|
16196
|
+
clearFieldPick();
|
|
16197
|
+
e.preventDefault();
|
|
16198
|
+
e.stopPropagation();
|
|
16199
|
+
deactivateRef.current();
|
|
16200
|
+
deselectRef.current();
|
|
16201
|
+
markFormFields(formEl);
|
|
16202
|
+
formHoverElRef.current = null;
|
|
16203
|
+
setFormHoverRect(null);
|
|
16204
|
+
formPickElRef.current = formEl;
|
|
16205
|
+
setFormPickRect(formEl.getBoundingClientRect());
|
|
16206
|
+
postToParentRef.current({
|
|
16207
|
+
type: "ow:form-selected",
|
|
16208
|
+
formKey: formKeyOf(formEl),
|
|
16209
|
+
hasLongText: formHasLongText(formEl)
|
|
16210
|
+
});
|
|
16211
|
+
return;
|
|
16212
|
+
}
|
|
16213
|
+
if (!formEl && formPickElRef.current) clearFormPick();
|
|
16214
|
+
}
|
|
16204
16215
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
16205
16216
|
const beneath = document.elementsFromPoint(e.clientX, e.clientY).find(
|
|
16206
16217
|
(el) => el instanceof HTMLElement && !el.closest("[data-ohw-bridge-root]") && el.closest("[data-ohw-section]") != null
|
|
@@ -16268,15 +16279,9 @@ function OhhwellsBridge() {
|
|
|
16268
16279
|
if (logoEl) {
|
|
16269
16280
|
e.preventDefault();
|
|
16270
16281
|
e.stopPropagation();
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
const identity = readLogoIdentityFromDom();
|
|
16275
|
-
postToParentRef.current({ type: "ow:open-logo-settings", ...identity });
|
|
16276
|
-
return;
|
|
16277
|
-
}
|
|
16278
|
-
selectLogoRef.current(logoEl);
|
|
16279
|
-
openLogoSizePanelRef.current(logoEl);
|
|
16282
|
+
deselectRef.current();
|
|
16283
|
+
deactivateRef.current();
|
|
16284
|
+
postToParentRef.current({ type: "ow:open-logo-settings" });
|
|
16280
16285
|
return;
|
|
16281
16286
|
}
|
|
16282
16287
|
const editable = target.closest("[data-ohw-editable]");
|
|
@@ -16431,12 +16436,10 @@ function OhhwellsBridge() {
|
|
|
16431
16436
|
};
|
|
16432
16437
|
const handleDblClick = (e) => {
|
|
16433
16438
|
const target = e.target;
|
|
16434
|
-
if (target.closest("[data-ohw-ai-review]")) return;
|
|
16435
16439
|
if (target.closest("[data-ohw-toolbar]")) return;
|
|
16436
16440
|
if (target.closest("[data-ohw-state-toggle]")) return;
|
|
16437
16441
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
16438
16442
|
if (isInsideLinkEditor(target)) return;
|
|
16439
|
-
if (isInsideFloatingPanel(target)) return;
|
|
16440
16443
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
16441
16444
|
return;
|
|
16442
16445
|
}
|
|
@@ -16464,16 +16467,26 @@ function OhhwellsBridge() {
|
|
|
16464
16467
|
setHoveredNavContainerRect(null);
|
|
16465
16468
|
return;
|
|
16466
16469
|
}
|
|
16467
|
-
if (
|
|
16470
|
+
if (target.closest(EDITOR_CHROME_SELECTOR) || isOverEditorChrome(e.clientX, e.clientY) || isInsideLinkEditor(target)) {
|
|
16471
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
16468
16472
|
hoveredItemElRef.current = null;
|
|
16469
16473
|
setHoveredItemRect(null);
|
|
16470
16474
|
hoveredNavContainerRef.current = null;
|
|
16471
16475
|
setHoveredNavContainerRect(null);
|
|
16476
|
+
formHoverElRef.current = null;
|
|
16477
|
+
setFormHoverRect(null);
|
|
16472
16478
|
siblingHintElRef.current = null;
|
|
16473
16479
|
setSiblingHintRect(null);
|
|
16474
16480
|
setSiblingHintRects([]);
|
|
16475
16481
|
return;
|
|
16476
16482
|
}
|
|
16483
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || target.closest("[data-ohw-floating-panel]")) {
|
|
16484
|
+
hoveredItemElRef.current = null;
|
|
16485
|
+
setHoveredItemRect(null);
|
|
16486
|
+
hoveredNavContainerRef.current = null;
|
|
16487
|
+
setHoveredNavContainerRect(null);
|
|
16488
|
+
return;
|
|
16489
|
+
}
|
|
16477
16490
|
{
|
|
16478
16491
|
const selected2 = selectedElRef.current;
|
|
16479
16492
|
const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup2(selected2)));
|
|
@@ -16516,7 +16529,7 @@ function OhhwellsBridge() {
|
|
|
16516
16529
|
setHoveredNavContainerRect(null);
|
|
16517
16530
|
if (selectedElRef.current === logoEl) return;
|
|
16518
16531
|
hoveredItemElRef.current = logoEl;
|
|
16519
|
-
setHoveredItemRect(
|
|
16532
|
+
setHoveredItemRect(logoEl.getBoundingClientRect());
|
|
16520
16533
|
return;
|
|
16521
16534
|
}
|
|
16522
16535
|
const navAnchor = getNavigationItemAnchor(target);
|
|
@@ -16540,6 +16553,26 @@ function OhhwellsBridge() {
|
|
|
16540
16553
|
return;
|
|
16541
16554
|
}
|
|
16542
16555
|
const editable = target.closest("[data-ohw-editable]");
|
|
16556
|
+
const hoverForm = getFormElement(target);
|
|
16557
|
+
if (hoverForm) {
|
|
16558
|
+
const hoverField = getFieldWrapper(target);
|
|
16559
|
+
const hoverTarget = hoverField ?? hoverForm;
|
|
16560
|
+
const selectedHere = hoverTarget === fieldPickElRef.current || hoverTarget === formPickElRef.current;
|
|
16561
|
+
hoveredItemElRef.current = null;
|
|
16562
|
+
setHoveredItemRect(null);
|
|
16563
|
+
if (selectedHere) {
|
|
16564
|
+
formHoverElRef.current = null;
|
|
16565
|
+
setFormHoverRect(null);
|
|
16566
|
+
} else {
|
|
16567
|
+
formHoverElRef.current = hoverTarget;
|
|
16568
|
+
setFormHoverRect(hoverTarget.getBoundingClientRect());
|
|
16569
|
+
}
|
|
16570
|
+
return;
|
|
16571
|
+
}
|
|
16572
|
+
if (formHoverElRef.current) {
|
|
16573
|
+
formHoverElRef.current = null;
|
|
16574
|
+
setFormHoverRect(null);
|
|
16575
|
+
}
|
|
16543
16576
|
if (!editable) return;
|
|
16544
16577
|
const selected = selectedElRef.current;
|
|
16545
16578
|
if (selected && (selected === editable || selected.contains(editable))) return;
|
|
@@ -16560,6 +16593,7 @@ function OhhwellsBridge() {
|
|
|
16560
16593
|
hoveredNavContainerRef.current = null;
|
|
16561
16594
|
setHoveredNavContainerRect(null);
|
|
16562
16595
|
hoveredItemElRef.current = editable;
|
|
16596
|
+
setHoveredItemRect(editable.getBoundingClientRect());
|
|
16563
16597
|
}
|
|
16564
16598
|
}
|
|
16565
16599
|
}
|
|
@@ -16767,7 +16801,7 @@ function OhhwellsBridge() {
|
|
|
16767
16801
|
setHoveredNavContainerRect(null);
|
|
16768
16802
|
if (selectedElRef.current !== logo) {
|
|
16769
16803
|
hoveredItemElRef.current = logo;
|
|
16770
|
-
setHoveredItemRect(
|
|
16804
|
+
setHoveredItemRect(logo.getBoundingClientRect());
|
|
16771
16805
|
}
|
|
16772
16806
|
return;
|
|
16773
16807
|
}
|
|
@@ -16856,7 +16890,7 @@ function OhhwellsBridge() {
|
|
|
16856
16890
|
}
|
|
16857
16891
|
};
|
|
16858
16892
|
const probeImageAt = (clientX, clientY, isDragOver = false, fromParentViewport = false) => {
|
|
16859
|
-
if (linkPopoverOpenRef.current
|
|
16893
|
+
if (linkPopoverOpenRef.current) {
|
|
16860
16894
|
if (hoveredImageRef.current) {
|
|
16861
16895
|
hoveredImageRef.current = null;
|
|
16862
16896
|
hoveredImageHasTextOverlapRef.current = false;
|
|
@@ -17110,7 +17144,7 @@ function OhhwellsBridge() {
|
|
|
17110
17144
|
}
|
|
17111
17145
|
};
|
|
17112
17146
|
const probeHoverCardsAt = (clientX, clientY, fromParentViewport = false) => {
|
|
17113
|
-
if (linkPopoverOpenRef.current ||
|
|
17147
|
+
if (linkPopoverOpenRef.current || document.documentElement.hasAttribute("data-ohw-section-picking")) {
|
|
17114
17148
|
if (activeStateElRef.current) {
|
|
17115
17149
|
activeStateElRef.current.removeAttribute("data-ohw-state-hovered");
|
|
17116
17150
|
activeStateElRef.current = null;
|
|
@@ -17176,19 +17210,24 @@ function OhhwellsBridge() {
|
|
|
17176
17210
|
setSectionGap(null);
|
|
17177
17211
|
}
|
|
17178
17212
|
};
|
|
17213
|
+
const pointOwnedByFloatingPanel = (clientX, clientY) => {
|
|
17214
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return true;
|
|
17215
|
+
const panel = document.querySelector("[data-ohw-floating-panel]");
|
|
17216
|
+
if (!panel) return false;
|
|
17217
|
+
const rect = panel.getBoundingClientRect();
|
|
17218
|
+
return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
|
17219
|
+
};
|
|
17179
17220
|
const handleMouseMove = (e) => {
|
|
17180
17221
|
const { clientX, clientY } = e;
|
|
17181
|
-
if (
|
|
17222
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) return;
|
|
17223
|
+
if (isOverEditorChrome(clientX, clientY)) {
|
|
17224
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
17225
|
+
formHoverElRef.current = null;
|
|
17226
|
+
setFormHoverRect(null);
|
|
17182
17227
|
hoveredItemElRef.current = null;
|
|
17183
17228
|
setHoveredItemRect(null);
|
|
17184
17229
|
hoveredNavContainerRef.current = null;
|
|
17185
17230
|
setHoveredNavContainerRect(null);
|
|
17186
|
-
siblingHintElRef.current = null;
|
|
17187
|
-
setSiblingHintRect(null);
|
|
17188
|
-
setSiblingHintRects([]);
|
|
17189
|
-
dismissImageHover();
|
|
17190
|
-
clearImageHover();
|
|
17191
|
-
setSectionGap(null);
|
|
17192
17231
|
return;
|
|
17193
17232
|
}
|
|
17194
17233
|
probeSectionGapAt(clientX, clientY);
|
|
@@ -17199,11 +17238,7 @@ function OhhwellsBridge() {
|
|
|
17199
17238
|
if (e.data?.type !== "ow:pointer-sync") return;
|
|
17200
17239
|
const { clientX, clientY } = e.data;
|
|
17201
17240
|
if (typeof clientX !== "number" || typeof clientY !== "number") return;
|
|
17202
|
-
if (
|
|
17203
|
-
dismissImageHover();
|
|
17204
|
-
clearImageHover();
|
|
17205
|
-
return;
|
|
17206
|
-
}
|
|
17241
|
+
if (pointOwnedByFloatingPanel(clientX, clientY)) return;
|
|
17207
17242
|
probeSectionGapAt(clientX, clientY);
|
|
17208
17243
|
probeImageAt(clientX, clientY);
|
|
17209
17244
|
probeHoverCardsAt(clientX, clientY);
|
|
@@ -17453,15 +17488,6 @@ function OhhwellsBridge() {
|
|
|
17453
17488
|
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
17454
17489
|
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
17455
17490
|
}
|
|
17456
|
-
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
17457
|
-
brandKitRef.current = content[BRAND_KIT_KEY];
|
|
17458
|
-
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
17459
|
-
}
|
|
17460
|
-
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17461
|
-
stylesRef.current = content[STYLE_STORE_KEY];
|
|
17462
|
-
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
17463
|
-
}
|
|
17464
|
-
applyBrandChrome(content);
|
|
17465
17491
|
let sectionsJson = null;
|
|
17466
17492
|
for (const [key, val] of Object.entries(content)) {
|
|
17467
17493
|
if (key === "__ohw_sections") {
|
|
@@ -17469,11 +17495,6 @@ function OhhwellsBridge() {
|
|
|
17469
17495
|
continue;
|
|
17470
17496
|
}
|
|
17471
17497
|
if (key === AI_SECTIONS_KEY) continue;
|
|
17472
|
-
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
17473
|
-
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
17474
|
-
if (key === BRAND_KIT_KEY) continue;
|
|
17475
|
-
if (key === STYLE_STORE_KEY) continue;
|
|
17476
|
-
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
17477
17498
|
if (applyVideoSettingNode(key, val)) continue;
|
|
17478
17499
|
if (applyCarouselNode(key, val)) continue;
|
|
17479
17500
|
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
@@ -17493,8 +17514,6 @@ function OhhwellsBridge() {
|
|
|
17493
17514
|
});
|
|
17494
17515
|
applyLinkByKey(key, val);
|
|
17495
17516
|
}
|
|
17496
|
-
applyLogoFromContent(content);
|
|
17497
|
-
applyLogoSizes(content);
|
|
17498
17517
|
if (sectionsJson) {
|
|
17499
17518
|
initSectionsFromContent({ __ohw_sections: sectionsJson }, true);
|
|
17500
17519
|
sectionsLoadedRef.current = true;
|
|
@@ -17510,58 +17529,6 @@ function OhhwellsBridge() {
|
|
|
17510
17529
|
if (hydratedHeight > 50) postToParentRef.current({ type: "ow:height", height: hydratedHeight });
|
|
17511
17530
|
postToParentRef.current({ type: "ow:hydrate-done" });
|
|
17512
17531
|
};
|
|
17513
|
-
const handleUpdateLogoIdentity = (e) => {
|
|
17514
|
-
if (e.data?.type !== "ow:update-logo-identity") return;
|
|
17515
|
-
const rawText = typeof e.data.text === "string" ? e.data.text : "";
|
|
17516
|
-
const alt = typeof e.data.alt === "string" ? e.data.alt : rawText;
|
|
17517
|
-
const href = typeof e.data.href === "string" ? e.data.href : void 0;
|
|
17518
|
-
const imageProvided = "image" in e.data;
|
|
17519
|
-
const imageUrl = imageProvided && typeof e.data.image === "string" && e.data.image.trim() ? e.data.image.trim() : imageProvided ? null : void 0;
|
|
17520
|
-
let isPlaceholder = e.data.isPlaceholder !== false;
|
|
17521
|
-
if (imageUrl) isPlaceholder = false;
|
|
17522
|
-
else if (imageProvided && imageUrl === null) {
|
|
17523
|
-
isPlaceholder = e.data.isPlaceholder === true || !rawText.trim() || resolveLogoDisplayText(rawText) === PLACEHOLDER_BUSINESS_NAME;
|
|
17524
|
-
}
|
|
17525
|
-
const display = applyLogoIdentity(rawText, isPlaceholder);
|
|
17526
|
-
const displayAlt = resolveLogoDisplayText(alt || display);
|
|
17527
|
-
if (imageUrl !== void 0) {
|
|
17528
|
-
applyLogoImage(imageUrl, displayAlt);
|
|
17529
|
-
} else {
|
|
17530
|
-
for (const key of LOGO_IMAGE_KEYS) {
|
|
17531
|
-
document.querySelectorAll(`[data-ohw-key="${key}"]`).forEach((el) => {
|
|
17532
|
-
const img = el instanceof HTMLImageElement ? el : el.querySelector("img");
|
|
17533
|
-
if (img) img.alt = displayAlt;
|
|
17534
|
-
});
|
|
17535
|
-
}
|
|
17536
|
-
}
|
|
17537
|
-
if (href !== void 0) {
|
|
17538
|
-
applyLogoHref(href);
|
|
17539
|
-
applyLinkByKey("nav-logo-href", href);
|
|
17540
|
-
applyLinkByKey("footer-logo-href", href);
|
|
17541
|
-
applyLinkByKey("logo-href", href);
|
|
17542
|
-
}
|
|
17543
|
-
const nodes = [
|
|
17544
|
-
...LOGO_TEXT_KEYS.map((key) => ({ key, text: display })),
|
|
17545
|
-
{ key: LOGO_PLACEHOLDER_KEY, text: isPlaceholder ? "true" : "false" },
|
|
17546
|
-
{ key: LOGO_ALT_KEY, text: displayAlt }
|
|
17547
|
-
];
|
|
17548
|
-
if (imageUrl !== void 0) {
|
|
17549
|
-
if (imageUrl) {
|
|
17550
|
-
for (const key of LOGO_IMAGE_KEYS) nodes.push({ key, text: imageUrl });
|
|
17551
|
-
} else {
|
|
17552
|
-
for (const key of LOGO_IMAGE_KEYS) nodes.push({ key, text: "" });
|
|
17553
|
-
}
|
|
17554
|
-
}
|
|
17555
|
-
if (href !== void 0) {
|
|
17556
|
-
for (const key of LOGO_HREF_KEYS) nodes.push({ key, text: href.trim() || "/" });
|
|
17557
|
-
}
|
|
17558
|
-
editContentRef.current = {
|
|
17559
|
-
...editContentRef.current,
|
|
17560
|
-
...Object.fromEntries(nodes.map(({ key, text }) => [key, text]))
|
|
17561
|
-
};
|
|
17562
|
-
applyLogoSizes(editContentRef.current);
|
|
17563
|
-
postToParentRef.current({ type: "ow:change", nodes });
|
|
17564
|
-
};
|
|
17565
17532
|
window.addEventListener("message", handleHydrate);
|
|
17566
17533
|
const postAiSectionsChanged = () => {
|
|
17567
17534
|
postToParentRef.current({
|
|
@@ -17575,10 +17542,7 @@ function OhhwellsBridge() {
|
|
|
17575
17542
|
const payload = e.data.payload;
|
|
17576
17543
|
if (!payload || typeof payload.id !== "string" || !isRenderableTree(payload.tree)) return;
|
|
17577
17544
|
const previous = aiSectionsRef.current;
|
|
17578
|
-
const nextState = applyTreeToState(parseAiSectionsState(previous),
|
|
17579
|
-
...payload,
|
|
17580
|
-
path: payload.path ?? window.location.pathname
|
|
17581
|
-
});
|
|
17545
|
+
const nextState = applyTreeToState(parseAiSectionsState(previous), payload);
|
|
17582
17546
|
const nextValue = serializeAiSectionsState(nextState);
|
|
17583
17547
|
aiSectionsRef.current = nextValue;
|
|
17584
17548
|
applyAiSectionsToDom(nextState);
|
|
@@ -17615,42 +17579,12 @@ function OhhwellsBridge() {
|
|
|
17615
17579
|
const value = typeof e.data.value === "string" ? e.data.value : "";
|
|
17616
17580
|
aiSectionsRef.current = value;
|
|
17617
17581
|
applyAiSectionsToDom(parseAiSectionsState(value));
|
|
17618
|
-
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
17619
17582
|
const restoredHeight = document.documentElement.scrollHeight;
|
|
17620
17583
|
if (restoredHeight > 50) postToParentRef.current({ type: "ow:height", height: restoredHeight });
|
|
17621
17584
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: AI_SECTIONS_KEY, text: value }] });
|
|
17622
17585
|
postAiSectionsChanged();
|
|
17623
17586
|
};
|
|
17624
17587
|
window.addEventListener("message", handleAiSetSections);
|
|
17625
|
-
const handleAiSetBrand = (e) => {
|
|
17626
|
-
if (e.data?.type !== "ow:ai-set-brand") return;
|
|
17627
|
-
const value = typeof e.data.value === "string" ? e.data.value : "";
|
|
17628
|
-
const previous = brandKitRef.current;
|
|
17629
|
-
brandKitRef.current = value;
|
|
17630
|
-
applyBrandToDom(parseBrandKit(value));
|
|
17631
|
-
if (aiSectionsRef.current) applyAiSectionsToDom(parseAiSectionsState(aiSectionsRef.current));
|
|
17632
|
-
applyStylesToDom(parseStyleStore(stylesRef.current));
|
|
17633
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: BRAND_KIT_KEY, text: value }] });
|
|
17634
|
-
postToParentRef.current({ type: "ow:ai-brand-applied", previous, value });
|
|
17635
|
-
};
|
|
17636
|
-
window.addEventListener("message", handleAiSetBrand);
|
|
17637
|
-
const handleAiSetStyles = (e) => {
|
|
17638
|
-
if (e.data?.type !== "ow:ai-set-styles") return;
|
|
17639
|
-
const value = typeof e.data.value === "string" ? e.data.value : "";
|
|
17640
|
-
const previous = stylesRef.current;
|
|
17641
|
-
stylesRef.current = value;
|
|
17642
|
-
applyStylesToDom(parseStyleStore(value));
|
|
17643
|
-
postToParentRef.current({ type: "ow:change", nodes: [{ key: STYLE_STORE_KEY, text: value }] });
|
|
17644
|
-
postToParentRef.current({ type: "ow:ai-styles-applied", previous, value });
|
|
17645
|
-
};
|
|
17646
|
-
window.addEventListener("message", handleAiSetStyles);
|
|
17647
|
-
const handleGetBrand = (e) => {
|
|
17648
|
-
if (e.data?.type !== "ow:get-brand") return;
|
|
17649
|
-
const template = deriveTemplateBrand();
|
|
17650
|
-
const value = brandKitRef.current || (template ? JSON.stringify(template) : "");
|
|
17651
|
-
postToParentRef.current({ type: "ow:brand-value", value });
|
|
17652
|
-
};
|
|
17653
|
-
window.addEventListener("message", handleGetBrand);
|
|
17654
17588
|
const handleDeactivate = (e) => {
|
|
17655
17589
|
if (e.data?.type !== "ow:deactivate") return;
|
|
17656
17590
|
if (Date.now() < linkPopoverGraceUntilRef.current) return;
|
|
@@ -17659,12 +17593,6 @@ function OhhwellsBridge() {
|
|
|
17659
17593
|
closeLinkPopoverRef.current();
|
|
17660
17594
|
return;
|
|
17661
17595
|
}
|
|
17662
|
-
if (floatingPanelOpenRef.current) {
|
|
17663
|
-
setFloatingPanelRef.current(null);
|
|
17664
|
-
deselectRef.current();
|
|
17665
|
-
deactivateRef.current();
|
|
17666
|
-
return;
|
|
17667
|
-
}
|
|
17668
17596
|
deselectRef.current();
|
|
17669
17597
|
deactivateRef.current();
|
|
17670
17598
|
};
|
|
@@ -17718,10 +17646,6 @@ function OhhwellsBridge() {
|
|
|
17718
17646
|
return;
|
|
17719
17647
|
}
|
|
17720
17648
|
if (selectedElRef.current) {
|
|
17721
|
-
if (toolbarVariantRef.current === "logo") {
|
|
17722
|
-
deselectRef.current();
|
|
17723
|
-
return;
|
|
17724
|
-
}
|
|
17725
17649
|
if (toolbarVariantRef.current === "select-frame") {
|
|
17726
17650
|
const parent2 = getNavigationSelectionParent(selectedElRef.current);
|
|
17727
17651
|
if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
|
|
@@ -17741,6 +17665,13 @@ function OhhwellsBridge() {
|
|
|
17741
17665
|
}
|
|
17742
17666
|
}
|
|
17743
17667
|
};
|
|
17668
|
+
const handleFormCount = (e) => {
|
|
17669
|
+
if (e.data?.type !== "ow:form-count") return;
|
|
17670
|
+
const form = formPickElRef.current;
|
|
17671
|
+
if (!form || formKeyOf(form) !== e.data.formKey) return;
|
|
17672
|
+
setFormPickCount(typeof e.data.count === "number" ? e.data.count : null);
|
|
17673
|
+
};
|
|
17674
|
+
window.addEventListener("message", handleFormCount);
|
|
17744
17675
|
window.addEventListener("message", handleUiEscape);
|
|
17745
17676
|
const handleKeyDown = (e) => {
|
|
17746
17677
|
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -17760,11 +17691,12 @@ function OhhwellsBridge() {
|
|
|
17760
17691
|
closeFloatingPanelOnlyRef.current();
|
|
17761
17692
|
return;
|
|
17762
17693
|
}
|
|
17694
|
+
if (e.key === "Escape" && formPickElRef.current) {
|
|
17695
|
+
e.preventDefault();
|
|
17696
|
+
clearFormPickRef.current();
|
|
17697
|
+
return;
|
|
17698
|
+
}
|
|
17763
17699
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
17764
|
-
if (toolbarVariantRef.current === "logo") {
|
|
17765
|
-
deselectRef.current();
|
|
17766
|
-
return;
|
|
17767
|
-
}
|
|
17768
17700
|
if (toolbarVariantRef.current === "select-frame") {
|
|
17769
17701
|
const parent2 = getNavigationSelectionParent(selectedElRef.current);
|
|
17770
17702
|
if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
|
|
@@ -17842,8 +17774,7 @@ function OhhwellsBridge() {
|
|
|
17842
17774
|
const handleScroll = () => {
|
|
17843
17775
|
const focusEl = activeElRef.current ?? selectedElRef.current;
|
|
17844
17776
|
if (focusEl) {
|
|
17845
|
-
const
|
|
17846
|
-
const r2 = measureEl ? measureEl.getBoundingClientRect() : toolbarVariantRef.current === "logo" ? getLogoInteractionRect(focusEl) : focusEl.getBoundingClientRect();
|
|
17777
|
+
const r2 = activeElRef.current ? getEditMeasureEl(activeElRef.current).getBoundingClientRect() : focusEl.getBoundingClientRect();
|
|
17847
17778
|
applyToolbarPos(r2);
|
|
17848
17779
|
setToolbarRect(r2);
|
|
17849
17780
|
setMaxBadge((prev) => prev && activeElRef.current ? { ...prev, rect: r2 } : prev);
|
|
@@ -17853,9 +17784,7 @@ function OhhwellsBridge() {
|
|
|
17853
17784
|
setToggleState((prev) => prev ? { ...prev, rect } : null);
|
|
17854
17785
|
}
|
|
17855
17786
|
if (hoveredItemElRef.current) {
|
|
17856
|
-
|
|
17857
|
-
const logo = getLogoElement(hoverEl);
|
|
17858
|
-
setHoveredItemRect(logo ? getLogoInteractionRect(logo) : hoverEl.getBoundingClientRect());
|
|
17787
|
+
setHoveredItemRect(hoveredItemElRef.current.getBoundingClientRect());
|
|
17859
17788
|
}
|
|
17860
17789
|
if (hoveredNavContainerRef.current) {
|
|
17861
17790
|
setHoveredNavContainerRect(hoveredNavContainerRef.current.getBoundingClientRect());
|
|
@@ -17899,12 +17828,13 @@ function OhhwellsBridge() {
|
|
|
17899
17828
|
if (aiSectionsRef.current) {
|
|
17900
17829
|
nodes.push({ key: AI_SECTIONS_KEY, type: "sections", text: aiSectionsRef.current });
|
|
17901
17830
|
}
|
|
17902
|
-
|
|
17903
|
-
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
17907
|
-
|
|
17831
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
17832
|
+
const formKey = formKeyOf(form);
|
|
17833
|
+
if (!formKey) return;
|
|
17834
|
+
const specs = readFieldsFromDom(form);
|
|
17835
|
+
const text = specs.length ? JSON.stringify(specs) : editContentRef.current[fieldsKey(formKey)];
|
|
17836
|
+
if (text) nodes.push({ key: fieldsKey(formKey), type: "text", text });
|
|
17837
|
+
});
|
|
17908
17838
|
postToParentRef.current({ type: "ow:save-result", nodes });
|
|
17909
17839
|
};
|
|
17910
17840
|
const handleInsertSection = (e) => {
|
|
@@ -17915,12 +17845,8 @@ function OhhwellsBridge() {
|
|
|
17915
17845
|
if (inserted) {
|
|
17916
17846
|
const tracker = getSectionsTracker();
|
|
17917
17847
|
postToParentRef.current({ type: "ow:change", nodes: [{ key: "__ohw_sections", text: tracker.textContent ?? "[]" }] });
|
|
17918
|
-
const
|
|
17919
|
-
|
|
17920
|
-
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
17921
|
-
};
|
|
17922
|
-
reportHeight();
|
|
17923
|
-
setTimeout(reportHeight, 500);
|
|
17848
|
+
const h = document.documentElement.scrollHeight;
|
|
17849
|
+
if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
|
|
17924
17850
|
}
|
|
17925
17851
|
};
|
|
17926
17852
|
const handleSwitchSchedule = (e) => {
|
|
@@ -18113,17 +18039,13 @@ function OhhwellsBridge() {
|
|
|
18113
18039
|
if (e.data?.type !== "ow:parent-scroll") return;
|
|
18114
18040
|
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
18115
18041
|
parentScrollRef.current = { iframeOffsetTop, headerH, canvasH };
|
|
18116
|
-
if (floatingPanelOpenRef.current) {
|
|
18117
|
-
setParentScrollSnap({ iframeOffsetTop, headerH, canvasH });
|
|
18118
|
-
}
|
|
18119
18042
|
if (visibleViewportRef.current) {
|
|
18120
18043
|
applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
|
|
18121
18044
|
}
|
|
18122
18045
|
const focusEl = activeElRef.current ?? selectedElRef.current;
|
|
18123
18046
|
if (focusEl) {
|
|
18124
|
-
const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) :
|
|
18125
|
-
|
|
18126
|
-
applyToolbarPos(r2);
|
|
18047
|
+
const measureEl = activeElRef.current ? getEditMeasureEl(activeElRef.current) : focusEl;
|
|
18048
|
+
applyToolbarPos(measureEl.getBoundingClientRect());
|
|
18127
18049
|
}
|
|
18128
18050
|
};
|
|
18129
18051
|
const handleClickAt = (e) => {
|
|
@@ -18156,15 +18078,9 @@ function OhhwellsBridge() {
|
|
|
18156
18078
|
return clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
|
|
18157
18079
|
});
|
|
18158
18080
|
if (logoAtPoint) {
|
|
18159
|
-
|
|
18160
|
-
|
|
18161
|
-
|
|
18162
|
-
const identity = readLogoIdentityFromDom();
|
|
18163
|
-
postToParentRef.current({ type: "ow:open-logo-settings", ...identity });
|
|
18164
|
-
return;
|
|
18165
|
-
}
|
|
18166
|
-
selectLogoRef.current(logoAtPoint);
|
|
18167
|
-
openLogoSizePanelRef.current(logoAtPoint);
|
|
18081
|
+
deselectRef.current();
|
|
18082
|
+
deactivateRef.current();
|
|
18083
|
+
postToParentRef.current({ type: "ow:open-logo-settings" });
|
|
18168
18084
|
return;
|
|
18169
18085
|
}
|
|
18170
18086
|
const textEditable = Array.from(
|
|
@@ -18238,14 +18154,6 @@ function OhhwellsBridge() {
|
|
|
18238
18154
|
window.addEventListener("message", handleParentScroll);
|
|
18239
18155
|
window.addEventListener("message", handlePointerSync);
|
|
18240
18156
|
window.addEventListener("message", handleClickAt);
|
|
18241
|
-
window.addEventListener("message", handleUpdateLogoIdentity);
|
|
18242
|
-
const handleViewMode = (e) => {
|
|
18243
|
-
if (e.data?.type !== "ow:view-mode") return;
|
|
18244
|
-
const mode = e.data.mode === "Mobile" || e.data.mode === "mobile" ? "mobile" : "desktop";
|
|
18245
|
-
setEditorViewport(mode);
|
|
18246
|
-
applyLogoSizes(editContentRef.current);
|
|
18247
|
-
};
|
|
18248
|
-
window.addEventListener("message", handleViewMode);
|
|
18249
18157
|
const handleViewportResize = () => {
|
|
18250
18158
|
if (visibleViewportRef.current) {
|
|
18251
18159
|
applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
|
|
@@ -18301,17 +18209,13 @@ function OhhwellsBridge() {
|
|
|
18301
18209
|
window.removeEventListener("resize", handleViewportResize);
|
|
18302
18210
|
window.removeEventListener("message", handlePointerSync);
|
|
18303
18211
|
window.removeEventListener("message", handleClickAt);
|
|
18304
|
-
window.removeEventListener("message", handleUpdateLogoIdentity);
|
|
18305
|
-
window.removeEventListener("message", handleViewMode);
|
|
18306
18212
|
window.removeEventListener("message", handleHydrate);
|
|
18307
18213
|
window.removeEventListener("message", handleAiApplyTree);
|
|
18308
18214
|
window.removeEventListener("message", handleAiDeleteSection);
|
|
18309
18215
|
window.removeEventListener("message", handleAiSetSections);
|
|
18310
|
-
window.removeEventListener("message", handleAiSetBrand);
|
|
18311
|
-
window.removeEventListener("message", handleAiSetStyles);
|
|
18312
|
-
window.removeEventListener("message", handleGetBrand);
|
|
18313
18216
|
window.removeEventListener("message", handleDeactivate);
|
|
18314
18217
|
window.removeEventListener("message", handleToastAction);
|
|
18218
|
+
window.removeEventListener("message", handleFormCount);
|
|
18315
18219
|
window.removeEventListener("message", handleUiEscape);
|
|
18316
18220
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
18317
18221
|
autoSaveTimers.current.clear();
|
|
@@ -18335,7 +18239,9 @@ function OhhwellsBridge() {
|
|
|
18335
18239
|
if (footerDragRef.current) return;
|
|
18336
18240
|
const target = e.target;
|
|
18337
18241
|
if (!target) return;
|
|
18338
|
-
if (target.closest(
|
|
18242
|
+
if (target.closest(
|
|
18243
|
+
'[data-ohw-drag-handle-container], [data-slot="drag-handle"], [data-ohw-toolbar], [data-ohw-item-toolbar-anchor], [data-ohw-link-popover-root], [data-ohw-floating-panel], [data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"]'
|
|
18244
|
+
)) {
|
|
18339
18245
|
return;
|
|
18340
18246
|
}
|
|
18341
18247
|
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
@@ -18513,7 +18419,7 @@ function OhhwellsBridge() {
|
|
|
18513
18419
|
postToParent2({
|
|
18514
18420
|
type: "ow:ready",
|
|
18515
18421
|
version: "1",
|
|
18516
|
-
bridgeVersion: "0.1.
|
|
18422
|
+
bridgeVersion: "0.1.63",
|
|
18517
18423
|
path: pathname,
|
|
18518
18424
|
nodes: collectEditableNodes(editContentRef.current),
|
|
18519
18425
|
sections
|
|
@@ -18980,6 +18886,151 @@ function OhhwellsBridge() {
|
|
|
18980
18886
|
hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
18981
18887
|
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
18982
18888
|
hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
|
|
18889
|
+
formPickRect && !isItemDragging && /* @__PURE__ */ jsx33(
|
|
18890
|
+
ItemInteractionLayer,
|
|
18891
|
+
{
|
|
18892
|
+
rect: formPickRect,
|
|
18893
|
+
state: "active-top",
|
|
18894
|
+
itemDragSurface: false,
|
|
18895
|
+
toolbarAlign: "left",
|
|
18896
|
+
chromeGap: 24,
|
|
18897
|
+
toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ jsxs20(
|
|
18898
|
+
"div",
|
|
18899
|
+
{
|
|
18900
|
+
"data-ohw-form-toolbar": "",
|
|
18901
|
+
className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
|
|
18902
|
+
children: [
|
|
18903
|
+
/* @__PURE__ */ jsx33(
|
|
18904
|
+
"button",
|
|
18905
|
+
{
|
|
18906
|
+
type: "button",
|
|
18907
|
+
"aria-label": "Add field",
|
|
18908
|
+
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
|
|
18909
|
+
onClick: () => setFieldTypePickerOpen((open) => !open),
|
|
18910
|
+
"data-ohw-add-field": "",
|
|
18911
|
+
children: /* @__PURE__ */ jsx33(Plus4, { size: 15, "aria-hidden": true })
|
|
18912
|
+
}
|
|
18913
|
+
),
|
|
18914
|
+
/* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
18915
|
+
/* @__PURE__ */ jsxs20(
|
|
18916
|
+
"button",
|
|
18917
|
+
{
|
|
18918
|
+
type: "button",
|
|
18919
|
+
className: "flex h-7 items-center gap-1.5 whitespace-nowrap rounded-md px-2 text-[13px] font-semibold text-foreground transition-colors hover:bg-muted/80",
|
|
18920
|
+
onClick: () => {
|
|
18921
|
+
const form = formPickElRef.current;
|
|
18922
|
+
if (!form) return;
|
|
18923
|
+
postToParent2({
|
|
18924
|
+
type: "ow:form-pick",
|
|
18925
|
+
formKey: formKeyOf(form),
|
|
18926
|
+
hasLongText: formHasLongText(form)
|
|
18927
|
+
});
|
|
18928
|
+
},
|
|
18929
|
+
children: [
|
|
18930
|
+
/* @__PURE__ */ jsx33(Settings, { size: 14, "aria-hidden": true }),
|
|
18931
|
+
"Form settings",
|
|
18932
|
+
formPickCount ? (
|
|
18933
|
+
// Counter pill, per the design — not a text suffix.
|
|
18934
|
+
/* @__PURE__ */ jsx33(
|
|
18935
|
+
"span",
|
|
18936
|
+
{
|
|
18937
|
+
"data-ohw-form-count": "",
|
|
18938
|
+
className: "ml-0.5 inline-flex h-[18px] min-w-[18px] items-center justify-center rounded-full bg-primary px-1.5 text-[11px] font-semibold text-primary-foreground",
|
|
18939
|
+
children: formPickCount
|
|
18940
|
+
}
|
|
18941
|
+
)
|
|
18942
|
+
) : null
|
|
18943
|
+
]
|
|
18944
|
+
}
|
|
18945
|
+
),
|
|
18946
|
+
/* @__PURE__ */ jsx33("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
18947
|
+
/* @__PURE__ */ jsx33("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ jsx33(
|
|
18948
|
+
"button",
|
|
18949
|
+
{
|
|
18950
|
+
type: "button",
|
|
18951
|
+
"aria-pressed": formViewState === state,
|
|
18952
|
+
className: "rounded-md px-2.5 py-1 text-[13px] font-semibold capitalize transition-colors " + (formViewState === state ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
|
|
18953
|
+
onClick: () => {
|
|
18954
|
+
const form = formPickElRef.current;
|
|
18955
|
+
const key = form ? formKeyOf(form) : null;
|
|
18956
|
+
if (!form || !key) return;
|
|
18957
|
+
const initial = successInitialFor(form, key, editContentRef.current);
|
|
18958
|
+
setFormViewState(form, key, state, initial);
|
|
18959
|
+
setFormViewStateUi(state);
|
|
18960
|
+
setFormPickRect(form.getBoundingClientRect());
|
|
18961
|
+
if (state === "success") {
|
|
18962
|
+
const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
|
|
18963
|
+
if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
|
|
18964
|
+
} else {
|
|
18965
|
+
deactivateRef.current();
|
|
18966
|
+
}
|
|
18967
|
+
},
|
|
18968
|
+
children: state
|
|
18969
|
+
},
|
|
18970
|
+
state
|
|
18971
|
+
)) })
|
|
18972
|
+
]
|
|
18973
|
+
}
|
|
18974
|
+
)
|
|
18975
|
+
}
|
|
18976
|
+
),
|
|
18977
|
+
formHoverRect && !isItemDragging && /* @__PURE__ */ jsx33(
|
|
18978
|
+
ItemInteractionLayer,
|
|
18979
|
+
{
|
|
18980
|
+
rect: formHoverRect,
|
|
18981
|
+
state: "hover",
|
|
18982
|
+
chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
|
|
18983
|
+
}
|
|
18984
|
+
),
|
|
18985
|
+
fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ jsx33(
|
|
18986
|
+
ItemInteractionLayer,
|
|
18987
|
+
{
|
|
18988
|
+
rect: fieldPickRect,
|
|
18989
|
+
state: fieldDragging ? "dragging" : "active-top",
|
|
18990
|
+
itemDragSurface: false,
|
|
18991
|
+
toolbarAlign: "left",
|
|
18992
|
+
chromeGap: 10,
|
|
18993
|
+
showHandle: true,
|
|
18994
|
+
dragHandleLabel: "Reorder field",
|
|
18995
|
+
onDragHandleDragStart: handleFieldDragStart,
|
|
18996
|
+
onDragHandleDragEnd: handleFieldDragEnd,
|
|
18997
|
+
toolbar: /* @__PURE__ */ jsx33(
|
|
18998
|
+
FormFieldToolbar,
|
|
18999
|
+
{
|
|
19000
|
+
type: fieldPickState.type,
|
|
19001
|
+
required: fieldPickState.required,
|
|
19002
|
+
onTypeChange: handleFieldTypeChange,
|
|
19003
|
+
onRequiredToggle: handleFieldRequiredToggle,
|
|
19004
|
+
onDuplicate: handleFieldDuplicate,
|
|
19005
|
+
onDelete: handleFieldDelete
|
|
19006
|
+
}
|
|
19007
|
+
)
|
|
19008
|
+
}
|
|
19009
|
+
),
|
|
19010
|
+
fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ jsx33(
|
|
19011
|
+
"div",
|
|
19012
|
+
{
|
|
19013
|
+
className: "pointer-events-none fixed z-[2147483644]",
|
|
19014
|
+
style: { top: slot.top, left: slot.left, width: slot.width },
|
|
19015
|
+
children: /* @__PURE__ */ jsx33(
|
|
19016
|
+
DropIndicator,
|
|
19017
|
+
{
|
|
19018
|
+
direction: "horizontal",
|
|
19019
|
+
state: fieldDropIndex === i ? "dragActive" : "dragIdle",
|
|
19020
|
+
className: "!w-full"
|
|
19021
|
+
}
|
|
19022
|
+
)
|
|
19023
|
+
},
|
|
19024
|
+
`field-drop-${i}`
|
|
19025
|
+
)) : null,
|
|
19026
|
+
fieldTypePickerOpen && formPickRect && /* @__PURE__ */ jsx33(
|
|
19027
|
+
"div",
|
|
19028
|
+
{
|
|
19029
|
+
className: "pointer-events-none fixed z-[2147483645]",
|
|
19030
|
+
style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
|
|
19031
|
+
children: /* @__PURE__ */ jsx33(FieldTypePicker, { onPick: handleAddField })
|
|
19032
|
+
}
|
|
19033
|
+
),
|
|
18983
19034
|
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ jsx33(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
18984
19035
|
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ jsx33(
|
|
18985
19036
|
FooterContainerChrome,
|
|
@@ -18989,7 +19040,7 @@ function OhhwellsBridge() {
|
|
|
18989
19040
|
addDisabled: !canAddFooterColumn()
|
|
18990
19041
|
}
|
|
18991
19042
|
),
|
|
18992
|
-
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame"
|
|
19043
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ jsx33(
|
|
18993
19044
|
ItemInteractionLayer,
|
|
18994
19045
|
{
|
|
18995
19046
|
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
@@ -19001,9 +19052,9 @@ function OhhwellsBridge() {
|
|
|
19001
19052
|
dragHandleLabel: reorderHrefKey ? `Reorder ${reorderHrefKey}` : "Reorder item",
|
|
19002
19053
|
onDragHandleDragStart: handleItemDragStart,
|
|
19003
19054
|
onDragHandleDragEnd: handleItemDragEnd,
|
|
19004
|
-
onItemPointerDown:
|
|
19005
|
-
onItemClick:
|
|
19006
|
-
itemDragSurface:
|
|
19055
|
+
onItemPointerDown: handleItemChromePointerDown,
|
|
19056
|
+
onItemClick: handleItemChromeClick,
|
|
19057
|
+
itemDragSurface: !isFooterFrameSelection,
|
|
19007
19058
|
toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ jsx33(
|
|
19008
19059
|
ItemActionToolbar,
|
|
19009
19060
|
{
|
|
@@ -19166,115 +19217,11 @@ function OhhwellsBridge() {
|
|
|
19166
19217
|
}
|
|
19167
19218
|
)
|
|
19168
19219
|
}
|
|
19169
|
-
) : null,
|
|
19170
|
-
floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ jsx33(
|
|
19171
|
-
FloatingPanel,
|
|
19172
|
-
{
|
|
19173
|
-
open: true,
|
|
19174
|
-
title: floatingPanel.title,
|
|
19175
|
-
context: floatingPanel.context,
|
|
19176
|
-
position: floatingPanelPos,
|
|
19177
|
-
onPositionChange: setFloatingPanelPos,
|
|
19178
|
-
parentScroll: parentScrollSnap ?? parentScrollRef.current,
|
|
19179
|
-
onClose: closeFloatingPanelAndDeselect,
|
|
19180
|
-
children: /* @__PURE__ */ jsx33(
|
|
19181
|
-
LogoSizePanel,
|
|
19182
|
-
{
|
|
19183
|
-
viewport: editorViewport,
|
|
19184
|
-
sizePx: editorViewport === "mobile" && !logoSizeDraft.mobileFollowing ? logoSizeDraft.mobilePx : logoSizeDraft.desktopPx,
|
|
19185
|
-
mobileFollowing: logoSizeDraft.mobileFollowing,
|
|
19186
|
-
onSizeChange: (px) => {
|
|
19187
|
-
const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx: px, mobileFollowing: false } : {
|
|
19188
|
-
...logoSizeDraft,
|
|
19189
|
-
desktopPx: px,
|
|
19190
|
-
mobilePx: logoSizeDraft.mobileFollowing ? px : logoSizeDraft.mobilePx
|
|
19191
|
-
};
|
|
19192
|
-
setLogoSizeDraft(next);
|
|
19193
|
-
persistLogoSizeDraft(floatingPanel.placement, next);
|
|
19194
|
-
},
|
|
19195
|
-
onCustomizeMobile: () => {
|
|
19196
|
-
const next = {
|
|
19197
|
-
...logoSizeDraft,
|
|
19198
|
-
mobileFollowing: false,
|
|
19199
|
-
mobilePx: logoSizeDraft.desktopPx
|
|
19200
|
-
};
|
|
19201
|
-
setLogoSizeDraft(next);
|
|
19202
|
-
persistLogoSizeDraft(floatingPanel.placement, next);
|
|
19203
|
-
},
|
|
19204
|
-
onResetMobile: () => {
|
|
19205
|
-
const next = {
|
|
19206
|
-
...logoSizeDraft,
|
|
19207
|
-
mobileFollowing: true,
|
|
19208
|
-
mobilePx: logoSizeDraft.desktopPx
|
|
19209
|
-
};
|
|
19210
|
-
setLogoSizeDraft(next);
|
|
19211
|
-
persistLogoSizeDraft(floatingPanel.placement, next);
|
|
19212
|
-
},
|
|
19213
|
-
onUpdateEverywhere: () => {
|
|
19214
|
-
const identity = readLogoIdentityFromDom();
|
|
19215
|
-
postToParent2({ type: "ow:open-logo-settings", ...identity });
|
|
19216
|
-
}
|
|
19217
|
-
}
|
|
19218
|
-
)
|
|
19219
|
-
}
|
|
19220
19220
|
) : null
|
|
19221
19221
|
] }),
|
|
19222
19222
|
bridgeRoot
|
|
19223
19223
|
) : null;
|
|
19224
19224
|
}
|
|
19225
|
-
|
|
19226
|
-
// src/ui/EmptySection.tsx
|
|
19227
|
-
import Link4 from "next/link";
|
|
19228
|
-
import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
19229
|
-
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
19230
|
-
return /* @__PURE__ */ jsxs21(Fragment9, { children: [
|
|
19231
|
-
/* @__PURE__ */ jsx34(
|
|
19232
|
-
"p",
|
|
19233
|
-
{
|
|
19234
|
-
style: {
|
|
19235
|
-
fontFamily: "var(--brand-font-body)",
|
|
19236
|
-
fontSize: "0.75rem",
|
|
19237
|
-
fontWeight: 500,
|
|
19238
|
-
letterSpacing: "0.15em",
|
|
19239
|
-
textTransform: "uppercase",
|
|
19240
|
-
color: "var(--brand-accent)",
|
|
19241
|
-
marginBottom: "1.5rem"
|
|
19242
|
-
},
|
|
19243
|
-
children: /* @__PURE__ */ jsx34(Link4, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ jsx34("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
19244
|
-
}
|
|
19245
|
-
),
|
|
19246
|
-
/* @__PURE__ */ jsx34(
|
|
19247
|
-
"h1",
|
|
19248
|
-
{
|
|
19249
|
-
style: {
|
|
19250
|
-
fontFamily: "var(--brand-font-heading)",
|
|
19251
|
-
fontSize: "clamp(2rem, 3.5vw, 2.75rem)",
|
|
19252
|
-
lineHeight: 1.1,
|
|
19253
|
-
letterSpacing: "-0.025em",
|
|
19254
|
-
color: "var(--brand-text)",
|
|
19255
|
-
marginBottom: "1rem"
|
|
19256
|
-
},
|
|
19257
|
-
...titleKey ? { "data-ohw-editable": "text", "data-ohw-key": titleKey, "data-ohw-max-length": 80 } : {},
|
|
19258
|
-
children: title
|
|
19259
|
-
}
|
|
19260
|
-
),
|
|
19261
|
-
/* @__PURE__ */ jsx34(
|
|
19262
|
-
"p",
|
|
19263
|
-
{
|
|
19264
|
-
style: {
|
|
19265
|
-
fontFamily: "var(--brand-font-body)",
|
|
19266
|
-
fontSize: "1rem",
|
|
19267
|
-
lineHeight: 1.7,
|
|
19268
|
-
fontWeight: 300,
|
|
19269
|
-
color: "var(--brand-text-muted)",
|
|
19270
|
-
maxWidth: "340px"
|
|
19271
|
-
},
|
|
19272
|
-
...subtitleKey ? { "data-ohw-editable": "text", "data-ohw-key": subtitleKey, "data-ohw-max-length": 160 } : {},
|
|
19273
|
-
children: "This page doesn't have any content yet."
|
|
19274
|
-
}
|
|
19275
|
-
)
|
|
19276
|
-
] });
|
|
19277
|
-
}
|
|
19278
19225
|
export {
|
|
19279
19226
|
AI_DEFAULT_BRAND,
|
|
19280
19227
|
AI_TREE_SCHEMA_VERSIONS,
|
|
@@ -19291,7 +19238,6 @@ export {
|
|
|
19291
19238
|
DropdownMenuItem,
|
|
19292
19239
|
DropdownMenuSeparator,
|
|
19293
19240
|
DropdownMenuTrigger,
|
|
19294
|
-
EmptySection,
|
|
19295
19241
|
ItemActionToolbar,
|
|
19296
19242
|
ItemInteractionLayer,
|
|
19297
19243
|
LinkEditorPanel,
|