@ohhwells/bridge 0.1.64-next.176 → 0.1.65-next.179
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 +1438 -275
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1422 -259
- package/dist/index.js.map +1 -1
- package/dist/styles.css +92 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -157,7 +157,12 @@ function parseAiSectionsState(raw) {
|
|
|
157
157
|
media: entry.media && typeof entry.media === "object" ? entry.media : {}
|
|
158
158
|
}));
|
|
159
159
|
const removed = Array.isArray(parsed.removed) ? parsed.removed.filter((id) => typeof id === "string" && id.length > 0) : [];
|
|
160
|
-
return {
|
|
160
|
+
return {
|
|
161
|
+
v: 1,
|
|
162
|
+
sections,
|
|
163
|
+
...removed.length ? { removed } : {},
|
|
164
|
+
...parsed.hideTemplate === true ? { hideTemplate: true } : {}
|
|
165
|
+
};
|
|
161
166
|
} catch {
|
|
162
167
|
return EMPTY_AI_SECTIONS;
|
|
163
168
|
}
|
|
@@ -534,6 +539,36 @@ var FEATURE_LINE_CSS = [
|
|
|
534
539
|
`background-color:currentColor;-webkit-mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px;`,
|
|
535
540
|
`mask:url("${CHECK_MASK}") no-repeat 0 0/24px 24px}`
|
|
536
541
|
].join("");
|
|
542
|
+
function hexLuminance(color) {
|
|
543
|
+
const m = /^#([0-9a-f]{6})$/i.exec(color.trim());
|
|
544
|
+
if (!m) return null;
|
|
545
|
+
const [r2, g, b] = [0, 2, 4].map((i) => {
|
|
546
|
+
const c = parseInt(m[1].slice(i, i + 2), 16) / 255;
|
|
547
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
548
|
+
});
|
|
549
|
+
return 0.2126 * r2 + 0.7152 * g + 0.0722 * b;
|
|
550
|
+
}
|
|
551
|
+
function hexContrast(a, b) {
|
|
552
|
+
const la = hexLuminance(a);
|
|
553
|
+
const lb = hexLuminance(b);
|
|
554
|
+
if (la === null || lb === null) return null;
|
|
555
|
+
const [hi, lo] = la > lb ? [la, lb] : [lb, la];
|
|
556
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
557
|
+
}
|
|
558
|
+
function accentBandContext(brand) {
|
|
559
|
+
const p = brand.palette;
|
|
560
|
+
const lightWins = (hexContrast(p.light, p.primary) ?? 99) >= (hexContrast(p.dark, p.primary) ?? 0);
|
|
561
|
+
if (lightWins) {
|
|
562
|
+
return {
|
|
563
|
+
brand: { ...brand, palette: { dark: p.light, primary: p.light, accent: p.light, light: p.primary } },
|
|
564
|
+
buttonLabel: p.primary
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
brand: { ...brand, palette: { dark: p.dark, primary: p.dark, accent: p.dark, light: p.light } },
|
|
569
|
+
buttonLabel: p.light
|
|
570
|
+
};
|
|
571
|
+
}
|
|
537
572
|
function textAttrs(ctx, path) {
|
|
538
573
|
return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
|
|
539
574
|
}
|
|
@@ -641,7 +676,7 @@ function ButtonEl({
|
|
|
641
676
|
textDecoration: "none",
|
|
642
677
|
cursor: "pointer",
|
|
643
678
|
...typeStyle(AI_TREE_TOKENS.type.button, ctx.brand.fonts.body),
|
|
644
|
-
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: AI_TREE_TOKENS.textPrimaryForeground }
|
|
679
|
+
...secondary ? { border: `1px solid ${ctx.brand.palette.dark}`, color: ctx.brand.palette.dark } : { background: ctx.brand.palette.primary, color: ctx.buttonLabel ?? AI_TREE_TOKENS.textPrimaryForeground }
|
|
645
680
|
},
|
|
646
681
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...path ? textAttrs(ctx, `${path}.label`) : {}, children: str(slots.label) })
|
|
647
682
|
}
|
|
@@ -1543,11 +1578,14 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1543
1578
|
return null;
|
|
1544
1579
|
}
|
|
1545
1580
|
const resolvedBrand = brand ?? AI_DEFAULT_BRAND;
|
|
1581
|
+
const band = (tree.settings ?? {}).sectionBackground === "accent" ? accentBandContext(resolvedBrand) : null;
|
|
1582
|
+
const blockBrand = band?.brand ?? resolvedBrand;
|
|
1546
1583
|
const ctx = {
|
|
1547
|
-
brand:
|
|
1584
|
+
brand: blockBrand,
|
|
1548
1585
|
resolveMedia: resolveMedia ?? (() => null),
|
|
1549
|
-
cardSurface:
|
|
1550
|
-
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null
|
|
1586
|
+
cardSurface: blockBrand.palette.light.toUpperCase() === AI_DEFAULT_BRAND.palette.light.toUpperCase() ? "#ECECEB" : `color-mix(in srgb, ${blockBrand.palette.light} 90%, ${blockBrand.palette.dark})`,
|
|
1587
|
+
keyFor: editKeyPrefix ? (path) => `${editKeyPrefix}.${path}` : null,
|
|
1588
|
+
...band ? { buttonLabel: band.buttonLabel } : {}
|
|
1551
1589
|
};
|
|
1552
1590
|
const settings = tree.settings ?? {};
|
|
1553
1591
|
const pad = AI_TREE_TOKENS.sectionPadding[settings.spacing ?? "balanced"];
|
|
@@ -1582,7 +1620,7 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
|
|
|
1582
1620
|
backgroundImage: backgroundUrl ? `url(${backgroundUrl})` : void 0,
|
|
1583
1621
|
backgroundSize: "cover",
|
|
1584
1622
|
backgroundPosition: "center",
|
|
1585
|
-
color: settings.sectionBackground === "accent" ?
|
|
1623
|
+
color: settings.sectionBackground === "accent" ? blockBrand.palette.dark : void 0
|
|
1586
1624
|
},
|
|
1587
1625
|
children: [
|
|
1588
1626
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
|
|
@@ -1639,6 +1677,8 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
|
1639
1677
|
var CONTAINER_ATTR = "data-ohw-ai-generated";
|
|
1640
1678
|
var REPLACED_ATTR = "data-ohw-ai-replaced-by";
|
|
1641
1679
|
var REMOVED_ATTR = "data-ohw-ai-removed";
|
|
1680
|
+
var TEMPLATE_HIDDEN_ATTR = "data-ohw-ai-template-hidden";
|
|
1681
|
+
var CHROME_SECTION_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
1642
1682
|
function readRootVar(name) {
|
|
1643
1683
|
if (typeof document === "undefined") return "";
|
|
1644
1684
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
@@ -1738,6 +1778,24 @@ function syncRemovedSections(state) {
|
|
|
1738
1778
|
}
|
|
1739
1779
|
}
|
|
1740
1780
|
}
|
|
1781
|
+
function syncTemplateHidden(state, pageHasSections) {
|
|
1782
|
+
const hide = state.hideTemplate === true && pageHasSections;
|
|
1783
|
+
for (const el of Array.from(document.querySelectorAll(`[${TEMPLATE_HIDDEN_ATTR}]`))) {
|
|
1784
|
+
if (!hide) {
|
|
1785
|
+
el.style.removeProperty("display");
|
|
1786
|
+
el.removeAttribute(TEMPLATE_HIDDEN_ATTR);
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
if (!hide) return;
|
|
1790
|
+
for (const el of Array.from(document.querySelectorAll("[data-ohw-section]"))) {
|
|
1791
|
+
if (el.hasAttribute(CONTAINER_ATTR)) continue;
|
|
1792
|
+
if (CHROME_SECTION_IDS.has(el.getAttribute("data-ohw-section") ?? "")) continue;
|
|
1793
|
+
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
1794
|
+
if (el.hasAttribute(REPLACED_ATTR) || el.hasAttribute(REMOVED_ATTR)) continue;
|
|
1795
|
+
el.style.display = "none";
|
|
1796
|
+
el.setAttribute(TEMPLATE_HIDDEN_ATTR, "");
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1741
1799
|
function syncReplacedOriginals(state) {
|
|
1742
1800
|
for (const el of document.querySelectorAll(`[${REPLACED_ATTR}]`)) {
|
|
1743
1801
|
const byId = el.getAttribute(REPLACED_ATTR) ?? "";
|
|
@@ -1808,6 +1866,7 @@ function applyAiSectionsToDom(state, options) {
|
|
|
1808
1866
|
}
|
|
1809
1867
|
syncReplacedOriginals(state);
|
|
1810
1868
|
syncRemovedSections(state);
|
|
1869
|
+
syncTemplateHidden(state, pageSections.length > 0);
|
|
1811
1870
|
}
|
|
1812
1871
|
|
|
1813
1872
|
// src/useLinkHrefGuardian.ts
|
|
@@ -6589,6 +6648,7 @@ function getChromeStyle(state) {
|
|
|
6589
6648
|
}
|
|
6590
6649
|
function ClampedToolbarSlot({
|
|
6591
6650
|
placement,
|
|
6651
|
+
align = "center",
|
|
6592
6652
|
children
|
|
6593
6653
|
}) {
|
|
6594
6654
|
const slotRef = (0, import_react7.useRef)(null);
|
|
@@ -6610,7 +6670,7 @@ function ClampedToolbarSlot({
|
|
|
6610
6670
|
Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN - half)
|
|
6611
6671
|
);
|
|
6612
6672
|
const offsetX = clampedCenter - centerX;
|
|
6613
|
-
slot.style.transform = `translateX(calc(-50% + ${offsetX}px))`;
|
|
6673
|
+
slot.style.transform = align === "left" ? "none" : `translateX(calc(-50% + ${offsetX}px))`;
|
|
6614
6674
|
};
|
|
6615
6675
|
clamp();
|
|
6616
6676
|
const ro = new ResizeObserver(clamp);
|
|
@@ -6621,19 +6681,20 @@ function ClampedToolbarSlot({
|
|
|
6621
6681
|
ro.disconnect();
|
|
6622
6682
|
window.removeEventListener("resize", clamp);
|
|
6623
6683
|
};
|
|
6624
|
-
}, [placement, children]);
|
|
6684
|
+
}, [placement, children, align]);
|
|
6625
6685
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6626
6686
|
"div",
|
|
6627
6687
|
{
|
|
6628
6688
|
ref: slotRef,
|
|
6629
6689
|
className: cn(
|
|
6630
|
-
"pointer-events-auto absolute
|
|
6690
|
+
"pointer-events-auto absolute",
|
|
6691
|
+
align === "left" ? "left-0" : "left-1/2",
|
|
6631
6692
|
placement === "top" ? "bottom-full" : "top-full"
|
|
6632
6693
|
),
|
|
6633
6694
|
style: {
|
|
6634
6695
|
marginBottom: placement === "top" ? TOOLBAR_STROKE_GAP : void 0,
|
|
6635
6696
|
marginTop: placement === "bottom" ? TOOLBAR_STROKE_GAP : void 0,
|
|
6636
|
-
transform: "translateX(-50%)"
|
|
6697
|
+
transform: align === "left" ? "none" : "translateX(-50%)"
|
|
6637
6698
|
},
|
|
6638
6699
|
"data-ohw-item-toolbar-anchor": placement,
|
|
6639
6700
|
children
|
|
@@ -6702,6 +6763,7 @@ function ItemInteractionLayer({
|
|
|
6702
6763
|
onItemClick,
|
|
6703
6764
|
itemDragSurface = true,
|
|
6704
6765
|
chromeGap,
|
|
6766
|
+
toolbarAlign = "center",
|
|
6705
6767
|
className
|
|
6706
6768
|
}) {
|
|
6707
6769
|
if (state === "default") return null;
|
|
@@ -6789,8 +6851,8 @@ function ItemInteractionLayer({
|
|
|
6789
6851
|
)
|
|
6790
6852
|
}
|
|
6791
6853
|
),
|
|
6792
|
-
showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { placement: "top", children: toolbar }),
|
|
6793
|
-
showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { placement: "bottom", children: toolbar }),
|
|
6854
|
+
showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { align: toolbarAlign, placement: "top", children: toolbar }),
|
|
6855
|
+
showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { align: toolbarAlign, placement: "bottom", children: toolbar }),
|
|
6794
6856
|
useDetachedBelowToolbar && toolbarBelowRect ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
6795
6857
|
DetachedBelowToolbarSlot,
|
|
6796
6858
|
{
|
|
@@ -6804,14 +6866,580 @@ function ItemInteractionLayer({
|
|
|
6804
6866
|
);
|
|
6805
6867
|
}
|
|
6806
6868
|
|
|
6869
|
+
// src/lib/forms.ts
|
|
6870
|
+
var FORM_SELECTOR = '[data-ohw-editable="form"]';
|
|
6871
|
+
function getFormElement(el) {
|
|
6872
|
+
if (!el) return null;
|
|
6873
|
+
return el.closest(FORM_SELECTOR);
|
|
6874
|
+
}
|
|
6875
|
+
function formKeyOf(form) {
|
|
6876
|
+
return form.getAttribute("data-ohw-key");
|
|
6877
|
+
}
|
|
6878
|
+
function formHasLongText(form) {
|
|
6879
|
+
return form.querySelector("textarea") !== null;
|
|
6880
|
+
}
|
|
6881
|
+
function collectFormFields(form) {
|
|
6882
|
+
const fields = {};
|
|
6883
|
+
form.querySelectorAll(
|
|
6884
|
+
"input, textarea, select"
|
|
6885
|
+
).forEach((input) => {
|
|
6886
|
+
const type = input.type;
|
|
6887
|
+
if (type === "submit" || type === "button" || type === "reset") return;
|
|
6888
|
+
const key = input.getAttribute("name") ?? input.getAttribute("data-ohw-key");
|
|
6889
|
+
if (!key) return;
|
|
6890
|
+
if (type === "checkbox") {
|
|
6891
|
+
fields[key] = input.checked ? "yes" : "no";
|
|
6892
|
+
return;
|
|
6893
|
+
}
|
|
6894
|
+
fields[key] = input.value;
|
|
6895
|
+
});
|
|
6896
|
+
return fields;
|
|
6897
|
+
}
|
|
6898
|
+
function formStateContainer(form) {
|
|
6899
|
+
return form.closest("[data-ohw-editable-state]") ?? form.parentElement ?? form;
|
|
6900
|
+
}
|
|
6901
|
+
function showSuccess(form, message) {
|
|
6902
|
+
const container = formStateContainer(form);
|
|
6903
|
+
const views = container.querySelectorAll("[data-ohw-state-view]");
|
|
6904
|
+
if (views.length > 0) {
|
|
6905
|
+
views.forEach((view) => {
|
|
6906
|
+
view.style.display = view.getAttribute("data-ohw-state-view") === "success" ? "block" : "none";
|
|
6907
|
+
});
|
|
6908
|
+
return;
|
|
6909
|
+
}
|
|
6910
|
+
const text = message ?? form.getAttribute("data-ohw-success-text") ?? DEFAULT_SUCCESS_TEXT;
|
|
6911
|
+
const note = document.createElement("p");
|
|
6912
|
+
note.setAttribute("data-ohw-form-success", "");
|
|
6913
|
+
note.setAttribute("role", "status");
|
|
6914
|
+
note.innerHTML = text;
|
|
6915
|
+
form.replaceChildren(note);
|
|
6916
|
+
}
|
|
6917
|
+
function showSubmitError(form) {
|
|
6918
|
+
let note = form.querySelector("[data-ohw-form-error]");
|
|
6919
|
+
if (!note) {
|
|
6920
|
+
note = document.createElement("p");
|
|
6921
|
+
note.setAttribute("data-ohw-form-error", "");
|
|
6922
|
+
note.setAttribute("role", "alert");
|
|
6923
|
+
note.style.marginTop = "8px";
|
|
6924
|
+
form.appendChild(note);
|
|
6925
|
+
}
|
|
6926
|
+
note.textContent = "Something went wrong. Please try again.";
|
|
6927
|
+
note.style.display = "";
|
|
6928
|
+
}
|
|
6929
|
+
function clearSubmitError(form) {
|
|
6930
|
+
const note = form.querySelector("[data-ohw-form-error]");
|
|
6931
|
+
if (note) note.style.display = "none";
|
|
6932
|
+
}
|
|
6933
|
+
var SUCCESS_TEXT_ATTR = "data-ohw-form-success-text";
|
|
6934
|
+
var HIDDEN_ATTR = "data-ohw-form-hidden";
|
|
6935
|
+
var DEFAULT_SUCCESS_TEXT = "Thanks! We'll be in touch.";
|
|
6936
|
+
function formSuccessKey(formKey) {
|
|
6937
|
+
return `${formKey}-success`;
|
|
6938
|
+
}
|
|
6939
|
+
function ensureSuccessTextEl(form, formKey, initialText) {
|
|
6940
|
+
let el = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
|
|
6941
|
+
if (el) return el;
|
|
6942
|
+
el = document.createElement("p");
|
|
6943
|
+
el.setAttribute(SUCCESS_TEXT_ATTR, "");
|
|
6944
|
+
el.setAttribute("data-ohw-editable", "text");
|
|
6945
|
+
el.setAttribute("data-ohw-key", formSuccessKey(formKey));
|
|
6946
|
+
el.innerHTML = initialText;
|
|
6947
|
+
el.style.display = "none";
|
|
6948
|
+
el.style.margin = "56px 4px 16px";
|
|
6949
|
+
form.appendChild(el);
|
|
6950
|
+
return el;
|
|
6951
|
+
}
|
|
6952
|
+
function setFormViewState(form, formKey, state, initialText) {
|
|
6953
|
+
const success = ensureSuccessTextEl(form, formKey, initialText);
|
|
6954
|
+
Array.from(form.children).forEach((child) => {
|
|
6955
|
+
if (!(child instanceof HTMLElement) || child === success) return;
|
|
6956
|
+
if (state === "success") {
|
|
6957
|
+
if (!child.hasAttribute(HIDDEN_ATTR)) {
|
|
6958
|
+
child.setAttribute(HIDDEN_ATTR, child.style.display);
|
|
6959
|
+
child.style.display = "none";
|
|
6960
|
+
}
|
|
6961
|
+
} else if (child.hasAttribute(HIDDEN_ATTR)) {
|
|
6962
|
+
child.style.display = child.getAttribute(HIDDEN_ATTR) ?? "";
|
|
6963
|
+
child.removeAttribute(HIDDEN_ATTR);
|
|
6964
|
+
}
|
|
6965
|
+
});
|
|
6966
|
+
success.style.display = state === "success" ? "" : "none";
|
|
6967
|
+
}
|
|
6968
|
+
var BOUND_ATTR = "data-ohw-form-bound";
|
|
6969
|
+
function bindPublishedForms(apiUrl, subdomain, content = {}) {
|
|
6970
|
+
document.querySelectorAll(FORM_SELECTOR).forEach((form) => {
|
|
6971
|
+
if (form.hasAttribute(BOUND_ATTR)) return;
|
|
6972
|
+
if (!(form instanceof HTMLFormElement)) return;
|
|
6973
|
+
const formKey = formKeyOf(form);
|
|
6974
|
+
if (!formKey) return;
|
|
6975
|
+
form.setAttribute(BOUND_ATTR, "");
|
|
6976
|
+
form.addEventListener("submit", async (e) => {
|
|
6977
|
+
e.preventDefault();
|
|
6978
|
+
clearSubmitError(form);
|
|
6979
|
+
const submitButton = form.querySelector(
|
|
6980
|
+
'button[type="submit"], input[type="submit"], button:not([type])'
|
|
6981
|
+
);
|
|
6982
|
+
if (submitButton) submitButton.disabled = true;
|
|
6983
|
+
try {
|
|
6984
|
+
const response = await fetch(`${apiUrl}/api/public/sites/${subdomain}/forms/submissions`, {
|
|
6985
|
+
method: "POST",
|
|
6986
|
+
headers: { "Content-Type": "application/json" },
|
|
6987
|
+
body: JSON.stringify({
|
|
6988
|
+
formKey,
|
|
6989
|
+
fields: collectFormFields(form),
|
|
6990
|
+
hasLongText: formHasLongText(form)
|
|
6991
|
+
})
|
|
6992
|
+
});
|
|
6993
|
+
if (!response.ok) throw new Error(`submit failed: ${response.status}`);
|
|
6994
|
+
showSuccess(form, content[formSuccessKey(formKey)]);
|
|
6995
|
+
} catch {
|
|
6996
|
+
showSubmitError(form);
|
|
6997
|
+
if (submitButton) submitButton.disabled = false;
|
|
6998
|
+
}
|
|
6999
|
+
});
|
|
7000
|
+
});
|
|
7001
|
+
}
|
|
7002
|
+
|
|
7003
|
+
// src/lib/form-fields.ts
|
|
7004
|
+
var FIELD_DEFAULTS = {
|
|
7005
|
+
"short-text": { label: "Short text", placeholder: "Type placeholder text..." },
|
|
7006
|
+
"long-text": { label: "Long text", placeholder: "How can we help?" },
|
|
7007
|
+
email: { label: "Email", placeholder: "hello@example.com" },
|
|
7008
|
+
phone: { label: "Phone number", placeholder: "(555) 000-0000" }
|
|
7009
|
+
};
|
|
7010
|
+
var FIELD_TYPES = [
|
|
7011
|
+
{ type: "short-text", label: "Short text" },
|
|
7012
|
+
{ type: "long-text", label: "Long text" },
|
|
7013
|
+
{ type: "email", label: "Email" },
|
|
7014
|
+
{ type: "phone", label: "Phone" }
|
|
7015
|
+
];
|
|
7016
|
+
var FIELD_ATTR = "data-ohw-form-field";
|
|
7017
|
+
var FIELD_TYPE_ATTR = "data-ohw-field-type";
|
|
7018
|
+
function fieldsKey(formKey) {
|
|
7019
|
+
return `${formKey}-fields`;
|
|
7020
|
+
}
|
|
7021
|
+
function inputTagFor(type) {
|
|
7022
|
+
if (type === "long-text") return { tag: "textarea" };
|
|
7023
|
+
if (type === "email") return { tag: "input", inputType: "email" };
|
|
7024
|
+
if (type === "phone") return { tag: "input", inputType: "tel" };
|
|
7025
|
+
return { tag: "input", inputType: "text" };
|
|
7026
|
+
}
|
|
7027
|
+
function inferType(input) {
|
|
7028
|
+
if (input.tagName === "TEXTAREA") return "long-text";
|
|
7029
|
+
const type = input.type;
|
|
7030
|
+
if (type === "email") return "email";
|
|
7031
|
+
if (type === "tel") return "phone";
|
|
7032
|
+
return "short-text";
|
|
7033
|
+
}
|
|
7034
|
+
function ensureFieldLabel(wrapper, key) {
|
|
7035
|
+
const existing = fieldLabelOf(wrapper);
|
|
7036
|
+
if (existing) {
|
|
7037
|
+
if (!existing.hasAttribute("data-ohw-editable")) {
|
|
7038
|
+
existing.setAttribute("data-ohw-editable", "text");
|
|
7039
|
+
existing.setAttribute("data-ohw-key", `${key}-label`);
|
|
7040
|
+
}
|
|
7041
|
+
return existing;
|
|
7042
|
+
}
|
|
7043
|
+
const input = fieldInputOf(wrapper);
|
|
7044
|
+
const label = document.createElement("label");
|
|
7045
|
+
label.setAttribute("data-ohw-editable", "text");
|
|
7046
|
+
label.setAttribute("data-ohw-key", `${key}-label`);
|
|
7047
|
+
label.setAttribute("data-ohw-field-label", "");
|
|
7048
|
+
label.style.display = "block";
|
|
7049
|
+
label.style.marginBottom = "6px";
|
|
7050
|
+
label.style.fontSize = "13px";
|
|
7051
|
+
label.style.fontWeight = "500";
|
|
7052
|
+
label.style.lineHeight = "1.3";
|
|
7053
|
+
const fromPlaceholder = input?.getAttribute("placeholder")?.trim();
|
|
7054
|
+
const text = fromPlaceholder && fromPlaceholder.length < 40 ? fromPlaceholder : key.replace(/[-_]/g, " ");
|
|
7055
|
+
label.textContent = input?.hasAttribute("required") ? `${text} *` : text;
|
|
7056
|
+
if (input && input.parentElement === wrapper) wrapper.insertBefore(label, input);
|
|
7057
|
+
else wrapper.insertBefore(label, wrapper.firstChild);
|
|
7058
|
+
return label;
|
|
7059
|
+
}
|
|
7060
|
+
function listFieldWrappers(form) {
|
|
7061
|
+
return Array.from(form.querySelectorAll(`[${FIELD_ATTR}]`));
|
|
7062
|
+
}
|
|
7063
|
+
function getFieldWrapper(el) {
|
|
7064
|
+
return el?.closest(`[${FIELD_ATTR}]`) ?? null;
|
|
7065
|
+
}
|
|
7066
|
+
function fieldInputOf(wrapper) {
|
|
7067
|
+
return wrapper.querySelector("input, textarea");
|
|
7068
|
+
}
|
|
7069
|
+
function fieldLabelOf(wrapper) {
|
|
7070
|
+
return wrapper.querySelector("label");
|
|
7071
|
+
}
|
|
7072
|
+
function fieldKeyOf(wrapper) {
|
|
7073
|
+
return wrapper.getAttribute(FIELD_ATTR) ?? "";
|
|
7074
|
+
}
|
|
7075
|
+
function fieldTypeOf(wrapper) {
|
|
7076
|
+
return wrapper.getAttribute(FIELD_TYPE_ATTR) ?? "short-text";
|
|
7077
|
+
}
|
|
7078
|
+
function isFieldRequired(wrapper) {
|
|
7079
|
+
return fieldInputOf(wrapper)?.hasAttribute("required") ?? false;
|
|
7080
|
+
}
|
|
7081
|
+
function markFormFields(form) {
|
|
7082
|
+
form.querySelectorAll("input, textarea").forEach((input) => {
|
|
7083
|
+
const type = input.type;
|
|
7084
|
+
if (type === "submit" || type === "button" || type === "reset" || type === "hidden") return;
|
|
7085
|
+
if (getFieldWrapper(input)) return;
|
|
7086
|
+
let wrapper = input;
|
|
7087
|
+
while (wrapper.parentElement && wrapper.parentElement !== form && wrapper.parentElement.querySelectorAll("input, textarea").length === 1) {
|
|
7088
|
+
wrapper = wrapper.parentElement;
|
|
7089
|
+
}
|
|
7090
|
+
if (wrapper === input) {
|
|
7091
|
+
const box = document.createElement("div");
|
|
7092
|
+
box.setAttribute("data-ohw-field-box", "");
|
|
7093
|
+
input.replaceWith(box);
|
|
7094
|
+
box.appendChild(input);
|
|
7095
|
+
wrapper = box;
|
|
7096
|
+
}
|
|
7097
|
+
const key = input.getAttribute("name") ?? input.getAttribute("data-ohw-key") ?? `field-${Date.now()}`;
|
|
7098
|
+
wrapper.setAttribute(FIELD_ATTR, key);
|
|
7099
|
+
wrapper.setAttribute(FIELD_TYPE_ATTR, inferType(input));
|
|
7100
|
+
ensureFieldLabel(wrapper, key);
|
|
7101
|
+
syncRequiredMark(wrapper);
|
|
7102
|
+
});
|
|
7103
|
+
return listFieldWrappers(form);
|
|
7104
|
+
}
|
|
7105
|
+
function readFieldsFromDom(form) {
|
|
7106
|
+
return listFieldWrappers(form).map((wrapper) => {
|
|
7107
|
+
const input = fieldInputOf(wrapper);
|
|
7108
|
+
return {
|
|
7109
|
+
key: fieldKeyOf(wrapper),
|
|
7110
|
+
type: fieldTypeOf(wrapper),
|
|
7111
|
+
label: fieldLabelOf(wrapper)?.textContent?.trim() ?? "",
|
|
7112
|
+
placeholder: input?.getAttribute("placeholder") ?? "",
|
|
7113
|
+
required: Boolean(input?.hasAttribute("required"))
|
|
7114
|
+
};
|
|
7115
|
+
});
|
|
7116
|
+
}
|
|
7117
|
+
function parseFieldSpecs(raw) {
|
|
7118
|
+
if (!raw) return null;
|
|
7119
|
+
try {
|
|
7120
|
+
const parsed = JSON.parse(raw);
|
|
7121
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
7122
|
+
} catch {
|
|
7123
|
+
return null;
|
|
7124
|
+
}
|
|
7125
|
+
}
|
|
7126
|
+
function isDefaultText(value, pick) {
|
|
7127
|
+
const trimmed = value.trim().replace(/\s*\*$/, "");
|
|
7128
|
+
if (!trimmed) return true;
|
|
7129
|
+
return Object.values(FIELD_DEFAULTS).some((defaults) => pick(defaults) === trimmed);
|
|
7130
|
+
}
|
|
7131
|
+
function applyFieldType(wrapper, type) {
|
|
7132
|
+
const input = fieldInputOf(wrapper);
|
|
7133
|
+
if (!input) return;
|
|
7134
|
+
const defaults = FIELD_DEFAULTS[type];
|
|
7135
|
+
const placeholder = input.getAttribute("placeholder") ?? "";
|
|
7136
|
+
const label = fieldLabelOf(wrapper);
|
|
7137
|
+
const followsDefaults = {
|
|
7138
|
+
// A label the owner wrote stays; one that still reads as a type name (or as the old
|
|
7139
|
+
// placeholder the template shipped) follows the new type.
|
|
7140
|
+
label: isDefaultText(label?.textContent ?? "", (d) => d.label) || (label?.textContent ?? "").trim().replace(/\s*\*$/, "") === placeholder.trim()
|
|
7141
|
+
};
|
|
7142
|
+
const { tag, inputType } = inputTagFor(type);
|
|
7143
|
+
wrapper.setAttribute(FIELD_TYPE_ATTR, type);
|
|
7144
|
+
const shedSize = (el) => {
|
|
7145
|
+
if (type === "long-text") return;
|
|
7146
|
+
el.style.removeProperty("height");
|
|
7147
|
+
el.style.removeProperty("min-height");
|
|
7148
|
+
el.style.removeProperty("resize");
|
|
7149
|
+
el.removeAttribute("rows");
|
|
7150
|
+
};
|
|
7151
|
+
const applyDefaults = (el) => {
|
|
7152
|
+
el.setAttribute("placeholder", defaults.placeholder);
|
|
7153
|
+
if (label && followsDefaults.label) {
|
|
7154
|
+
const required = (label.textContent ?? "").trim().endsWith("*");
|
|
7155
|
+
label.textContent = required ? `${defaults.label} *` : defaults.label;
|
|
7156
|
+
}
|
|
7157
|
+
};
|
|
7158
|
+
if (input.tagName.toLowerCase() === tag) {
|
|
7159
|
+
if (inputType) input.type = inputType;
|
|
7160
|
+
shedSize(input);
|
|
7161
|
+
applyDefaults(input);
|
|
7162
|
+
return;
|
|
7163
|
+
}
|
|
7164
|
+
const next = document.createElement(tag);
|
|
7165
|
+
Array.from(input.attributes).forEach((attr) => {
|
|
7166
|
+
if (attr.name === "type") return;
|
|
7167
|
+
next.setAttribute(attr.name, attr.value);
|
|
7168
|
+
});
|
|
7169
|
+
if (inputType) next.setAttribute("type", inputType);
|
|
7170
|
+
shedSize(next);
|
|
7171
|
+
if (type === "long-text") next.setAttribute("rows", "4");
|
|
7172
|
+
input.replaceWith(next);
|
|
7173
|
+
applyDefaults(next);
|
|
7174
|
+
}
|
|
7175
|
+
function syncRequiredMark(wrapper) {
|
|
7176
|
+
const label = fieldLabelOf(wrapper);
|
|
7177
|
+
if (!label) return;
|
|
7178
|
+
const required = isFieldRequired(wrapper);
|
|
7179
|
+
const base = (label.textContent ?? "").replace(/\s*\*\s*$/, "").trimEnd();
|
|
7180
|
+
const next = required ? `${base} *` : base;
|
|
7181
|
+
if (label.textContent !== next) label.textContent = next;
|
|
7182
|
+
}
|
|
7183
|
+
function setFieldRequired(wrapper, required) {
|
|
7184
|
+
const input = fieldInputOf(wrapper);
|
|
7185
|
+
const label = fieldLabelOf(wrapper);
|
|
7186
|
+
if (!input) return;
|
|
7187
|
+
if (required) input.setAttribute("required", "");
|
|
7188
|
+
else input.removeAttribute("required");
|
|
7189
|
+
if (label) syncRequiredMark(wrapper);
|
|
7190
|
+
}
|
|
7191
|
+
var PLACEHOLDER_EDIT_ATTR = "data-ohw-placeholder-edit";
|
|
7192
|
+
function beginPlaceholderEdit(wrapper) {
|
|
7193
|
+
const input = fieldInputOf(wrapper);
|
|
7194
|
+
if (!input || input.hasAttribute(PLACEHOLDER_EDIT_ATTR)) return;
|
|
7195
|
+
input.setAttribute(PLACEHOLDER_EDIT_ATTR, "");
|
|
7196
|
+
input.value = input.getAttribute("placeholder") ?? "";
|
|
7197
|
+
input.setAttribute("placeholder", "");
|
|
7198
|
+
}
|
|
7199
|
+
function commitPlaceholderEdit(wrapper) {
|
|
7200
|
+
if (!wrapper) return false;
|
|
7201
|
+
const input = fieldInputOf(wrapper);
|
|
7202
|
+
if (!input || !input.hasAttribute(PLACEHOLDER_EDIT_ATTR)) return false;
|
|
7203
|
+
const typed = input.value;
|
|
7204
|
+
input.removeAttribute(PLACEHOLDER_EDIT_ATTR);
|
|
7205
|
+
input.value = "";
|
|
7206
|
+
const previous = input.getAttribute("placeholder") ?? "";
|
|
7207
|
+
input.setAttribute("placeholder", typed);
|
|
7208
|
+
return previous !== typed;
|
|
7209
|
+
}
|
|
7210
|
+
function setFieldPlaceholder(wrapper, placeholder) {
|
|
7211
|
+
fieldInputOf(wrapper)?.setAttribute("placeholder", placeholder);
|
|
7212
|
+
}
|
|
7213
|
+
function uniqueKey(form, base) {
|
|
7214
|
+
const taken = new Set(listFieldWrappers(form).map(fieldKeyOf));
|
|
7215
|
+
if (!taken.has(base)) return base;
|
|
7216
|
+
let n = 2;
|
|
7217
|
+
while (taken.has(`${base}-${n}`)) n += 1;
|
|
7218
|
+
return `${base}-${n}`;
|
|
7219
|
+
}
|
|
7220
|
+
function insertField(form, type) {
|
|
7221
|
+
const existing = listFieldWrappers(form);
|
|
7222
|
+
const source = existing[existing.length - 1] ?? null;
|
|
7223
|
+
const key = uniqueKey(form, type);
|
|
7224
|
+
let wrapper;
|
|
7225
|
+
if (source) {
|
|
7226
|
+
wrapper = source.cloneNode(true);
|
|
7227
|
+
source.after(wrapper);
|
|
7228
|
+
} else {
|
|
7229
|
+
wrapper = document.createElement("div");
|
|
7230
|
+
const label2 = document.createElement("label");
|
|
7231
|
+
const input2 = document.createElement("input");
|
|
7232
|
+
wrapper.append(label2, input2);
|
|
7233
|
+
const submit = form.querySelector('button, input[type="submit"]');
|
|
7234
|
+
if (submit) submit.before(wrapper);
|
|
7235
|
+
else form.appendChild(wrapper);
|
|
7236
|
+
}
|
|
7237
|
+
wrapper.setAttribute(FIELD_ATTR, key);
|
|
7238
|
+
wrapper.setAttribute(FIELD_TYPE_ATTR, type);
|
|
7239
|
+
applyFieldType(wrapper, type);
|
|
7240
|
+
const defaults = FIELD_DEFAULTS[type];
|
|
7241
|
+
const input = fieldInputOf(wrapper);
|
|
7242
|
+
if (input) {
|
|
7243
|
+
input.setAttribute("name", key);
|
|
7244
|
+
input.setAttribute("data-ohw-key", key);
|
|
7245
|
+
input.removeAttribute("required");
|
|
7246
|
+
input.setAttribute("placeholder", defaults.placeholder);
|
|
7247
|
+
input.value = "";
|
|
7248
|
+
}
|
|
7249
|
+
const label = ensureFieldLabel(wrapper, key);
|
|
7250
|
+
label.textContent = defaults.label;
|
|
7251
|
+
label.setAttribute("data-ohw-key", `${key}-label`);
|
|
7252
|
+
return wrapper;
|
|
7253
|
+
}
|
|
7254
|
+
function duplicateField(form, wrapper) {
|
|
7255
|
+
const copy = wrapper.cloneNode(true);
|
|
7256
|
+
const key = uniqueKey(form, `${fieldKeyOf(wrapper)}-copy`);
|
|
7257
|
+
copy.setAttribute(FIELD_ATTR, key);
|
|
7258
|
+
const input = fieldInputOf(copy);
|
|
7259
|
+
if (input) {
|
|
7260
|
+
input.setAttribute("name", key);
|
|
7261
|
+
input.setAttribute("data-ohw-key", key);
|
|
7262
|
+
input.value = "";
|
|
7263
|
+
}
|
|
7264
|
+
wrapper.after(copy);
|
|
7265
|
+
return copy;
|
|
7266
|
+
}
|
|
7267
|
+
function removeField(wrapper) {
|
|
7268
|
+
wrapper.remove();
|
|
7269
|
+
}
|
|
7270
|
+
function moveField(form, key, toIndex) {
|
|
7271
|
+
const wrappers = listFieldWrappers(form);
|
|
7272
|
+
const moving = wrappers.find((wrapper) => fieldKeyOf(wrapper) === key);
|
|
7273
|
+
if (!moving) return;
|
|
7274
|
+
const rest = wrappers.filter((wrapper) => wrapper !== moving);
|
|
7275
|
+
const target = rest[Math.max(0, Math.min(rest.length, toIndex))];
|
|
7276
|
+
if (target) target.before(moving);
|
|
7277
|
+
else rest[rest.length - 1]?.after(moving);
|
|
7278
|
+
}
|
|
7279
|
+
function reconcileFieldsFromContent(form, content) {
|
|
7280
|
+
const formKey = form.getAttribute("data-ohw-key");
|
|
7281
|
+
if (!formKey) return;
|
|
7282
|
+
markFormFields(form);
|
|
7283
|
+
const stored = parseFieldSpecs(content[fieldsKey(formKey)]);
|
|
7284
|
+
if (!stored) return;
|
|
7285
|
+
const byKey = new Map(listFieldWrappers(form).map((wrapper) => [fieldKeyOf(wrapper), wrapper]));
|
|
7286
|
+
stored.forEach((spec) => {
|
|
7287
|
+
let wrapper = byKey.get(spec.key) ?? null;
|
|
7288
|
+
if (!wrapper) {
|
|
7289
|
+
wrapper = insertField(form, spec.type);
|
|
7290
|
+
if (!wrapper) return;
|
|
7291
|
+
wrapper.setAttribute(FIELD_ATTR, spec.key);
|
|
7292
|
+
const input = fieldInputOf(wrapper);
|
|
7293
|
+
if (input) {
|
|
7294
|
+
input.setAttribute("name", spec.key);
|
|
7295
|
+
input.setAttribute("data-ohw-key", spec.key);
|
|
7296
|
+
}
|
|
7297
|
+
byKey.set(spec.key, wrapper);
|
|
7298
|
+
}
|
|
7299
|
+
applyFieldType(wrapper, spec.type);
|
|
7300
|
+
setFieldRequired(wrapper, spec.required);
|
|
7301
|
+
setFieldPlaceholder(wrapper, spec.placeholder);
|
|
7302
|
+
const label = fieldLabelOf(wrapper);
|
|
7303
|
+
if (label && spec.label) label.textContent = spec.label;
|
|
7304
|
+
});
|
|
7305
|
+
const wanted = new Set(stored.map((spec) => spec.key));
|
|
7306
|
+
listFieldWrappers(form).forEach((wrapper) => {
|
|
7307
|
+
if (!wanted.has(fieldKeyOf(wrapper))) wrapper.remove();
|
|
7308
|
+
});
|
|
7309
|
+
stored.forEach((spec, index) => moveField(form, spec.key, index));
|
|
7310
|
+
}
|
|
7311
|
+
|
|
7312
|
+
// src/ui/form-field-toolbar.tsx
|
|
7313
|
+
var import_lucide_react4 = require("lucide-react");
|
|
7314
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
7315
|
+
var TYPE_ICONS = {
|
|
7316
|
+
"short-text": import_lucide_react4.Type,
|
|
7317
|
+
"long-text": import_lucide_react4.TextQuote,
|
|
7318
|
+
email: import_lucide_react4.AtSign,
|
|
7319
|
+
phone: import_lucide_react4.Phone
|
|
7320
|
+
};
|
|
7321
|
+
function FormFieldToolbar({
|
|
7322
|
+
type,
|
|
7323
|
+
required,
|
|
7324
|
+
onTypeChange,
|
|
7325
|
+
onRequiredToggle,
|
|
7326
|
+
onDuplicate,
|
|
7327
|
+
onDelete
|
|
7328
|
+
}) {
|
|
7329
|
+
const TypeIcon = TYPE_ICONS[type];
|
|
7330
|
+
const typeLabel = FIELD_TYPES.find((entry) => entry.type === type)?.label ?? "Short text";
|
|
7331
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7332
|
+
"div",
|
|
7333
|
+
{
|
|
7334
|
+
"data-ohw-field-toolbar": "",
|
|
7335
|
+
className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
|
|
7336
|
+
children: [
|
|
7337
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenu, { children: [
|
|
7338
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7339
|
+
"button",
|
|
7340
|
+
{
|
|
7341
|
+
type: "button",
|
|
7342
|
+
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",
|
|
7343
|
+
"data-ohw-field-type-trigger": "",
|
|
7344
|
+
children: [
|
|
7345
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TypeIcon, { size: 14, strokeWidth: 1.75, "aria-hidden": true }),
|
|
7346
|
+
typeLabel,
|
|
7347
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.ChevronDown, { size: 13, className: "text-muted-foreground", "aria-hidden": true })
|
|
7348
|
+
]
|
|
7349
|
+
}
|
|
7350
|
+
) }),
|
|
7351
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
|
|
7352
|
+
const Icon = TYPE_ICONS[entry.type];
|
|
7353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7354
|
+
DropdownMenuItem,
|
|
7355
|
+
{
|
|
7356
|
+
onSelect: () => onTypeChange(entry.type),
|
|
7357
|
+
className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
|
|
7358
|
+
children: [
|
|
7359
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7360
|
+
entry.label
|
|
7361
|
+
]
|
|
7362
|
+
},
|
|
7363
|
+
entry.type
|
|
7364
|
+
);
|
|
7365
|
+
}) })
|
|
7366
|
+
] }),
|
|
7367
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
7368
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7369
|
+
"button",
|
|
7370
|
+
{
|
|
7371
|
+
type: "button",
|
|
7372
|
+
"aria-pressed": required,
|
|
7373
|
+
onClick: onRequiredToggle,
|
|
7374
|
+
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"),
|
|
7375
|
+
"data-ohw-field-required": "",
|
|
7376
|
+
children: [
|
|
7377
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
|
|
7378
|
+
"Required"
|
|
7379
|
+
]
|
|
7380
|
+
}
|
|
7381
|
+
),
|
|
7382
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
7383
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenu, { children: [
|
|
7384
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7385
|
+
"button",
|
|
7386
|
+
{
|
|
7387
|
+
type: "button",
|
|
7388
|
+
title: "More",
|
|
7389
|
+
"aria-label": "More",
|
|
7390
|
+
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/70",
|
|
7391
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
|
|
7392
|
+
}
|
|
7393
|
+
) }),
|
|
7394
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
|
|
7395
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
|
|
7396
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7397
|
+
"Duplicate"
|
|
7398
|
+
] }),
|
|
7399
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { variant: "destructive", onSelect: onDelete, className: "rounded-md py-2 text-[13px]", children: [
|
|
7400
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Trash2, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
|
|
7401
|
+
"Delete"
|
|
7402
|
+
] })
|
|
7403
|
+
] })
|
|
7404
|
+
] })
|
|
7405
|
+
]
|
|
7406
|
+
}
|
|
7407
|
+
);
|
|
7408
|
+
}
|
|
7409
|
+
function FieldTypePicker({ onPick }) {
|
|
7410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7411
|
+
"div",
|
|
7412
|
+
{
|
|
7413
|
+
"data-ohw-field-type-picker": "",
|
|
7414
|
+
className: "pointer-events-auto grid w-[420px] grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
|
|
7415
|
+
children: FIELD_TYPES.map((entry) => {
|
|
7416
|
+
const Icon = TYPE_ICONS[entry.type];
|
|
7417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
7418
|
+
"button",
|
|
7419
|
+
{
|
|
7420
|
+
type: "button",
|
|
7421
|
+
onClick: () => onPick(entry.type),
|
|
7422
|
+
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",
|
|
7423
|
+
children: [
|
|
7424
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
|
|
7425
|
+
entry.label
|
|
7426
|
+
]
|
|
7427
|
+
},
|
|
7428
|
+
entry.type
|
|
7429
|
+
);
|
|
7430
|
+
})
|
|
7431
|
+
}
|
|
7432
|
+
);
|
|
7433
|
+
}
|
|
7434
|
+
|
|
6807
7435
|
// src/ui/MediaOverlay.tsx
|
|
6808
7436
|
var React7 = __toESM(require("react"), 1);
|
|
6809
|
-
var
|
|
7437
|
+
var import_lucide_react5 = require("lucide-react");
|
|
6810
7438
|
|
|
6811
7439
|
// src/ui/button.tsx
|
|
6812
7440
|
var React6 = __toESM(require("react"), 1);
|
|
6813
7441
|
var import_radix_ui5 = require("radix-ui");
|
|
6814
|
-
var
|
|
7442
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
6815
7443
|
var buttonVariants = cva(
|
|
6816
7444
|
"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",
|
|
6817
7445
|
{
|
|
@@ -6835,7 +7463,7 @@ var buttonVariants = cva(
|
|
|
6835
7463
|
var Button = React6.forwardRef(
|
|
6836
7464
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
6837
7465
|
const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
|
|
6838
|
-
return /* @__PURE__ */ (0,
|
|
7466
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
6839
7467
|
Comp,
|
|
6840
7468
|
{
|
|
6841
7469
|
ref,
|
|
@@ -6849,7 +7477,7 @@ var Button = React6.forwardRef(
|
|
|
6849
7477
|
Button.displayName = "Button";
|
|
6850
7478
|
|
|
6851
7479
|
// src/ui/MediaOverlay.tsx
|
|
6852
|
-
var
|
|
7480
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
6853
7481
|
var MEDIA_UPLOAD_FADE_MS = 300;
|
|
6854
7482
|
var VIDEO_SETTINGS_BAR_INSET = 8;
|
|
6855
7483
|
var OVERLAY_BUTTON_STYLE = {
|
|
@@ -6907,7 +7535,7 @@ function MediaOverlay({
|
|
|
6907
7535
|
return () => anim.cancel();
|
|
6908
7536
|
}, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
|
|
6909
7537
|
if (isUploading) {
|
|
6910
|
-
return /* @__PURE__ */ (0,
|
|
7538
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6911
7539
|
"div",
|
|
6912
7540
|
{
|
|
6913
7541
|
ref: skeletonRef,
|
|
@@ -6916,11 +7544,11 @@ function MediaOverlay({
|
|
|
6916
7544
|
"data-ohw-media-skeleton": "",
|
|
6917
7545
|
"aria-hidden": true,
|
|
6918
7546
|
style: { ...box, pointerEvents: "none" },
|
|
6919
|
-
children: /* @__PURE__ */ (0,
|
|
7547
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("style", { children: SKELETON_CSS })
|
|
6920
7548
|
}
|
|
6921
7549
|
);
|
|
6922
7550
|
}
|
|
6923
|
-
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0,
|
|
7551
|
+
const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
6924
7552
|
"div",
|
|
6925
7553
|
{
|
|
6926
7554
|
"data-ohw-bridge": "",
|
|
@@ -6936,7 +7564,7 @@ function MediaOverlay({
|
|
|
6936
7564
|
},
|
|
6937
7565
|
onClick: (e) => e.stopPropagation(),
|
|
6938
7566
|
children: [
|
|
6939
|
-
/* @__PURE__ */ (0,
|
|
7567
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6940
7568
|
Button,
|
|
6941
7569
|
{
|
|
6942
7570
|
"data-ohw-media-overlay": "",
|
|
@@ -6951,10 +7579,10 @@ function MediaOverlay({
|
|
|
6951
7579
|
e.stopPropagation();
|
|
6952
7580
|
onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
|
|
6953
7581
|
},
|
|
6954
|
-
children: autoplay ? /* @__PURE__ */ (0,
|
|
7582
|
+
children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Play, { size: 14 })
|
|
6955
7583
|
}
|
|
6956
7584
|
),
|
|
6957
|
-
/* @__PURE__ */ (0,
|
|
7585
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6958
7586
|
Button,
|
|
6959
7587
|
{
|
|
6960
7588
|
"data-ohw-media-overlay": "",
|
|
@@ -6969,15 +7597,15 @@ function MediaOverlay({
|
|
|
6969
7597
|
e.stopPropagation();
|
|
6970
7598
|
onVideoSettingsChange?.(hover.key, { muted: !muted });
|
|
6971
7599
|
},
|
|
6972
|
-
children: muted ? /* @__PURE__ */ (0,
|
|
7600
|
+
children: muted ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Volume2, { size: 14 })
|
|
6973
7601
|
}
|
|
6974
7602
|
)
|
|
6975
7603
|
]
|
|
6976
7604
|
}
|
|
6977
7605
|
) : null;
|
|
6978
|
-
return /* @__PURE__ */ (0,
|
|
7606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
6979
7607
|
settingsBar,
|
|
6980
|
-
/* @__PURE__ */ (0,
|
|
7608
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
6981
7609
|
"div",
|
|
6982
7610
|
{
|
|
6983
7611
|
"data-ohw-bridge": "",
|
|
@@ -6994,7 +7622,7 @@ function MediaOverlay({
|
|
|
6994
7622
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
6995
7623
|
},
|
|
6996
7624
|
onClick: () => onReplace(hover.key),
|
|
6997
|
-
children: /* @__PURE__ */ (0,
|
|
7625
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
6998
7626
|
Button,
|
|
6999
7627
|
{
|
|
7000
7628
|
"data-ohw-media-overlay": "",
|
|
@@ -7012,7 +7640,7 @@ function MediaOverlay({
|
|
|
7012
7640
|
onReplace(hover.key);
|
|
7013
7641
|
},
|
|
7014
7642
|
children: [
|
|
7015
|
-
isVideo ? /* @__PURE__ */ (0,
|
|
7643
|
+
isVideo ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.ImageIcon, { size: 14 }),
|
|
7016
7644
|
isVideo ? "Replace video" : "Replace image"
|
|
7017
7645
|
]
|
|
7018
7646
|
}
|
|
@@ -7023,8 +7651,8 @@ function MediaOverlay({
|
|
|
7023
7651
|
}
|
|
7024
7652
|
|
|
7025
7653
|
// src/ui/CarouselOverlay.tsx
|
|
7026
|
-
var
|
|
7027
|
-
var
|
|
7654
|
+
var import_lucide_react6 = require("lucide-react");
|
|
7655
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
7028
7656
|
var OVERLAY_BUTTON_STYLE2 = {
|
|
7029
7657
|
pointerEvents: "auto",
|
|
7030
7658
|
fontFamily: "Inter, sans-serif",
|
|
@@ -7036,7 +7664,7 @@ function CarouselOverlay({
|
|
|
7036
7664
|
onEdit
|
|
7037
7665
|
}) {
|
|
7038
7666
|
const { rect } = hover;
|
|
7039
|
-
return /* @__PURE__ */ (0,
|
|
7667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
7040
7668
|
"div",
|
|
7041
7669
|
{
|
|
7042
7670
|
"data-ohw-bridge": "",
|
|
@@ -7054,7 +7682,7 @@ function CarouselOverlay({
|
|
|
7054
7682
|
background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
|
|
7055
7683
|
},
|
|
7056
7684
|
onClick: () => onEdit(hover.key),
|
|
7057
|
-
children: /* @__PURE__ */ (0,
|
|
7685
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
7058
7686
|
Button,
|
|
7059
7687
|
{
|
|
7060
7688
|
"data-ohw-carousel-overlay": "",
|
|
@@ -7068,7 +7696,7 @@ function CarouselOverlay({
|
|
|
7068
7696
|
onEdit(hover.key);
|
|
7069
7697
|
},
|
|
7070
7698
|
children: [
|
|
7071
|
-
/* @__PURE__ */ (0,
|
|
7699
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
|
|
7072
7700
|
"Edit gallery"
|
|
7073
7701
|
]
|
|
7074
7702
|
}
|
|
@@ -7079,7 +7707,7 @@ function CarouselOverlay({
|
|
|
7079
7707
|
|
|
7080
7708
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
7081
7709
|
var import_react8 = require("react");
|
|
7082
|
-
var
|
|
7710
|
+
var import_lucide_react7 = require("lucide-react");
|
|
7083
7711
|
|
|
7084
7712
|
// src/lib/sections.ts
|
|
7085
7713
|
var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
|
|
@@ -7093,6 +7721,8 @@ function parseSectionsFromRoot(root) {
|
|
|
7093
7721
|
const id = el.getAttribute("data-ohw-section") ?? "";
|
|
7094
7722
|
if (!id || seen.has(id) || LINK_PICKER_EXCLUDED_IDS.has(id)) continue;
|
|
7095
7723
|
if (el.parentElement?.closest("[data-ohw-section]")) continue;
|
|
7724
|
+
if (el.hasAttribute("data-ohw-ai-template-hidden") || el.hasAttribute("data-ohw-ai-removed") || el.hasAttribute("data-ohw-ai-replaced-by"))
|
|
7725
|
+
continue;
|
|
7096
7726
|
seen.add(id);
|
|
7097
7727
|
const label = el.getAttribute("data-ohw-section-label") ?? titleCaseSectionId(id);
|
|
7098
7728
|
sections.push({ id, label });
|
|
@@ -7109,7 +7739,7 @@ function parseSectionsFromHtml(html) {
|
|
|
7109
7739
|
}
|
|
7110
7740
|
|
|
7111
7741
|
// src/ui/ai-section/AiSectionOverlay.tsx
|
|
7112
|
-
var
|
|
7742
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
7113
7743
|
function findSectionElement(instanceId) {
|
|
7114
7744
|
const escaped = CSS.escape(instanceId);
|
|
7115
7745
|
return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
|
|
@@ -7177,8 +7807,8 @@ function ReviewButton({
|
|
|
7177
7807
|
color
|
|
7178
7808
|
}) {
|
|
7179
7809
|
const [hover, setHover] = (0, import_react8.useState)(false);
|
|
7180
|
-
return /* @__PURE__ */ (0,
|
|
7181
|
-
/* @__PURE__ */ (0,
|
|
7810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { position: "relative" }, children: [
|
|
7811
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
7182
7812
|
"button",
|
|
7183
7813
|
{
|
|
7184
7814
|
type: "button",
|
|
@@ -7202,7 +7832,7 @@ function ReviewButton({
|
|
|
7202
7832
|
children
|
|
7203
7833
|
}
|
|
7204
7834
|
),
|
|
7205
|
-
hover && /* @__PURE__ */ (0,
|
|
7835
|
+
hover && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
7206
7836
|
"div",
|
|
7207
7837
|
{
|
|
7208
7838
|
style: {
|
|
@@ -7368,8 +7998,8 @@ function AiSectionOverlay({
|
|
|
7368
7998
|
isLast
|
|
7369
7999
|
});
|
|
7370
8000
|
}, [activeSelectionId, selectionRect, postToParent2]);
|
|
7371
|
-
return /* @__PURE__ */ (0,
|
|
7372
|
-
hoverRect && /* @__PURE__ */ (0,
|
|
8001
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
8002
|
+
hoverRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
7373
8003
|
"div",
|
|
7374
8004
|
{
|
|
7375
8005
|
"data-ohw-ai-section-hover": "",
|
|
@@ -7387,7 +8017,7 @@ function AiSectionOverlay({
|
|
|
7387
8017
|
}
|
|
7388
8018
|
}
|
|
7389
8019
|
),
|
|
7390
|
-
selectionRect && /* @__PURE__ */ (0,
|
|
8020
|
+
selectionRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
7391
8021
|
"div",
|
|
7392
8022
|
{
|
|
7393
8023
|
"data-ohw-ai-section-selected": "",
|
|
@@ -7405,7 +8035,7 @@ function AiSectionOverlay({
|
|
|
7405
8035
|
}
|
|
7406
8036
|
}
|
|
7407
8037
|
),
|
|
7408
|
-
reviewRect && /* @__PURE__ */ (0,
|
|
8038
|
+
reviewRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
7409
8039
|
"div",
|
|
7410
8040
|
{
|
|
7411
8041
|
"data-ohw-ai-review": "",
|
|
@@ -7427,7 +8057,7 @@ function AiSectionOverlay({
|
|
|
7427
8057
|
cursor: "default"
|
|
7428
8058
|
},
|
|
7429
8059
|
onClick: (e) => e.stopPropagation(),
|
|
7430
|
-
children: !reviewButtonsHidden && /* @__PURE__ */ (0,
|
|
8060
|
+
children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
7431
8061
|
"div",
|
|
7432
8062
|
{
|
|
7433
8063
|
style: {
|
|
@@ -7440,8 +8070,8 @@ function AiSectionOverlay({
|
|
|
7440
8070
|
paddingTop: 12
|
|
7441
8071
|
},
|
|
7442
8072
|
children: [
|
|
7443
|
-
/* @__PURE__ */ (0,
|
|
7444
|
-
/* @__PURE__ */ (0,
|
|
8073
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
|
|
8074
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
|
|
7445
8075
|
]
|
|
7446
8076
|
}
|
|
7447
8077
|
)
|
|
@@ -7800,23 +8430,23 @@ var import_react12 = require("react");
|
|
|
7800
8430
|
// src/ui/dialog.tsx
|
|
7801
8431
|
var React8 = __toESM(require("react"), 1);
|
|
7802
8432
|
var import_radix_ui6 = require("radix-ui");
|
|
7803
|
-
var
|
|
7804
|
-
var
|
|
8433
|
+
var import_lucide_react8 = require("lucide-react");
|
|
8434
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
7805
8435
|
function Dialog2({
|
|
7806
8436
|
...props
|
|
7807
8437
|
}) {
|
|
7808
|
-
return /* @__PURE__ */ (0,
|
|
8438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
7809
8439
|
}
|
|
7810
8440
|
function DialogPortal({
|
|
7811
8441
|
...props
|
|
7812
8442
|
}) {
|
|
7813
|
-
return /* @__PURE__ */ (0,
|
|
8443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
|
|
7814
8444
|
}
|
|
7815
8445
|
function DialogOverlay({
|
|
7816
8446
|
className,
|
|
7817
8447
|
...props
|
|
7818
8448
|
}) {
|
|
7819
|
-
return /* @__PURE__ */ (0,
|
|
8449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7820
8450
|
import_radix_ui6.Dialog.Overlay,
|
|
7821
8451
|
{
|
|
7822
8452
|
"data-slot": "dialog-overlay",
|
|
@@ -7829,9 +8459,9 @@ function DialogOverlay({
|
|
|
7829
8459
|
var DialogContent = React8.forwardRef(
|
|
7830
8460
|
({ className, children, showCloseButton = true, container, ...props }, ref) => {
|
|
7831
8461
|
const positionMode = container ? "absolute" : "fixed";
|
|
7832
|
-
return /* @__PURE__ */ (0,
|
|
7833
|
-
/* @__PURE__ */ (0,
|
|
7834
|
-
/* @__PURE__ */ (0,
|
|
8462
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogPortal, { container: container ?? void 0, children: [
|
|
8463
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
|
|
8464
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
7835
8465
|
import_radix_ui6.Dialog.Content,
|
|
7836
8466
|
{
|
|
7837
8467
|
ref,
|
|
@@ -7847,13 +8477,13 @@ var DialogContent = React8.forwardRef(
|
|
|
7847
8477
|
...props,
|
|
7848
8478
|
children: [
|
|
7849
8479
|
children,
|
|
7850
|
-
showCloseButton ? /* @__PURE__ */ (0,
|
|
8480
|
+
showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7851
8481
|
import_radix_ui6.Dialog.Close,
|
|
7852
8482
|
{
|
|
7853
8483
|
type: "button",
|
|
7854
8484
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
|
|
7855
8485
|
"aria-label": "Close",
|
|
7856
|
-
children: /* @__PURE__ */ (0,
|
|
8486
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
|
|
7857
8487
|
}
|
|
7858
8488
|
) : null
|
|
7859
8489
|
]
|
|
@@ -7867,13 +8497,13 @@ function DialogHeader({
|
|
|
7867
8497
|
className,
|
|
7868
8498
|
...props
|
|
7869
8499
|
}) {
|
|
7870
|
-
return /* @__PURE__ */ (0,
|
|
8500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
|
|
7871
8501
|
}
|
|
7872
8502
|
function DialogFooter({
|
|
7873
8503
|
className,
|
|
7874
8504
|
...props
|
|
7875
8505
|
}) {
|
|
7876
|
-
return /* @__PURE__ */ (0,
|
|
8506
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7877
8507
|
"div",
|
|
7878
8508
|
{
|
|
7879
8509
|
className: cn("flex items-center justify-end gap-2", className),
|
|
@@ -7881,7 +8511,7 @@ function DialogFooter({
|
|
|
7881
8511
|
}
|
|
7882
8512
|
);
|
|
7883
8513
|
}
|
|
7884
|
-
var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0,
|
|
8514
|
+
var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7885
8515
|
import_radix_ui6.Dialog.Title,
|
|
7886
8516
|
{
|
|
7887
8517
|
ref,
|
|
@@ -7893,7 +8523,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
7893
8523
|
}
|
|
7894
8524
|
));
|
|
7895
8525
|
DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
|
|
7896
|
-
var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0,
|
|
8526
|
+
var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
7897
8527
|
import_radix_ui6.Dialog.Description,
|
|
7898
8528
|
{
|
|
7899
8529
|
ref,
|
|
@@ -7905,63 +8535,63 @@ DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
|
|
|
7905
8535
|
var DialogClose = import_radix_ui6.Dialog.Close;
|
|
7906
8536
|
|
|
7907
8537
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
7908
|
-
var
|
|
8538
|
+
var import_lucide_react12 = require("lucide-react");
|
|
7909
8539
|
|
|
7910
8540
|
// src/ui/link-modal/DestinationBreadcrumb.tsx
|
|
7911
|
-
var
|
|
7912
|
-
var
|
|
8541
|
+
var import_lucide_react9 = require("lucide-react");
|
|
8542
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
7913
8543
|
function DestinationBreadcrumb({
|
|
7914
8544
|
pageTitle,
|
|
7915
8545
|
sectionLabel
|
|
7916
8546
|
}) {
|
|
7917
|
-
return /* @__PURE__ */ (0,
|
|
7918
|
-
/* @__PURE__ */ (0,
|
|
7919
|
-
/* @__PURE__ */ (0,
|
|
7920
|
-
/* @__PURE__ */ (0,
|
|
7921
|
-
/* @__PURE__ */ (0,
|
|
7922
|
-
/* @__PURE__ */ (0,
|
|
8547
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
|
|
8548
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
|
|
8549
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
8550
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
8551
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
|
|
8552
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
|
|
7923
8553
|
] }),
|
|
7924
|
-
/* @__PURE__ */ (0,
|
|
7925
|
-
|
|
8554
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
8555
|
+
import_lucide_react9.ArrowRight,
|
|
7926
8556
|
{
|
|
7927
8557
|
size: 16,
|
|
7928
8558
|
className: "shrink-0 text-muted-foreground",
|
|
7929
8559
|
"aria-hidden": true
|
|
7930
8560
|
}
|
|
7931
8561
|
),
|
|
7932
|
-
/* @__PURE__ */ (0,
|
|
7933
|
-
/* @__PURE__ */ (0,
|
|
7934
|
-
|
|
8562
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
8563
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
8564
|
+
import_lucide_react9.GalleryVertical,
|
|
7935
8565
|
{
|
|
7936
8566
|
size: 16,
|
|
7937
8567
|
className: "shrink-0 text-foreground",
|
|
7938
8568
|
"aria-hidden": true
|
|
7939
8569
|
}
|
|
7940
8570
|
),
|
|
7941
|
-
/* @__PURE__ */ (0,
|
|
8571
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
|
|
7942
8572
|
] })
|
|
7943
8573
|
] })
|
|
7944
8574
|
] });
|
|
7945
8575
|
}
|
|
7946
8576
|
|
|
7947
8577
|
// src/ui/link-modal/SectionTreeItem.tsx
|
|
7948
|
-
var
|
|
7949
|
-
var
|
|
8578
|
+
var import_lucide_react10 = require("lucide-react");
|
|
8579
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
7950
8580
|
function SectionTreeItem({
|
|
7951
8581
|
section,
|
|
7952
8582
|
onSelect,
|
|
7953
8583
|
selected
|
|
7954
8584
|
}) {
|
|
7955
8585
|
const interactive = Boolean(onSelect);
|
|
7956
|
-
return /* @__PURE__ */ (0,
|
|
7957
|
-
/* @__PURE__ */ (0,
|
|
8586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
|
|
8587
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
7958
8588
|
"div",
|
|
7959
8589
|
{
|
|
7960
8590
|
className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
|
|
7961
8591
|
"aria-hidden": true
|
|
7962
8592
|
}
|
|
7963
8593
|
),
|
|
7964
|
-
/* @__PURE__ */ (0,
|
|
8594
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
7965
8595
|
"div",
|
|
7966
8596
|
{
|
|
7967
8597
|
role: interactive ? "button" : void 0,
|
|
@@ -7979,15 +8609,15 @@ function SectionTreeItem({
|
|
|
7979
8609
|
interactive && selected && "border-primary"
|
|
7980
8610
|
),
|
|
7981
8611
|
children: [
|
|
7982
|
-
/* @__PURE__ */ (0,
|
|
7983
|
-
|
|
8612
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
8613
|
+
import_lucide_react10.GalleryVertical,
|
|
7984
8614
|
{
|
|
7985
8615
|
size: 16,
|
|
7986
8616
|
className: "shrink-0 text-foreground",
|
|
7987
8617
|
"aria-hidden": true
|
|
7988
8618
|
}
|
|
7989
8619
|
),
|
|
7990
|
-
/* @__PURE__ */ (0,
|
|
8620
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
|
|
7991
8621
|
]
|
|
7992
8622
|
}
|
|
7993
8623
|
)
|
|
@@ -7999,10 +8629,10 @@ var import_react9 = require("react");
|
|
|
7999
8629
|
|
|
8000
8630
|
// src/ui/input.tsx
|
|
8001
8631
|
var React9 = __toESM(require("react"), 1);
|
|
8002
|
-
var
|
|
8632
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
8003
8633
|
var Input = React9.forwardRef(
|
|
8004
8634
|
({ className, type, ...props }, ref) => {
|
|
8005
|
-
return /* @__PURE__ */ (0,
|
|
8635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
8006
8636
|
"input",
|
|
8007
8637
|
{
|
|
8008
8638
|
type,
|
|
@@ -8021,9 +8651,9 @@ Input.displayName = "Input";
|
|
|
8021
8651
|
|
|
8022
8652
|
// src/ui/label.tsx
|
|
8023
8653
|
var import_radix_ui7 = require("radix-ui");
|
|
8024
|
-
var
|
|
8654
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
8025
8655
|
function Label({ className, ...props }) {
|
|
8026
|
-
return /* @__PURE__ */ (0,
|
|
8656
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
8027
8657
|
import_radix_ui7.Label.Root,
|
|
8028
8658
|
{
|
|
8029
8659
|
"data-slot": "label",
|
|
@@ -8034,12 +8664,12 @@ function Label({ className, ...props }) {
|
|
|
8034
8664
|
}
|
|
8035
8665
|
|
|
8036
8666
|
// src/ui/link-modal/UrlOrPageInput.tsx
|
|
8037
|
-
var
|
|
8038
|
-
var
|
|
8667
|
+
var import_lucide_react11 = require("lucide-react");
|
|
8668
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
8039
8669
|
function FieldChevron({
|
|
8040
8670
|
onClick
|
|
8041
8671
|
}) {
|
|
8042
|
-
return /* @__PURE__ */ (0,
|
|
8672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8043
8673
|
"button",
|
|
8044
8674
|
{
|
|
8045
8675
|
type: "button",
|
|
@@ -8047,7 +8677,7 @@ function FieldChevron({
|
|
|
8047
8677
|
onClick,
|
|
8048
8678
|
"aria-label": "Open page list",
|
|
8049
8679
|
tabIndex: -1,
|
|
8050
|
-
children: /* @__PURE__ */ (0,
|
|
8680
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.ChevronDown, { size: 16 })
|
|
8051
8681
|
}
|
|
8052
8682
|
);
|
|
8053
8683
|
}
|
|
@@ -8108,19 +8738,19 @@ function UrlOrPageInput({
|
|
|
8108
8738
|
"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]",
|
|
8109
8739
|
urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
|
|
8110
8740
|
);
|
|
8111
|
-
return /* @__PURE__ */ (0,
|
|
8112
|
-
/* @__PURE__ */ (0,
|
|
8113
|
-
/* @__PURE__ */ (0,
|
|
8114
|
-
/* @__PURE__ */ (0,
|
|
8115
|
-
selectedPage ? /* @__PURE__ */ (0,
|
|
8116
|
-
|
|
8741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
|
|
8742
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
|
|
8743
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
|
|
8744
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
|
|
8745
|
+
selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8746
|
+
import_lucide_react11.File,
|
|
8117
8747
|
{
|
|
8118
8748
|
size: 16,
|
|
8119
8749
|
className: "shrink-0 text-foreground",
|
|
8120
8750
|
"aria-hidden": true
|
|
8121
8751
|
}
|
|
8122
8752
|
) }) : null,
|
|
8123
|
-
readOnly ? /* @__PURE__ */ (0,
|
|
8753
|
+
readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8124
8754
|
Input,
|
|
8125
8755
|
{
|
|
8126
8756
|
ref: inputRef,
|
|
@@ -8146,7 +8776,7 @@ function UrlOrPageInput({
|
|
|
8146
8776
|
)
|
|
8147
8777
|
}
|
|
8148
8778
|
),
|
|
8149
|
-
selectedPage && !readOnly ? /* @__PURE__ */ (0,
|
|
8779
|
+
selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8150
8780
|
"button",
|
|
8151
8781
|
{
|
|
8152
8782
|
type: "button",
|
|
@@ -8154,26 +8784,26 @@ function UrlOrPageInput({
|
|
|
8154
8784
|
onMouseDown: clearSelection,
|
|
8155
8785
|
"aria-label": "Clear selected page",
|
|
8156
8786
|
tabIndex: -1,
|
|
8157
|
-
children: /* @__PURE__ */ (0,
|
|
8787
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.X, { size: 16, "aria-hidden": true })
|
|
8158
8788
|
}
|
|
8159
8789
|
) : null,
|
|
8160
|
-
!readOnly ? /* @__PURE__ */ (0,
|
|
8790
|
+
!readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
|
|
8161
8791
|
] }),
|
|
8162
|
-
dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0,
|
|
8792
|
+
dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
8163
8793
|
"div",
|
|
8164
8794
|
{
|
|
8165
8795
|
"data-ohw-link-page-dropdown": "",
|
|
8166
8796
|
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",
|
|
8167
8797
|
onMouseDown: (e) => e.preventDefault(),
|
|
8168
|
-
children: filteredPages.map((page) => /* @__PURE__ */ (0,
|
|
8798
|
+
children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
8169
8799
|
"button",
|
|
8170
8800
|
{
|
|
8171
8801
|
type: "button",
|
|
8172
8802
|
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",
|
|
8173
8803
|
onClick: () => onPageSelect(page),
|
|
8174
8804
|
children: [
|
|
8175
|
-
/* @__PURE__ */ (0,
|
|
8176
|
-
/* @__PURE__ */ (0,
|
|
8805
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
8806
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "truncate", children: page.title })
|
|
8177
8807
|
]
|
|
8178
8808
|
},
|
|
8179
8809
|
page.path
|
|
@@ -8181,34 +8811,34 @@ function UrlOrPageInput({
|
|
|
8181
8811
|
}
|
|
8182
8812
|
) : null
|
|
8183
8813
|
] }),
|
|
8184
|
-
urlError ? /* @__PURE__ */ (0,
|
|
8814
|
+
urlError ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
|
|
8185
8815
|
] });
|
|
8186
8816
|
}
|
|
8187
8817
|
|
|
8188
8818
|
// src/ui/link-modal/LinkEditorPanel.tsx
|
|
8189
|
-
var
|
|
8819
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
8190
8820
|
function LinkEditorPanel({ state, onClose }) {
|
|
8191
8821
|
const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
|
|
8192
|
-
return /* @__PURE__ */ (0,
|
|
8193
|
-
/* @__PURE__ */ (0,
|
|
8822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
8823
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
8194
8824
|
"button",
|
|
8195
8825
|
{
|
|
8196
8826
|
type: "button",
|
|
8197
8827
|
className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
|
|
8198
8828
|
"aria-label": "Close",
|
|
8199
8829
|
onClick: onClose,
|
|
8200
|
-
children: /* @__PURE__ */ (0,
|
|
8830
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
|
|
8201
8831
|
}
|
|
8202
8832
|
) }),
|
|
8203
|
-
/* @__PURE__ */ (0,
|
|
8204
|
-
/* @__PURE__ */ (0,
|
|
8205
|
-
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0,
|
|
8833
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
|
|
8834
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
|
|
8835
|
+
state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
8206
8836
|
DestinationBreadcrumb,
|
|
8207
8837
|
{
|
|
8208
8838
|
pageTitle: state.selectedPage.title,
|
|
8209
8839
|
sectionLabel: state.selectedSection.label
|
|
8210
8840
|
}
|
|
8211
|
-
) : /* @__PURE__ */ (0,
|
|
8841
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
8212
8842
|
UrlOrPageInput,
|
|
8213
8843
|
{
|
|
8214
8844
|
value: state.searchValue,
|
|
@@ -8221,8 +8851,8 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8221
8851
|
urlError: state.urlError
|
|
8222
8852
|
}
|
|
8223
8853
|
),
|
|
8224
|
-
state.showChooseSection ? /* @__PURE__ */ (0,
|
|
8225
|
-
/* @__PURE__ */ (0,
|
|
8854
|
+
state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
|
|
8855
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
8226
8856
|
Button,
|
|
8227
8857
|
{
|
|
8228
8858
|
type: "button",
|
|
@@ -8233,15 +8863,15 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8233
8863
|
children: "Choose a section"
|
|
8234
8864
|
}
|
|
8235
8865
|
),
|
|
8236
|
-
/* @__PURE__ */ (0,
|
|
8237
|
-
/* @__PURE__ */ (0,
|
|
8238
|
-
/* @__PURE__ */ (0,
|
|
8866
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
8867
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
|
|
8868
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: "Pick a section this link should scroll to." })
|
|
8239
8869
|
] })
|
|
8240
8870
|
] }) : null,
|
|
8241
|
-
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0,
|
|
8871
|
+
state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
|
|
8242
8872
|
] }),
|
|
8243
|
-
/* @__PURE__ */ (0,
|
|
8244
|
-
/* @__PURE__ */ (0,
|
|
8873
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
|
|
8874
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
8245
8875
|
Button,
|
|
8246
8876
|
{
|
|
8247
8877
|
type: "button",
|
|
@@ -8256,7 +8886,7 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8256
8886
|
children: state.secondaryLabel
|
|
8257
8887
|
}
|
|
8258
8888
|
),
|
|
8259
|
-
/* @__PURE__ */ (0,
|
|
8889
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
8260
8890
|
Button,
|
|
8261
8891
|
{
|
|
8262
8892
|
type: "button",
|
|
@@ -8277,9 +8907,9 @@ function LinkEditorPanel({ state, onClose }) {
|
|
|
8277
8907
|
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
8278
8908
|
var import_react10 = require("react");
|
|
8279
8909
|
var import_react_dom2 = require("react-dom");
|
|
8280
|
-
var
|
|
8910
|
+
var import_lucide_react13 = require("lucide-react");
|
|
8281
8911
|
var import_navigation2 = require("next/navigation");
|
|
8282
|
-
var
|
|
8912
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
8283
8913
|
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
8284
8914
|
function rectsEqual(a, b) {
|
|
8285
8915
|
if (a.size !== b.size) return false;
|
|
@@ -8508,7 +9138,7 @@ function SectionPickerOverlay({
|
|
|
8508
9138
|
const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
|
|
8509
9139
|
if (!portalRoot) return null;
|
|
8510
9140
|
return (0, import_react_dom2.createPortal)(
|
|
8511
|
-
/* @__PURE__ */ (0,
|
|
9141
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
8512
9142
|
"div",
|
|
8513
9143
|
{
|
|
8514
9144
|
"data-ohw-section-picker": "",
|
|
@@ -8518,12 +9148,12 @@ function SectionPickerOverlay({
|
|
|
8518
9148
|
role: "dialog",
|
|
8519
9149
|
"aria-label": "Choose a section",
|
|
8520
9150
|
children: [
|
|
8521
|
-
/* @__PURE__ */ (0,
|
|
9151
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
8522
9152
|
"div",
|
|
8523
9153
|
{
|
|
8524
9154
|
className: "pointer-events-auto fixed left-5 z-[2]",
|
|
8525
9155
|
style: { top: chromeClip.top + 20 },
|
|
8526
|
-
children: /* @__PURE__ */ (0,
|
|
9156
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
8527
9157
|
Button,
|
|
8528
9158
|
{
|
|
8529
9159
|
type: "button",
|
|
@@ -8532,14 +9162,14 @@ function SectionPickerOverlay({
|
|
|
8532
9162
|
className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
|
|
8533
9163
|
onClick: onBack,
|
|
8534
9164
|
children: [
|
|
8535
|
-
/* @__PURE__ */ (0,
|
|
9165
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react13.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
8536
9166
|
"Back"
|
|
8537
9167
|
]
|
|
8538
9168
|
}
|
|
8539
9169
|
)
|
|
8540
9170
|
}
|
|
8541
9171
|
),
|
|
8542
|
-
/* @__PURE__ */ (0,
|
|
9172
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
8543
9173
|
"div",
|
|
8544
9174
|
{
|
|
8545
9175
|
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",
|
|
@@ -8552,7 +9182,7 @@ function SectionPickerOverlay({
|
|
|
8552
9182
|
children: "Click on section to select"
|
|
8553
9183
|
}
|
|
8554
9184
|
),
|
|
8555
|
-
!isOnTargetPage ? /* @__PURE__ */ (0,
|
|
9185
|
+
!isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
8556
9186
|
"div",
|
|
8557
9187
|
{
|
|
8558
9188
|
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",
|
|
@@ -8560,14 +9190,14 @@ function SectionPickerOverlay({
|
|
|
8560
9190
|
children: "Loading page preview\u2026"
|
|
8561
9191
|
}
|
|
8562
9192
|
) : null,
|
|
8563
|
-
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0,
|
|
9193
|
+
isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
|
|
8564
9194
|
isOnTargetPage ? liveSections.map((section) => {
|
|
8565
9195
|
const rect = rects.get(section.id);
|
|
8566
9196
|
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
8567
9197
|
const isSelected = selectedId === section.id;
|
|
8568
9198
|
const isHovered = hoveredId === section.id;
|
|
8569
9199
|
const isLit = isSelected || isHovered;
|
|
8570
|
-
return /* @__PURE__ */ (0,
|
|
9200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
8571
9201
|
"button",
|
|
8572
9202
|
{
|
|
8573
9203
|
type: "button",
|
|
@@ -8582,7 +9212,7 @@ function SectionPickerOverlay({
|
|
|
8582
9212
|
"aria-label": `Select section ${section.label}`,
|
|
8583
9213
|
onClick: () => handleSelect(section),
|
|
8584
9214
|
children: [
|
|
8585
|
-
isLit ? /* @__PURE__ */ (0,
|
|
9215
|
+
isLit ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
8586
9216
|
"span",
|
|
8587
9217
|
{
|
|
8588
9218
|
className: "pointer-events-none absolute",
|
|
@@ -8595,13 +9225,13 @@ function SectionPickerOverlay({
|
|
|
8595
9225
|
"aria-hidden": true
|
|
8596
9226
|
}
|
|
8597
9227
|
) : null,
|
|
8598
|
-
isSelected ? /* @__PURE__ */ (0,
|
|
9228
|
+
isSelected ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
8599
9229
|
"span",
|
|
8600
9230
|
{
|
|
8601
9231
|
className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
|
|
8602
9232
|
style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
|
|
8603
9233
|
"aria-hidden": true,
|
|
8604
|
-
children: /* @__PURE__ */ (0,
|
|
9234
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react13.Check, { className: "size-5" })
|
|
8605
9235
|
}
|
|
8606
9236
|
) : null
|
|
8607
9237
|
]
|
|
@@ -8781,7 +9411,7 @@ function useLinkModalState({
|
|
|
8781
9411
|
}
|
|
8782
9412
|
|
|
8783
9413
|
// src/ui/link-modal/LinkPopover.tsx
|
|
8784
|
-
var
|
|
9414
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
8785
9415
|
function postToParent(data) {
|
|
8786
9416
|
window.parent?.postMessage(data, "*");
|
|
8787
9417
|
}
|
|
@@ -8877,15 +9507,15 @@ function LinkPopover({
|
|
|
8877
9507
|
);
|
|
8878
9508
|
};
|
|
8879
9509
|
}, [open, sectionPickerActive]);
|
|
8880
|
-
return /* @__PURE__ */ (0,
|
|
8881
|
-
/* @__PURE__ */ (0,
|
|
9510
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
9511
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
8882
9512
|
Dialog2,
|
|
8883
9513
|
{
|
|
8884
9514
|
open: open && !sectionPickerActive,
|
|
8885
9515
|
onOpenChange: (next) => {
|
|
8886
9516
|
if (!next) onClose?.();
|
|
8887
9517
|
},
|
|
8888
|
-
children: /* @__PURE__ */ (0,
|
|
9518
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
8889
9519
|
DialogContent,
|
|
8890
9520
|
{
|
|
8891
9521
|
ref: panelRef,
|
|
@@ -8895,12 +9525,12 @@ function LinkPopover({
|
|
|
8895
9525
|
"data-ohw-bridge": "",
|
|
8896
9526
|
showCloseButton: false,
|
|
8897
9527
|
className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
|
|
8898
|
-
children: /* @__PURE__ */ (0,
|
|
9528
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LinkEditorPanel, { state, onClose })
|
|
8899
9529
|
}
|
|
8900
9530
|
)
|
|
8901
9531
|
}
|
|
8902
9532
|
),
|
|
8903
|
-
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0,
|
|
9533
|
+
sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
8904
9534
|
SectionPickerOverlay,
|
|
8905
9535
|
{
|
|
8906
9536
|
pagePath: state.selectedPage.path,
|
|
@@ -10126,13 +10756,14 @@ function listSocialItems(row) {
|
|
|
10126
10756
|
return isSocialItem(anchor) ? anchor : null;
|
|
10127
10757
|
}).filter((item) => item !== null);
|
|
10128
10758
|
}
|
|
10129
|
-
function socialRowUnit(item) {
|
|
10130
|
-
const row = findSocialsRow(item);
|
|
10759
|
+
function socialRowUnit(item, knownRow) {
|
|
10760
|
+
const row = knownRow ?? findSocialsRow(item);
|
|
10761
|
+
if (!row || !row.contains(item)) return null;
|
|
10131
10762
|
let node = item;
|
|
10132
10763
|
while (node.parentElement && node.parentElement !== row) {
|
|
10133
10764
|
node = node.parentElement;
|
|
10134
10765
|
}
|
|
10135
|
-
return node;
|
|
10766
|
+
return node.parentElement === row ? node : null;
|
|
10136
10767
|
}
|
|
10137
10768
|
function listSocialsRows(root = document) {
|
|
10138
10769
|
const rows = /* @__PURE__ */ new Set();
|
|
@@ -10151,7 +10782,8 @@ function markSocialsRows(root = document) {
|
|
|
10151
10782
|
listSocialsRows(root).forEach((row) => {
|
|
10152
10783
|
row.setAttribute(SOCIALS_ROW_ATTR, "");
|
|
10153
10784
|
const items = listSocialItems(row);
|
|
10154
|
-
|
|
10785
|
+
const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
|
|
10786
|
+
if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
|
|
10155
10787
|
items.forEach((item, index) => {
|
|
10156
10788
|
item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
|
|
10157
10789
|
const iconKey = socialIconKey(item);
|
|
@@ -10295,7 +10927,8 @@ function removeSocialItem(item, content) {
|
|
|
10295
10927
|
const previousContent = Object.fromEntries(
|
|
10296
10928
|
removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
|
|
10297
10929
|
);
|
|
10298
|
-
const unit = socialRowUnit(item);
|
|
10930
|
+
const unit = socialRowUnit(item, row);
|
|
10931
|
+
if (!unit) return null;
|
|
10299
10932
|
const nextSibling = unit.nextElementSibling;
|
|
10300
10933
|
unit.remove();
|
|
10301
10934
|
markSocialsRows(row.ownerDocument);
|
|
@@ -10318,7 +10951,9 @@ function applySocialsOrder(order, root = document) {
|
|
|
10318
10951
|
const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
|
|
10319
10952
|
wanted.forEach((key) => {
|
|
10320
10953
|
const item = byKey.get(key);
|
|
10321
|
-
if (item)
|
|
10954
|
+
if (!item) return;
|
|
10955
|
+
const unit = socialRowUnit(item, row);
|
|
10956
|
+
if (unit) row.appendChild(unit);
|
|
10322
10957
|
});
|
|
10323
10958
|
});
|
|
10324
10959
|
markSocialsRows(root);
|
|
@@ -10348,7 +10983,7 @@ function reconcileSocialsFromContent(content, root = document) {
|
|
|
10348
10983
|
});
|
|
10349
10984
|
if (surviving.length) {
|
|
10350
10985
|
present.forEach((item) => {
|
|
10351
|
-
if (!surviving.includes(item)) socialRowUnit(item)
|
|
10986
|
+
if (!surviving.includes(item)) socialRowUnit(item)?.remove();
|
|
10352
10987
|
});
|
|
10353
10988
|
}
|
|
10354
10989
|
});
|
|
@@ -11684,8 +12319,8 @@ function addFooterColumnWithPersist({
|
|
|
11684
12319
|
|
|
11685
12320
|
// src/ui/FloatingPanel.tsx
|
|
11686
12321
|
var import_react13 = require("react");
|
|
11687
|
-
var
|
|
11688
|
-
var
|
|
12322
|
+
var import_lucide_react14 = require("lucide-react");
|
|
12323
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
11689
12324
|
var PANEL_WIDTH = 256;
|
|
11690
12325
|
var EDGE_MARGIN = 16;
|
|
11691
12326
|
function getVisibleClip(parentScroll) {
|
|
@@ -11800,7 +12435,7 @@ function FloatingPanel({
|
|
|
11800
12435
|
}, [open]);
|
|
11801
12436
|
(0, import_react13.useEffect)(() => () => document.documentElement.removeAttribute("data-ohw-panel-dragging"), []);
|
|
11802
12437
|
if (!open) return null;
|
|
11803
|
-
return /* @__PURE__ */ (0,
|
|
12438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
11804
12439
|
"div",
|
|
11805
12440
|
{
|
|
11806
12441
|
ref: panelRef,
|
|
@@ -11817,7 +12452,7 @@ function FloatingPanel({
|
|
|
11817
12452
|
onPointerDown: (e) => e.stopPropagation(),
|
|
11818
12453
|
onClick: (e) => e.stopPropagation(),
|
|
11819
12454
|
children: [
|
|
11820
|
-
/* @__PURE__ */ (0,
|
|
12455
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
11821
12456
|
"div",
|
|
11822
12457
|
{
|
|
11823
12458
|
"data-ohw-floating-panel-header": "",
|
|
@@ -11827,14 +12462,14 @@ function FloatingPanel({
|
|
|
11827
12462
|
onPointerUp: endDrag,
|
|
11828
12463
|
onPointerCancel: endDrag,
|
|
11829
12464
|
children: [
|
|
11830
|
-
/* @__PURE__ */ (0,
|
|
11831
|
-
/* @__PURE__ */ (0,
|
|
11832
|
-
icon ? /* @__PURE__ */ (0,
|
|
11833
|
-
/* @__PURE__ */ (0,
|
|
12465
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
|
|
12466
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12467
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "shrink-0 text-foreground", children: icon }) : null,
|
|
12468
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
|
|
11834
12469
|
] }),
|
|
11835
|
-
context ? /* @__PURE__ */ (0,
|
|
12470
|
+
context ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
|
|
11836
12471
|
] }),
|
|
11837
|
-
/* @__PURE__ */ (0,
|
|
12472
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
11838
12473
|
"button",
|
|
11839
12474
|
{
|
|
11840
12475
|
type: "button",
|
|
@@ -11846,13 +12481,13 @@ function FloatingPanel({
|
|
|
11846
12481
|
onClose();
|
|
11847
12482
|
},
|
|
11848
12483
|
onPointerDown: (e) => e.stopPropagation(),
|
|
11849
|
-
children: /* @__PURE__ */ (0,
|
|
12484
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.X, { size: 16, "aria-hidden": true })
|
|
11850
12485
|
}
|
|
11851
12486
|
)
|
|
11852
12487
|
]
|
|
11853
12488
|
}
|
|
11854
12489
|
),
|
|
11855
|
-
/* @__PURE__ */ (0,
|
|
12490
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
11856
12491
|
"div",
|
|
11857
12492
|
{
|
|
11858
12493
|
"data-ohw-floating-panel-body": "",
|
|
@@ -11866,30 +12501,30 @@ function FloatingPanel({
|
|
|
11866
12501
|
}
|
|
11867
12502
|
|
|
11868
12503
|
// src/ui/logo-size-panel.tsx
|
|
11869
|
-
var
|
|
11870
|
-
var
|
|
12504
|
+
var import_lucide_react15 = require("lucide-react");
|
|
12505
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
11871
12506
|
function SizeSlider({
|
|
11872
12507
|
value,
|
|
11873
12508
|
onChange
|
|
11874
12509
|
}) {
|
|
11875
12510
|
const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
|
|
11876
|
-
return /* @__PURE__ */ (0,
|
|
11877
|
-
/* @__PURE__ */ (0,
|
|
11878
|
-
/* @__PURE__ */ (0,
|
|
11879
|
-
/* @__PURE__ */ (0,
|
|
12511
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full flex-col gap-3", children: [
|
|
12512
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
|
|
12513
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
|
|
12514
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
|
|
11880
12515
|
value,
|
|
11881
12516
|
" px"
|
|
11882
12517
|
] })
|
|
11883
12518
|
] }),
|
|
11884
|
-
/* @__PURE__ */ (0,
|
|
11885
|
-
/* @__PURE__ */ (0,
|
|
12519
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
|
|
12520
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
11886
12521
|
"div",
|
|
11887
12522
|
{
|
|
11888
12523
|
className: "absolute inset-y-0 left-0 rounded-full bg-primary",
|
|
11889
12524
|
style: { width: `${pct}%` }
|
|
11890
12525
|
}
|
|
11891
12526
|
),
|
|
11892
|
-
/* @__PURE__ */ (0,
|
|
12527
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
11893
12528
|
"input",
|
|
11894
12529
|
{
|
|
11895
12530
|
type: "range",
|
|
@@ -11926,14 +12561,14 @@ function LogoSizePanel({
|
|
|
11926
12561
|
const showFollowing = viewport === "mobile" && mobileFollowing;
|
|
11927
12562
|
const showMobileSlider = viewport === "mobile" && !mobileFollowing;
|
|
11928
12563
|
const showDesktopSlider = viewport === "desktop";
|
|
11929
|
-
return /* @__PURE__ */ (0,
|
|
11930
|
-
showFollowing ? /* @__PURE__ */ (0,
|
|
11931
|
-
/* @__PURE__ */ (0,
|
|
11932
|
-
/* @__PURE__ */ (0,
|
|
11933
|
-
/* @__PURE__ */ (0,
|
|
12564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("flex w-full flex-col gap-4", className), children: [
|
|
12565
|
+
showFollowing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
|
|
12566
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-start gap-1", children: [
|
|
12567
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react15.Link, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
|
|
12568
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
|
|
11934
12569
|
] }),
|
|
11935
|
-
/* @__PURE__ */ (0,
|
|
11936
|
-
/* @__PURE__ */ (0,
|
|
12570
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("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." }),
|
|
12571
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
11937
12572
|
Button,
|
|
11938
12573
|
{
|
|
11939
12574
|
type: "button",
|
|
@@ -11945,8 +12580,8 @@ function LogoSizePanel({
|
|
|
11945
12580
|
}
|
|
11946
12581
|
)
|
|
11947
12582
|
] }) : null,
|
|
11948
|
-
showDesktopSlider || showMobileSlider ? /* @__PURE__ */ (0,
|
|
11949
|
-
showMobileSlider ? /* @__PURE__ */ (0,
|
|
12583
|
+
showDesktopSlider || showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
|
|
12584
|
+
showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
11950
12585
|
Button,
|
|
11951
12586
|
{
|
|
11952
12587
|
type: "button",
|
|
@@ -11957,8 +12592,8 @@ function LogoSizePanel({
|
|
|
11957
12592
|
children: "Reset to desktop size"
|
|
11958
12593
|
}
|
|
11959
12594
|
) : null,
|
|
11960
|
-
/* @__PURE__ */ (0,
|
|
11961
|
-
/* @__PURE__ */ (0,
|
|
12595
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-px w-full bg-border", role: "separator" }),
|
|
12596
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
11962
12597
|
Button,
|
|
11963
12598
|
{
|
|
11964
12599
|
type: "button",
|
|
@@ -11968,24 +12603,24 @@ function LogoSizePanel({
|
|
|
11968
12603
|
onClick: onUpdateEverywhere,
|
|
11969
12604
|
children: [
|
|
11970
12605
|
"Update logo everywhere",
|
|
11971
|
-
/* @__PURE__ */ (0,
|
|
12606
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react15.ArrowUpRight, { size: 16, "aria-hidden": true })
|
|
11972
12607
|
]
|
|
11973
12608
|
}
|
|
11974
12609
|
),
|
|
11975
|
-
/* @__PURE__ */ (0,
|
|
12610
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
|
|
11976
12611
|
] });
|
|
11977
12612
|
}
|
|
11978
12613
|
|
|
11979
12614
|
// src/ui/socials-display-panel.tsx
|
|
11980
|
-
var
|
|
12615
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
11981
12616
|
function DisplaySwitch({
|
|
11982
12617
|
label,
|
|
11983
12618
|
checked,
|
|
11984
12619
|
disabled,
|
|
11985
12620
|
onChange
|
|
11986
12621
|
}) {
|
|
11987
|
-
return /* @__PURE__ */ (0,
|
|
11988
|
-
/* @__PURE__ */ (0,
|
|
12622
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
|
|
12623
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
11989
12624
|
"span",
|
|
11990
12625
|
{
|
|
11991
12626
|
className: cn(
|
|
@@ -11995,7 +12630,7 @@ function DisplaySwitch({
|
|
|
11995
12630
|
children: label
|
|
11996
12631
|
}
|
|
11997
12632
|
),
|
|
11998
|
-
/* @__PURE__ */ (0,
|
|
12633
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
11999
12634
|
"button",
|
|
12000
12635
|
{
|
|
12001
12636
|
type: "button",
|
|
@@ -12009,7 +12644,7 @@ function DisplaySwitch({
|
|
|
12009
12644
|
checked ? "bg-primary" : "bg-primary-50",
|
|
12010
12645
|
disabled ? "cursor-default opacity-50" : "cursor-pointer"
|
|
12011
12646
|
),
|
|
12012
|
-
children: /* @__PURE__ */ (0,
|
|
12647
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
12013
12648
|
"span",
|
|
12014
12649
|
{
|
|
12015
12650
|
className: cn(
|
|
@@ -12023,8 +12658,8 @@ function DisplaySwitch({
|
|
|
12023
12658
|
] });
|
|
12024
12659
|
}
|
|
12025
12660
|
function SocialsDisplayPanel({ display, onChange, className }) {
|
|
12026
|
-
return /* @__PURE__ */ (0,
|
|
12027
|
-
/* @__PURE__ */ (0,
|
|
12661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: cn("flex w-full flex-col gap-3", className), children: [
|
|
12662
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
12028
12663
|
DisplaySwitch,
|
|
12029
12664
|
{
|
|
12030
12665
|
label: "Text",
|
|
@@ -12033,7 +12668,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
|
|
|
12033
12668
|
onChange: (text) => onChange({ ...display, text })
|
|
12034
12669
|
}
|
|
12035
12670
|
),
|
|
12036
|
-
/* @__PURE__ */ (0,
|
|
12671
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
12037
12672
|
DisplaySwitch,
|
|
12038
12673
|
{
|
|
12039
12674
|
label: "Icon",
|
|
@@ -12593,8 +13228,8 @@ function useNavItemDrag({
|
|
|
12593
13228
|
}
|
|
12594
13229
|
|
|
12595
13230
|
// src/ui/footer-container-chrome.tsx
|
|
12596
|
-
var
|
|
12597
|
-
var
|
|
13231
|
+
var import_lucide_react16 = require("lucide-react");
|
|
13232
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
12598
13233
|
function FooterContainerChrome({
|
|
12599
13234
|
rect,
|
|
12600
13235
|
onAdd,
|
|
@@ -12602,7 +13237,7 @@ function FooterContainerChrome({
|
|
|
12602
13237
|
}) {
|
|
12603
13238
|
const chromeGap = 6;
|
|
12604
13239
|
const buttonMargin = 7;
|
|
12605
|
-
return /* @__PURE__ */ (0,
|
|
13240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
12606
13241
|
"div",
|
|
12607
13242
|
{
|
|
12608
13243
|
"data-ohw-footer-container-chrome": "",
|
|
@@ -12614,8 +13249,8 @@ function FooterContainerChrome({
|
|
|
12614
13249
|
width: rect.width + chromeGap * 2,
|
|
12615
13250
|
height: rect.height + chromeGap * 2
|
|
12616
13251
|
},
|
|
12617
|
-
children: /* @__PURE__ */ (0,
|
|
12618
|
-
/* @__PURE__ */ (0,
|
|
13252
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(Tooltip, { children: [
|
|
13253
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
12619
13254
|
"button",
|
|
12620
13255
|
{
|
|
12621
13256
|
type: "button",
|
|
@@ -12634,10 +13269,10 @@ function FooterContainerChrome({
|
|
|
12634
13269
|
if (addDisabled) return;
|
|
12635
13270
|
onAdd();
|
|
12636
13271
|
},
|
|
12637
|
-
children: /* @__PURE__ */ (0,
|
|
13272
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react16.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
12638
13273
|
}
|
|
12639
13274
|
) }),
|
|
12640
|
-
/* @__PURE__ */ (0,
|
|
13275
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
|
|
12641
13276
|
] })
|
|
12642
13277
|
}
|
|
12643
13278
|
) });
|
|
@@ -13097,14 +13732,14 @@ function deleteSelectedNavFooterItem(deps) {
|
|
|
13097
13732
|
}
|
|
13098
13733
|
|
|
13099
13734
|
// src/ui/navbar-container-chrome.tsx
|
|
13100
|
-
var
|
|
13101
|
-
var
|
|
13735
|
+
var import_lucide_react17 = require("lucide-react");
|
|
13736
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
13102
13737
|
function NavbarContainerChrome({
|
|
13103
13738
|
rect,
|
|
13104
13739
|
onAdd
|
|
13105
13740
|
}) {
|
|
13106
13741
|
const chromeGap = 6;
|
|
13107
|
-
return /* @__PURE__ */ (0,
|
|
13742
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
13108
13743
|
"div",
|
|
13109
13744
|
{
|
|
13110
13745
|
"data-ohw-navbar-container-chrome": "",
|
|
@@ -13116,7 +13751,7 @@ function NavbarContainerChrome({
|
|
|
13116
13751
|
width: rect.width + chromeGap * 2,
|
|
13117
13752
|
height: rect.height + chromeGap * 2
|
|
13118
13753
|
},
|
|
13119
|
-
children: /* @__PURE__ */ (0,
|
|
13754
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
13120
13755
|
"button",
|
|
13121
13756
|
{
|
|
13122
13757
|
type: "button",
|
|
@@ -13133,7 +13768,7 @@ function NavbarContainerChrome({
|
|
|
13133
13768
|
e.stopPropagation();
|
|
13134
13769
|
onAdd();
|
|
13135
13770
|
},
|
|
13136
|
-
children: /* @__PURE__ */ (0,
|
|
13771
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react17.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
13137
13772
|
}
|
|
13138
13773
|
)
|
|
13139
13774
|
}
|
|
@@ -13142,7 +13777,7 @@ function NavbarContainerChrome({
|
|
|
13142
13777
|
|
|
13143
13778
|
// src/ui/drop-indicator.tsx
|
|
13144
13779
|
var React10 = __toESM(require("react"), 1);
|
|
13145
|
-
var
|
|
13780
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
13146
13781
|
var dropIndicatorVariants = cva(
|
|
13147
13782
|
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
13148
13783
|
{
|
|
@@ -13166,7 +13801,7 @@ var dropIndicatorVariants = cva(
|
|
|
13166
13801
|
);
|
|
13167
13802
|
var DropIndicator = React10.forwardRef(
|
|
13168
13803
|
({ className, direction, state, ...props }, ref) => {
|
|
13169
|
-
return /* @__PURE__ */ (0,
|
|
13804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
13170
13805
|
"div",
|
|
13171
13806
|
{
|
|
13172
13807
|
ref,
|
|
@@ -13183,7 +13818,7 @@ var DropIndicator = React10.forwardRef(
|
|
|
13183
13818
|
DropIndicator.displayName = "DropIndicator";
|
|
13184
13819
|
|
|
13185
13820
|
// src/ui/badge.tsx
|
|
13186
|
-
var
|
|
13821
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
13187
13822
|
var badgeVariants = cva(
|
|
13188
13823
|
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
13189
13824
|
{
|
|
@@ -13201,12 +13836,12 @@ var badgeVariants = cva(
|
|
|
13201
13836
|
}
|
|
13202
13837
|
);
|
|
13203
13838
|
function Badge({ className, variant, ...props }) {
|
|
13204
|
-
return /* @__PURE__ */ (0,
|
|
13839
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
13205
13840
|
}
|
|
13206
13841
|
|
|
13207
13842
|
// src/OhhwellsBridge.tsx
|
|
13208
|
-
var
|
|
13209
|
-
var
|
|
13843
|
+
var import_lucide_react18 = require("lucide-react");
|
|
13844
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
13210
13845
|
var PRIMARY3 = "#0885FE";
|
|
13211
13846
|
var IMAGE_FADE_MS = 300;
|
|
13212
13847
|
function runOpacityFade(el, onDone) {
|
|
@@ -13375,7 +14010,7 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
|
|
|
13375
14010
|
const root = (0, import_client2.createRoot)(container);
|
|
13376
14011
|
(0, import_react_dom3.flushSync)(() => {
|
|
13377
14012
|
root.render(
|
|
13378
|
-
/* @__PURE__ */ (0,
|
|
14013
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
13379
14014
|
SchedulingWidget,
|
|
13380
14015
|
{
|
|
13381
14016
|
notifyOnConnect,
|
|
@@ -13490,7 +14125,7 @@ function isIconEditable(el) {
|
|
|
13490
14125
|
return el.dataset.ohwEditable === "icon";
|
|
13491
14126
|
}
|
|
13492
14127
|
var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
|
|
13493
|
-
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"])';
|
|
14128
|
+
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"])';
|
|
13494
14129
|
function getVideoEl2(el) {
|
|
13495
14130
|
return el instanceof HTMLVideoElement ? el : el.querySelector("video");
|
|
13496
14131
|
}
|
|
@@ -14051,7 +14686,7 @@ function EditGlowChrome({
|
|
|
14051
14686
|
hideHandle = false
|
|
14052
14687
|
}) {
|
|
14053
14688
|
const GAP = SELECTION_CHROME_GAP2;
|
|
14054
|
-
return /* @__PURE__ */ (0,
|
|
14689
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
14055
14690
|
"div",
|
|
14056
14691
|
{
|
|
14057
14692
|
ref: elRef,
|
|
@@ -14066,7 +14701,7 @@ function EditGlowChrome({
|
|
|
14066
14701
|
zIndex: 2147483646
|
|
14067
14702
|
},
|
|
14068
14703
|
children: [
|
|
14069
|
-
/* @__PURE__ */ (0,
|
|
14704
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14070
14705
|
"div",
|
|
14071
14706
|
{
|
|
14072
14707
|
style: {
|
|
@@ -14079,7 +14714,7 @@ function EditGlowChrome({
|
|
|
14079
14714
|
}
|
|
14080
14715
|
}
|
|
14081
14716
|
),
|
|
14082
|
-
reorderHrefKey && !hideHandle && /* @__PURE__ */ (0,
|
|
14717
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14083
14718
|
"div",
|
|
14084
14719
|
{
|
|
14085
14720
|
"data-ohw-drag-handle-container": "",
|
|
@@ -14091,7 +14726,7 @@ function EditGlowChrome({
|
|
|
14091
14726
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
14092
14727
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
14093
14728
|
},
|
|
14094
|
-
children: /* @__PURE__ */ (0,
|
|
14729
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14095
14730
|
DragHandle,
|
|
14096
14731
|
{
|
|
14097
14732
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -14301,7 +14936,7 @@ function FloatingToolbar({
|
|
|
14301
14936
|
return () => ro.disconnect();
|
|
14302
14937
|
}, [showEditLink, activeCommands]);
|
|
14303
14938
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
14304
|
-
return /* @__PURE__ */ (0,
|
|
14939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14305
14940
|
"div",
|
|
14306
14941
|
{
|
|
14307
14942
|
ref: setRefs,
|
|
@@ -14313,12 +14948,12 @@ function FloatingToolbar({
|
|
|
14313
14948
|
zIndex: 2147483647,
|
|
14314
14949
|
pointerEvents: "auto"
|
|
14315
14950
|
},
|
|
14316
|
-
children: /* @__PURE__ */ (0,
|
|
14317
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
14318
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
14951
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(CustomToolbar, { children: [
|
|
14952
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_react16.default.Fragment, { children: [
|
|
14953
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CustomToolbarDivider, {}),
|
|
14319
14954
|
btns.map((btn) => {
|
|
14320
14955
|
const isActive = activeCommands.has(btn.cmd);
|
|
14321
|
-
return /* @__PURE__ */ (0,
|
|
14956
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14322
14957
|
CustomToolbarButton,
|
|
14323
14958
|
{
|
|
14324
14959
|
title: btn.title,
|
|
@@ -14327,7 +14962,7 @@ function FloatingToolbar({
|
|
|
14327
14962
|
e.preventDefault();
|
|
14328
14963
|
onCommand(btn.cmd);
|
|
14329
14964
|
},
|
|
14330
|
-
children: /* @__PURE__ */ (0,
|
|
14965
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14331
14966
|
"svg",
|
|
14332
14967
|
{
|
|
14333
14968
|
width: "16",
|
|
@@ -14348,7 +14983,7 @@ function FloatingToolbar({
|
|
|
14348
14983
|
);
|
|
14349
14984
|
})
|
|
14350
14985
|
] }, gi)),
|
|
14351
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
14986
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14352
14987
|
CustomToolbarButton,
|
|
14353
14988
|
{
|
|
14354
14989
|
type: "button",
|
|
@@ -14362,7 +14997,7 @@ function FloatingToolbar({
|
|
|
14362
14997
|
e.preventDefault();
|
|
14363
14998
|
e.stopPropagation();
|
|
14364
14999
|
},
|
|
14365
|
-
children: /* @__PURE__ */ (0,
|
|
15000
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
14366
15001
|
}
|
|
14367
15002
|
) : null
|
|
14368
15003
|
] })
|
|
@@ -14379,7 +15014,7 @@ function StateToggle({
|
|
|
14379
15014
|
states,
|
|
14380
15015
|
onStateChange
|
|
14381
15016
|
}) {
|
|
14382
|
-
return /* @__PURE__ */ (0,
|
|
15017
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
14383
15018
|
ToggleGroup,
|
|
14384
15019
|
{
|
|
14385
15020
|
"data-ohw-state-toggle": "",
|
|
@@ -14393,7 +15028,7 @@ function StateToggle({
|
|
|
14393
15028
|
left: rect.right - 8,
|
|
14394
15029
|
transform: "translateX(-100%)"
|
|
14395
15030
|
},
|
|
14396
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
15031
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
14397
15032
|
}
|
|
14398
15033
|
);
|
|
14399
15034
|
}
|
|
@@ -14516,6 +15151,157 @@ function OhhwellsBridge() {
|
|
|
14516
15151
|
const sectionsLoadedRef = (0, import_react16.useRef)(false);
|
|
14517
15152
|
const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
|
|
14518
15153
|
const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
|
|
15154
|
+
const [formPickRect, setFormPickRect] = (0, import_react16.useState)(null);
|
|
15155
|
+
const formPickElRef = (0, import_react16.useRef)(null);
|
|
15156
|
+
const [formViewState, setFormViewStateUi] = (0, import_react16.useState)("default");
|
|
15157
|
+
const [formPickCount, setFormPickCount] = (0, import_react16.useState)(null);
|
|
15158
|
+
const [formHoverRect, setFormHoverRect] = (0, import_react16.useState)(null);
|
|
15159
|
+
const formHoverElRef = (0, import_react16.useRef)(null);
|
|
15160
|
+
const [fieldPickRect, setFieldPickRect] = (0, import_react16.useState)(null);
|
|
15161
|
+
const fieldPickElRef = (0, import_react16.useRef)(null);
|
|
15162
|
+
const [fieldPickState, setFieldPickState] = (0, import_react16.useState)(null);
|
|
15163
|
+
const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react16.useState)(false);
|
|
15164
|
+
const clearFormPick = (0, import_react16.useCallback)(() => {
|
|
15165
|
+
const form = formPickElRef.current;
|
|
15166
|
+
if (form) {
|
|
15167
|
+
const key = formKeyOf(form);
|
|
15168
|
+
if (key) setFormViewState(form, key, "default", DEFAULT_SUCCESS_TEXT);
|
|
15169
|
+
}
|
|
15170
|
+
setFormViewStateUi("default");
|
|
15171
|
+
setFormPickCount(null);
|
|
15172
|
+
setFieldTypePickerOpen(false);
|
|
15173
|
+
fieldPickElRef.current = null;
|
|
15174
|
+
setFieldPickRect(null);
|
|
15175
|
+
setFieldPickState(null);
|
|
15176
|
+
formPickElRef.current = null;
|
|
15177
|
+
setFormPickRect(null);
|
|
15178
|
+
}, []);
|
|
15179
|
+
const clearFieldPick = (0, import_react16.useCallback)(() => {
|
|
15180
|
+
const wrapper = fieldPickElRef.current;
|
|
15181
|
+
if (commitPlaceholderEdit(wrapper) && wrapper) {
|
|
15182
|
+
const form = wrapper.closest('[data-ohw-editable="form"]');
|
|
15183
|
+
if (form) persistFieldsRef.current(form);
|
|
15184
|
+
}
|
|
15185
|
+
fieldPickElRef.current = null;
|
|
15186
|
+
setFieldPickRect(null);
|
|
15187
|
+
setFieldPickState(null);
|
|
15188
|
+
}, []);
|
|
15189
|
+
const persistFieldsRef = (0, import_react16.useRef)(() => {
|
|
15190
|
+
});
|
|
15191
|
+
const persistFields = (0, import_react16.useCallback)(
|
|
15192
|
+
(form) => {
|
|
15193
|
+
const key = formKeyOf(form);
|
|
15194
|
+
if (!key) return;
|
|
15195
|
+
const json = JSON.stringify(readFieldsFromDom(form));
|
|
15196
|
+
editContentRef.current = { ...editContentRef.current, [fieldsKey(key)]: json };
|
|
15197
|
+
postToParentRef.current({ type: "ow:change", nodes: [{ key: fieldsKey(key), text: json }] });
|
|
15198
|
+
},
|
|
15199
|
+
[]
|
|
15200
|
+
);
|
|
15201
|
+
persistFieldsRef.current = persistFields;
|
|
15202
|
+
const selectField = (0, import_react16.useCallback)((wrapper) => {
|
|
15203
|
+
if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
|
|
15204
|
+
commitPlaceholderEdit(fieldPickElRef.current);
|
|
15205
|
+
}
|
|
15206
|
+
syncRequiredMark(wrapper);
|
|
15207
|
+
beginPlaceholderEdit(wrapper);
|
|
15208
|
+
formHoverElRef.current = null;
|
|
15209
|
+
setFormHoverRect(null);
|
|
15210
|
+
fieldPickElRef.current = wrapper;
|
|
15211
|
+
setFieldPickRect(wrapper.getBoundingClientRect());
|
|
15212
|
+
setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
|
|
15213
|
+
setFieldTypePickerOpen(false);
|
|
15214
|
+
}, []);
|
|
15215
|
+
const withSelectedField = (0, import_react16.useCallback)(
|
|
15216
|
+
(run) => {
|
|
15217
|
+
const wrapper = fieldPickElRef.current;
|
|
15218
|
+
const form = formPickElRef.current;
|
|
15219
|
+
if (!wrapper || !form) return;
|
|
15220
|
+
commitPlaceholderEdit(wrapper);
|
|
15221
|
+
run(form, wrapper);
|
|
15222
|
+
beginPlaceholderEdit(wrapper);
|
|
15223
|
+
persistFields(form);
|
|
15224
|
+
setFormPickRect(form.getBoundingClientRect());
|
|
15225
|
+
},
|
|
15226
|
+
[persistFields]
|
|
15227
|
+
);
|
|
15228
|
+
const handleFieldTypeChange = (0, import_react16.useCallback)(
|
|
15229
|
+
(type) => withSelectedField((_form, wrapper) => {
|
|
15230
|
+
applyFieldType(wrapper, type);
|
|
15231
|
+
selectField(wrapper);
|
|
15232
|
+
}),
|
|
15233
|
+
[selectField, withSelectedField]
|
|
15234
|
+
);
|
|
15235
|
+
const handleFieldRequiredToggle = (0, import_react16.useCallback)(
|
|
15236
|
+
() => withSelectedField((_form, wrapper) => {
|
|
15237
|
+
setFieldRequired(wrapper, !isFieldRequired(wrapper));
|
|
15238
|
+
selectField(wrapper);
|
|
15239
|
+
}),
|
|
15240
|
+
[selectField, withSelectedField]
|
|
15241
|
+
);
|
|
15242
|
+
const handleFieldDuplicate = (0, import_react16.useCallback)(
|
|
15243
|
+
() => withSelectedField((form, wrapper) => {
|
|
15244
|
+
const copy = duplicateField(form, wrapper);
|
|
15245
|
+
selectField(copy);
|
|
15246
|
+
}),
|
|
15247
|
+
[selectField, withSelectedField]
|
|
15248
|
+
);
|
|
15249
|
+
const handleFieldDelete = (0, import_react16.useCallback)(
|
|
15250
|
+
() => withSelectedField((_form, wrapper) => {
|
|
15251
|
+
removeField(wrapper);
|
|
15252
|
+
clearFieldPick();
|
|
15253
|
+
postToParentRef.current({ type: "ow:toast", title: "Form field deleted" });
|
|
15254
|
+
}),
|
|
15255
|
+
[clearFieldPick, withSelectedField]
|
|
15256
|
+
);
|
|
15257
|
+
const handleAddField = (0, import_react16.useCallback)(
|
|
15258
|
+
(type) => {
|
|
15259
|
+
const form = formPickElRef.current;
|
|
15260
|
+
if (!form) return;
|
|
15261
|
+
const wrapper = insertField(form, type);
|
|
15262
|
+
setFieldTypePickerOpen(false);
|
|
15263
|
+
if (!wrapper) return;
|
|
15264
|
+
persistFields(form);
|
|
15265
|
+
setFormPickRect(null);
|
|
15266
|
+
requestAnimationFrame(() => {
|
|
15267
|
+
selectField(wrapper);
|
|
15268
|
+
wrapper.scrollIntoView({ block: "nearest", behavior: "smooth" });
|
|
15269
|
+
});
|
|
15270
|
+
},
|
|
15271
|
+
[persistFields, selectField]
|
|
15272
|
+
);
|
|
15273
|
+
const fieldDragRef = (0, import_react16.useRef)(null);
|
|
15274
|
+
const handleFieldDragStart = (0, import_react16.useCallback)(() => {
|
|
15275
|
+
const wrapper = fieldPickElRef.current;
|
|
15276
|
+
const form = formPickElRef.current;
|
|
15277
|
+
if (!wrapper || !form) return;
|
|
15278
|
+
fieldDragRef.current = { key: fieldKeyOf(wrapper), form };
|
|
15279
|
+
}, []);
|
|
15280
|
+
const handleFieldDragEnd = (0, import_react16.useCallback)(() => {
|
|
15281
|
+
fieldDragRef.current = null;
|
|
15282
|
+
setFieldDropIndex(null);
|
|
15283
|
+
}, []);
|
|
15284
|
+
const [fieldDropIndex, setFieldDropIndex] = (0, import_react16.useState)(null);
|
|
15285
|
+
const clearFormPickRef = (0, import_react16.useRef)(clearFormPick);
|
|
15286
|
+
clearFormPickRef.current = clearFormPick;
|
|
15287
|
+
(0, import_react16.useEffect)(() => {
|
|
15288
|
+
const el = fieldPickElRef.current;
|
|
15289
|
+
if (!el || fieldPickRect === null) return;
|
|
15290
|
+
const observer = new ResizeObserver(() => {
|
|
15291
|
+
if (fieldPickElRef.current === el) setFieldPickRect(el.getBoundingClientRect());
|
|
15292
|
+
});
|
|
15293
|
+
observer.observe(el);
|
|
15294
|
+
return () => observer.disconnect();
|
|
15295
|
+
}, [fieldPickRect !== null, fieldPickState]);
|
|
15296
|
+
(0, import_react16.useEffect)(() => {
|
|
15297
|
+
const el = formPickElRef.current;
|
|
15298
|
+
if (!el || formPickRect === null) return;
|
|
15299
|
+
const observer = new ResizeObserver(() => {
|
|
15300
|
+
if (formPickElRef.current === el) setFormPickRect(el.getBoundingClientRect());
|
|
15301
|
+
});
|
|
15302
|
+
observer.observe(el);
|
|
15303
|
+
return () => observer.disconnect();
|
|
15304
|
+
}, [formPickRect !== null, formViewState]);
|
|
14519
15305
|
const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
|
|
14520
15306
|
const toolbarVariantRef = (0, import_react16.useRef)("none");
|
|
14521
15307
|
toolbarVariantRef.current = toolbarVariant;
|
|
@@ -14537,7 +15323,7 @@ function OhhwellsBridge() {
|
|
|
14537
15323
|
(0, import_react16.useEffect)(() => {
|
|
14538
15324
|
const sync = () => {
|
|
14539
15325
|
const el = document.querySelector(
|
|
14540
|
-
|
|
15326
|
+
'[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
|
|
14541
15327
|
);
|
|
14542
15328
|
const target = el && !el.closest("[data-ohw-href-key]") ? el : null;
|
|
14543
15329
|
if (!target) {
|
|
@@ -15669,6 +16455,7 @@ function OhhwellsBridge() {
|
|
|
15669
16455
|
setFloatingPanel(null);
|
|
15670
16456
|
setLogoSizeDraft(null);
|
|
15671
16457
|
}, []);
|
|
16458
|
+
closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
|
|
15672
16459
|
const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
|
|
15673
16460
|
setFloatingPanel(null);
|
|
15674
16461
|
setLogoSizeDraft(null);
|
|
@@ -15832,14 +16619,14 @@ function OhhwellsBridge() {
|
|
|
15832
16619
|
}
|
|
15833
16620
|
const applyContent = (content) => {
|
|
15834
16621
|
const imageLoads = [];
|
|
15835
|
-
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
15836
|
-
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
15837
|
-
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
15838
|
-
}
|
|
15839
16622
|
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
15840
16623
|
brandKitRef.current = content[BRAND_KIT_KEY];
|
|
15841
16624
|
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
15842
16625
|
}
|
|
16626
|
+
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
16627
|
+
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
16628
|
+
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
16629
|
+
}
|
|
15843
16630
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
15844
16631
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
15845
16632
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
@@ -15924,6 +16711,98 @@ function OhhwellsBridge() {
|
|
|
15924
16711
|
cancelled = true;
|
|
15925
16712
|
};
|
|
15926
16713
|
}, [subdomain, isEditMode]);
|
|
16714
|
+
(0, import_react16.useEffect)(() => {
|
|
16715
|
+
if (!isEditMode) return;
|
|
16716
|
+
const resolveIndex = (form, clientY) => {
|
|
16717
|
+
const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
|
|
16718
|
+
for (let i = 0; i < wrappers.length; i += 1) {
|
|
16719
|
+
const rect = wrappers[i].getBoundingClientRect();
|
|
16720
|
+
if (clientY < rect.top + rect.height / 2) return i;
|
|
16721
|
+
}
|
|
16722
|
+
return wrappers.length;
|
|
16723
|
+
};
|
|
16724
|
+
const onDragOver = (e) => {
|
|
16725
|
+
const session = fieldDragRef.current;
|
|
16726
|
+
if (!session) return;
|
|
16727
|
+
e.preventDefault();
|
|
16728
|
+
e.stopPropagation();
|
|
16729
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
16730
|
+
setFieldDropIndex(resolveIndex(session.form, e.clientY));
|
|
16731
|
+
};
|
|
16732
|
+
const onDrop = (e) => {
|
|
16733
|
+
const session = fieldDragRef.current;
|
|
16734
|
+
if (!session) return;
|
|
16735
|
+
e.preventDefault();
|
|
16736
|
+
e.stopPropagation();
|
|
16737
|
+
moveField(session.form, session.key, resolveIndex(session.form, e.clientY));
|
|
16738
|
+
persistFields(session.form);
|
|
16739
|
+
const moved = listFieldWrappers(session.form).find((el) => fieldKeyOf(el) === session.key);
|
|
16740
|
+
if (moved) selectField(moved);
|
|
16741
|
+
setFormPickRect(session.form.getBoundingClientRect());
|
|
16742
|
+
fieldDragRef.current = null;
|
|
16743
|
+
setFieldDropIndex(null);
|
|
16744
|
+
};
|
|
16745
|
+
window.addEventListener("dragover", onDragOver, true);
|
|
16746
|
+
window.addEventListener("drop", onDrop, true);
|
|
16747
|
+
return () => {
|
|
16748
|
+
window.removeEventListener("dragover", onDragOver, true);
|
|
16749
|
+
window.removeEventListener("drop", onDrop, true);
|
|
16750
|
+
};
|
|
16751
|
+
}, [isEditMode, persistFields, selectField]);
|
|
16752
|
+
(0, import_react16.useEffect)(() => {
|
|
16753
|
+
if (!isEditMode) return;
|
|
16754
|
+
const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
16755
|
+
markFormFields(form);
|
|
16756
|
+
});
|
|
16757
|
+
mark();
|
|
16758
|
+
const observer = new MutationObserver(() => mark());
|
|
16759
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
16760
|
+
observer.observe(form, { childList: true, subtree: true, characterData: true });
|
|
16761
|
+
});
|
|
16762
|
+
return () => observer.disconnect();
|
|
16763
|
+
}, [isEditMode, fetchState, pathname]);
|
|
16764
|
+
(0, import_react16.useEffect)(() => {
|
|
16765
|
+
if (!isEditMode) return;
|
|
16766
|
+
let saveTimer = null;
|
|
16767
|
+
const onInput = (e) => {
|
|
16768
|
+
const input = e.target;
|
|
16769
|
+
if (!input || !("value" in input)) return;
|
|
16770
|
+
const wrapper = getFieldWrapper(input);
|
|
16771
|
+
if (!wrapper || wrapper !== fieldPickElRef.current) return;
|
|
16772
|
+
if (saveTimer) clearTimeout(saveTimer);
|
|
16773
|
+
saveTimer = setTimeout(() => {
|
|
16774
|
+
const form = formPickElRef.current;
|
|
16775
|
+
if (!form) return;
|
|
16776
|
+
const previous = input.getAttribute("placeholder");
|
|
16777
|
+
input.setAttribute("placeholder", input.value);
|
|
16778
|
+
persistFields(form);
|
|
16779
|
+
input.setAttribute("placeholder", previous ?? "");
|
|
16780
|
+
}, 400);
|
|
16781
|
+
};
|
|
16782
|
+
document.addEventListener("input", onInput, true);
|
|
16783
|
+
return () => document.removeEventListener("input", onInput, true);
|
|
16784
|
+
}, [isEditMode, persistFields]);
|
|
16785
|
+
(0, import_react16.useEffect)(() => {
|
|
16786
|
+
if (isEditMode || fetchState !== "done") return;
|
|
16787
|
+
const content = contentCache.get(subdomain) ?? {};
|
|
16788
|
+
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
16789
|
+
reconcileFieldsFromContent(form, content);
|
|
16790
|
+
});
|
|
16791
|
+
}, [isEditMode, fetchState, subdomain]);
|
|
16792
|
+
(0, import_react16.useEffect)(() => {
|
|
16793
|
+
if (!isEditMode) return;
|
|
16794
|
+
const swallow = (e) => {
|
|
16795
|
+
const target = e.target;
|
|
16796
|
+
if (target && getFormElement(target)) e.preventDefault();
|
|
16797
|
+
};
|
|
16798
|
+
document.addEventListener("submit", swallow, true);
|
|
16799
|
+
return () => document.removeEventListener("submit", swallow, true);
|
|
16800
|
+
}, [isEditMode]);
|
|
16801
|
+
(0, import_react16.useEffect)(() => {
|
|
16802
|
+
if (isEditMode || fetchState !== "done") return;
|
|
16803
|
+
const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
|
|
16804
|
+
bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
|
|
16805
|
+
}, [isEditMode, fetchState, subdomain]);
|
|
15927
16806
|
(0, import_react16.useEffect)(() => {
|
|
15928
16807
|
if (!subdomain || isEditMode) return;
|
|
15929
16808
|
let debounceTimer = null;
|
|
@@ -16157,7 +17036,9 @@ function OhhwellsBridge() {
|
|
|
16157
17036
|
[style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
16158
17037
|
[style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
16159
17038
|
[style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
|
|
16160
|
-
|
|
17039
|
+
/* Not the form: it is a layout container (flex/grid with gaps), and forcing block
|
|
17040
|
+
crushed its fields together (OHH-490). */
|
|
17041
|
+
[data-ohw-editable]:not([data-ohw-editable="form"]) {
|
|
16161
17042
|
display: block;
|
|
16162
17043
|
}
|
|
16163
17044
|
/* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
|
|
@@ -16183,6 +17064,35 @@ function OhhwellsBridge() {
|
|
|
16183
17064
|
[data-ohw-editable="video"], [data-ohw-editable="video"] *,
|
|
16184
17065
|
[data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
|
|
16185
17066
|
[data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
|
|
17067
|
+
/* A form field is a design surface in the editor: its input takes the pointer so the
|
|
17068
|
+
field can be picked and hovered from anywhere inside it (OHH-642). */
|
|
17069
|
+
[data-ohw-editable="form"] [data-ohw-form-field] input,
|
|
17070
|
+
[data-ohw-editable="form"] [data-ohw-form-field] textarea,
|
|
17071
|
+
[data-ohw-editable="form"] [data-ohw-form-field] label {
|
|
17072
|
+
pointer-events: auto !important;
|
|
17073
|
+
cursor: pointer !important;
|
|
17074
|
+
}
|
|
17075
|
+
/* While a field is selected its placeholder is being written in the value, so the
|
|
17076
|
+
text reads as a placeholder rather than as an answer (OHH-642). */
|
|
17077
|
+
/* A field is a design surface here: dragging its corner resized it past the form and
|
|
17078
|
+
left the chrome behind. Height stays adjustable, width does not (OHH-642). */
|
|
17079
|
+
[data-ohw-editable="form"] [data-ohw-form-field] textarea {
|
|
17080
|
+
resize: vertical !important;
|
|
17081
|
+
max-width: 100% !important;
|
|
17082
|
+
}
|
|
17083
|
+
[data-ohw-editable="form"] [data-ohw-form-field] input,
|
|
17084
|
+
[data-ohw-editable="form"] [data-ohw-form-field] textarea {
|
|
17085
|
+
box-sizing: border-box !important;
|
|
17086
|
+
width: 100% !important;
|
|
17087
|
+
}
|
|
17088
|
+
/* Somewhere to click the block itself, on every side (OHH-642) \u2014 editor only. */
|
|
17089
|
+
[data-ohw-editable="form"] {
|
|
17090
|
+
padding: 18px !important;
|
|
17091
|
+
}
|
|
17092
|
+
[data-ohw-placeholder-edit] {
|
|
17093
|
+
color: color-mix(in srgb, currentColor 55%, transparent) !important;
|
|
17094
|
+
cursor: text !important;
|
|
17095
|
+
}
|
|
16186
17096
|
/* Text hover chrome is drawn by the overlay (see hoveredTextRect) \u2014 the CSS outline
|
|
16187
17097
|
that used to draw it dashes denser than the overlay border, so identical specs
|
|
16188
17098
|
still read as two different frames (OHH-695). The attribute stays: hover paths
|
|
@@ -16269,6 +17179,49 @@ function OhhwellsBridge() {
|
|
|
16269
17179
|
if (target.closest("[data-ohw-max-badge]")) return;
|
|
16270
17180
|
if (isInsideLinkEditor(target)) return;
|
|
16271
17181
|
if (isInsideFloatingPanel(target)) return;
|
|
17182
|
+
if (target.closest("[data-ohw-form-toolbar]")) return;
|
|
17183
|
+
if (target.closest(
|
|
17184
|
+
'[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
|
|
17185
|
+
)) {
|
|
17186
|
+
return;
|
|
17187
|
+
}
|
|
17188
|
+
{
|
|
17189
|
+
const formEl = getFormElement(target);
|
|
17190
|
+
const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
|
|
17191
|
+
if (formEl && formKeyOf(formEl) && !onSuccessText) {
|
|
17192
|
+
const fieldEl = getFieldWrapper(target);
|
|
17193
|
+
if (fieldEl) {
|
|
17194
|
+
const label = target.closest("label");
|
|
17195
|
+
if (label && fieldPickElRef.current === fieldEl) return;
|
|
17196
|
+
e.preventDefault();
|
|
17197
|
+
e.stopPropagation();
|
|
17198
|
+
deactivateRef.current();
|
|
17199
|
+
deselectRef.current();
|
|
17200
|
+
formPickElRef.current = formEl;
|
|
17201
|
+
setFormPickRect(null);
|
|
17202
|
+
selectField(fieldEl);
|
|
17203
|
+
if (!label) fieldEl.querySelector("input, textarea")?.focus();
|
|
17204
|
+
return;
|
|
17205
|
+
}
|
|
17206
|
+
clearFieldPick();
|
|
17207
|
+
e.preventDefault();
|
|
17208
|
+
e.stopPropagation();
|
|
17209
|
+
deactivateRef.current();
|
|
17210
|
+
deselectRef.current();
|
|
17211
|
+
markFormFields(formEl);
|
|
17212
|
+
formHoverElRef.current = null;
|
|
17213
|
+
setFormHoverRect(null);
|
|
17214
|
+
formPickElRef.current = formEl;
|
|
17215
|
+
setFormPickRect(formEl.getBoundingClientRect());
|
|
17216
|
+
postToParentRef.current({
|
|
17217
|
+
type: "ow:form-selected",
|
|
17218
|
+
formKey: formKeyOf(formEl),
|
|
17219
|
+
hasLongText: formHasLongText(formEl)
|
|
17220
|
+
});
|
|
17221
|
+
return;
|
|
17222
|
+
}
|
|
17223
|
+
if (!formEl && formPickElRef.current) clearFormPick();
|
|
17224
|
+
}
|
|
16272
17225
|
if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
|
|
16273
17226
|
const beneath = document.elementsFromPoint(e.clientX, e.clientY).find(
|
|
16274
17227
|
(el) => el instanceof HTMLElement && !el.closest("[data-ohw-bridge-root]") && el.closest("[data-ohw-section]") != null
|
|
@@ -16608,6 +17561,26 @@ function OhhwellsBridge() {
|
|
|
16608
17561
|
return;
|
|
16609
17562
|
}
|
|
16610
17563
|
const editable = target.closest("[data-ohw-editable]");
|
|
17564
|
+
const hoverForm = getFormElement(target);
|
|
17565
|
+
if (hoverForm) {
|
|
17566
|
+
const hoverField = getFieldWrapper(target);
|
|
17567
|
+
const hoverTarget = hoverField ?? hoverForm;
|
|
17568
|
+
const selectedHere = hoverTarget === fieldPickElRef.current || hoverTarget === formPickElRef.current;
|
|
17569
|
+
hoveredItemElRef.current = null;
|
|
17570
|
+
setHoveredItemRect(null);
|
|
17571
|
+
if (selectedHere) {
|
|
17572
|
+
formHoverElRef.current = null;
|
|
17573
|
+
setFormHoverRect(null);
|
|
17574
|
+
} else {
|
|
17575
|
+
formHoverElRef.current = hoverTarget;
|
|
17576
|
+
setFormHoverRect(hoverTarget.getBoundingClientRect());
|
|
17577
|
+
}
|
|
17578
|
+
return;
|
|
17579
|
+
}
|
|
17580
|
+
if (formHoverElRef.current) {
|
|
17581
|
+
formHoverElRef.current = null;
|
|
17582
|
+
setFormHoverRect(null);
|
|
17583
|
+
}
|
|
16611
17584
|
if (!editable) return;
|
|
16612
17585
|
const selected = selectedElRef.current;
|
|
16613
17586
|
if (selected && (selected === editable || selected.contains(editable))) return;
|
|
@@ -17244,6 +18217,13 @@ function OhhwellsBridge() {
|
|
|
17244
18217
|
setSectionGap(null);
|
|
17245
18218
|
}
|
|
17246
18219
|
};
|
|
18220
|
+
const pointOwnedByFloatingPanel = (clientX, clientY) => {
|
|
18221
|
+
if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return true;
|
|
18222
|
+
const panel = document.querySelector("[data-ohw-floating-panel]");
|
|
18223
|
+
if (!panel) return false;
|
|
18224
|
+
const rect = panel.getBoundingClientRect();
|
|
18225
|
+
return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
|
18226
|
+
};
|
|
17247
18227
|
const handleMouseMove = (e) => {
|
|
17248
18228
|
const { clientX, clientY } = e;
|
|
17249
18229
|
if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
|
|
@@ -17517,14 +18497,14 @@ function OhhwellsBridge() {
|
|
|
17517
18497
|
if (e.data?.type !== "ow:hydrate") return;
|
|
17518
18498
|
const content = e.data.content;
|
|
17519
18499
|
if (!content) return;
|
|
17520
|
-
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
17521
|
-
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
17522
|
-
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
17523
|
-
}
|
|
17524
18500
|
if (typeof content[BRAND_KIT_KEY] === "string") {
|
|
17525
18501
|
brandKitRef.current = content[BRAND_KIT_KEY];
|
|
17526
18502
|
applyBrandToDom(parseBrandKit(content[BRAND_KIT_KEY]));
|
|
17527
18503
|
}
|
|
18504
|
+
if (typeof content[AI_SECTIONS_KEY] === "string") {
|
|
18505
|
+
aiSectionsRef.current = content[AI_SECTIONS_KEY];
|
|
18506
|
+
applyAiSectionsToDom(parseAiSectionsState(content[AI_SECTIONS_KEY]));
|
|
18507
|
+
}
|
|
17528
18508
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
17529
18509
|
stylesRef.current = content[STYLE_STORE_KEY];
|
|
17530
18510
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
@@ -17809,6 +18789,13 @@ function OhhwellsBridge() {
|
|
|
17809
18789
|
}
|
|
17810
18790
|
}
|
|
17811
18791
|
};
|
|
18792
|
+
const handleFormCount = (e) => {
|
|
18793
|
+
if (e.data?.type !== "ow:form-count") return;
|
|
18794
|
+
const form = formPickElRef.current;
|
|
18795
|
+
if (!form || formKeyOf(form) !== e.data.formKey) return;
|
|
18796
|
+
setFormPickCount(typeof e.data.count === "number" ? e.data.count : null);
|
|
18797
|
+
};
|
|
18798
|
+
window.addEventListener("message", handleFormCount);
|
|
17812
18799
|
window.addEventListener("message", handleUiEscape);
|
|
17813
18800
|
const handleKeyDown = (e) => {
|
|
17814
18801
|
if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
|
|
@@ -17828,6 +18815,11 @@ function OhhwellsBridge() {
|
|
|
17828
18815
|
closeFloatingPanelOnlyRef.current();
|
|
17829
18816
|
return;
|
|
17830
18817
|
}
|
|
18818
|
+
if (e.key === "Escape" && formPickElRef.current) {
|
|
18819
|
+
e.preventDefault();
|
|
18820
|
+
clearFormPickRef.current();
|
|
18821
|
+
return;
|
|
18822
|
+
}
|
|
17831
18823
|
if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
|
|
17832
18824
|
if (toolbarVariantRef.current === "logo") {
|
|
17833
18825
|
deselectRef.current();
|
|
@@ -18380,6 +19372,7 @@ function OhhwellsBridge() {
|
|
|
18380
19372
|
window.removeEventListener("message", handleGetBrand);
|
|
18381
19373
|
window.removeEventListener("message", handleDeactivate);
|
|
18382
19374
|
window.removeEventListener("message", handleToastAction);
|
|
19375
|
+
window.removeEventListener("message", handleFormCount);
|
|
18383
19376
|
window.removeEventListener("message", handleUiEscape);
|
|
18384
19377
|
autoSaveTimers.current.forEach(clearTimeout);
|
|
18385
19378
|
autoSaveTimers.current.clear();
|
|
@@ -18403,7 +19396,9 @@ function OhhwellsBridge() {
|
|
|
18403
19396
|
if (footerDragRef.current) return;
|
|
18404
19397
|
const target = e.target;
|
|
18405
19398
|
if (!target) return;
|
|
18406
|
-
if (target.closest(
|
|
19399
|
+
if (target.closest(
|
|
19400
|
+
'[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"]'
|
|
19401
|
+
)) {
|
|
18407
19402
|
return;
|
|
18408
19403
|
}
|
|
18409
19404
|
if (target.closest("[data-ohw-item-drag-surface]")) return;
|
|
@@ -18581,7 +19576,7 @@ function OhhwellsBridge() {
|
|
|
18581
19576
|
postToParent2({
|
|
18582
19577
|
type: "ow:ready",
|
|
18583
19578
|
version: "1",
|
|
18584
|
-
bridgeVersion: "0.1.
|
|
19579
|
+
bridgeVersion: "0.1.65",
|
|
18585
19580
|
path: pathname,
|
|
18586
19581
|
nodes: collectEditableNodes(editContentRef.current),
|
|
18587
19582
|
sections
|
|
@@ -18976,10 +19971,10 @@ function OhhwellsBridge() {
|
|
|
18976
19971
|
[postToParent2]
|
|
18977
19972
|
);
|
|
18978
19973
|
return bridgeRoot ? (0, import_react_dom4.createPortal)(
|
|
18979
|
-
/* @__PURE__ */ (0,
|
|
18980
|
-
/* @__PURE__ */ (0,
|
|
18981
|
-
isEditMode && /* @__PURE__ */ (0,
|
|
18982
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0,
|
|
19974
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
19975
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
19976
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
|
|
19977
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
18983
19978
|
MediaOverlay,
|
|
18984
19979
|
{
|
|
18985
19980
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -18990,7 +19985,7 @@ function OhhwellsBridge() {
|
|
|
18990
19985
|
},
|
|
18991
19986
|
`uploading-${key}`
|
|
18992
19987
|
)),
|
|
18993
|
-
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0,
|
|
19988
|
+
mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
18994
19989
|
MediaOverlay,
|
|
18995
19990
|
{
|
|
18996
19991
|
hover: mediaHover,
|
|
@@ -18999,11 +19994,11 @@ function OhhwellsBridge() {
|
|
|
18999
19994
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
19000
19995
|
}
|
|
19001
19996
|
),
|
|
19002
|
-
carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0,
|
|
19003
|
-
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0,
|
|
19004
|
-
siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0,
|
|
19005
|
-
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0,
|
|
19006
|
-
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0,
|
|
19997
|
+
carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
|
|
19998
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
19999
|
+
siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
20000
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
20001
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19007
20002
|
"div",
|
|
19008
20003
|
{
|
|
19009
20004
|
className: "pointer-events-none fixed z-2147483646",
|
|
@@ -19013,7 +20008,7 @@ function OhhwellsBridge() {
|
|
|
19013
20008
|
width: slot.width,
|
|
19014
20009
|
height: slot.height
|
|
19015
20010
|
},
|
|
19016
|
-
children: /* @__PURE__ */ (0,
|
|
20011
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19017
20012
|
DropIndicator,
|
|
19018
20013
|
{
|
|
19019
20014
|
direction: slot.direction,
|
|
@@ -19024,7 +20019,7 @@ function OhhwellsBridge() {
|
|
|
19024
20019
|
},
|
|
19025
20020
|
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
19026
20021
|
)),
|
|
19027
|
-
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0,
|
|
20022
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19028
20023
|
"div",
|
|
19029
20024
|
{
|
|
19030
20025
|
className: "pointer-events-none fixed z-2147483646",
|
|
@@ -19034,7 +20029,7 @@ function OhhwellsBridge() {
|
|
|
19034
20029
|
width: slot.width,
|
|
19035
20030
|
height: slot.height
|
|
19036
20031
|
},
|
|
19037
|
-
children: /* @__PURE__ */ (0,
|
|
20032
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19038
20033
|
DropIndicator,
|
|
19039
20034
|
{
|
|
19040
20035
|
direction: slot.direction,
|
|
@@ -19045,11 +20040,179 @@ function OhhwellsBridge() {
|
|
|
19045
20040
|
},
|
|
19046
20041
|
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
19047
20042
|
)),
|
|
19048
|
-
hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0,
|
|
19049
|
-
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0,
|
|
19050
|
-
hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0,
|
|
19051
|
-
|
|
19052
|
-
|
|
20043
|
+
hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
20044
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
20045
|
+
hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
|
|
20046
|
+
formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20047
|
+
ItemInteractionLayer,
|
|
20048
|
+
{
|
|
20049
|
+
rect: formPickRect,
|
|
20050
|
+
state: "active-top",
|
|
20051
|
+
itemDragSurface: false,
|
|
20052
|
+
toolbarAlign: "left",
|
|
20053
|
+
chromeGap: 24,
|
|
20054
|
+
toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
20055
|
+
"div",
|
|
20056
|
+
{
|
|
20057
|
+
"data-ohw-form-toolbar": "",
|
|
20058
|
+
className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
|
|
20059
|
+
children: [
|
|
20060
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20061
|
+
"button",
|
|
20062
|
+
{
|
|
20063
|
+
type: "button",
|
|
20064
|
+
"aria-label": "Add field",
|
|
20065
|
+
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
|
|
20066
|
+
onClick: () => setFieldTypePickerOpen((open) => !open),
|
|
20067
|
+
"data-ohw-add-field": "",
|
|
20068
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Plus, { size: 15, "aria-hidden": true })
|
|
20069
|
+
}
|
|
20070
|
+
),
|
|
20071
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
20072
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
20073
|
+
"button",
|
|
20074
|
+
{
|
|
20075
|
+
type: "button",
|
|
20076
|
+
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",
|
|
20077
|
+
onClick: () => {
|
|
20078
|
+
const form = formPickElRef.current;
|
|
20079
|
+
if (!form) return;
|
|
20080
|
+
postToParent2({
|
|
20081
|
+
type: "ow:form-pick",
|
|
20082
|
+
formKey: formKeyOf(form),
|
|
20083
|
+
hasLongText: formHasLongText(form)
|
|
20084
|
+
});
|
|
20085
|
+
},
|
|
20086
|
+
children: [
|
|
20087
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Settings, { size: 14, "aria-hidden": true }),
|
|
20088
|
+
"Form settings",
|
|
20089
|
+
formPickCount ? (
|
|
20090
|
+
// Counter pill, per the design — not a text suffix.
|
|
20091
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20092
|
+
"span",
|
|
20093
|
+
{
|
|
20094
|
+
"data-ohw-form-count": "",
|
|
20095
|
+
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",
|
|
20096
|
+
children: formPickCount
|
|
20097
|
+
}
|
|
20098
|
+
)
|
|
20099
|
+
) : null
|
|
20100
|
+
]
|
|
20101
|
+
}
|
|
20102
|
+
),
|
|
20103
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
20104
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
20105
|
+
"button",
|
|
20106
|
+
{
|
|
20107
|
+
type: "button",
|
|
20108
|
+
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",
|
|
20109
|
+
onClick: () => {
|
|
20110
|
+
const form = formPickElRef.current;
|
|
20111
|
+
if (!form) return;
|
|
20112
|
+
postToParent2({
|
|
20113
|
+
type: "ow:form-submissions",
|
|
20114
|
+
formKey: formKeyOf(form),
|
|
20115
|
+
hasLongText: formHasLongText(form)
|
|
20116
|
+
});
|
|
20117
|
+
},
|
|
20118
|
+
"data-ohw-view-submissions": "",
|
|
20119
|
+
children: [
|
|
20120
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Table, { size: 14, "aria-hidden": true }),
|
|
20121
|
+
"View submissions"
|
|
20122
|
+
]
|
|
20123
|
+
}
|
|
20124
|
+
),
|
|
20125
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
20126
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20127
|
+
"button",
|
|
20128
|
+
{
|
|
20129
|
+
type: "button",
|
|
20130
|
+
"aria-pressed": formViewState === state,
|
|
20131
|
+
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"),
|
|
20132
|
+
onClick: () => {
|
|
20133
|
+
const form = formPickElRef.current;
|
|
20134
|
+
const key = form ? formKeyOf(form) : null;
|
|
20135
|
+
if (!form || !key) return;
|
|
20136
|
+
const initial = editContentRef.current[formSuccessKey(key)] ?? DEFAULT_SUCCESS_TEXT;
|
|
20137
|
+
setFormViewState(form, key, state, initial);
|
|
20138
|
+
setFormViewStateUi(state);
|
|
20139
|
+
setFormPickRect(form.getBoundingClientRect());
|
|
20140
|
+
if (state === "success") {
|
|
20141
|
+
const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
|
|
20142
|
+
if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
|
|
20143
|
+
} else {
|
|
20144
|
+
deactivateRef.current();
|
|
20145
|
+
}
|
|
20146
|
+
},
|
|
20147
|
+
children: state
|
|
20148
|
+
},
|
|
20149
|
+
state
|
|
20150
|
+
)) })
|
|
20151
|
+
]
|
|
20152
|
+
}
|
|
20153
|
+
)
|
|
20154
|
+
}
|
|
20155
|
+
),
|
|
20156
|
+
formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20157
|
+
ItemInteractionLayer,
|
|
20158
|
+
{
|
|
20159
|
+
rect: formHoverRect,
|
|
20160
|
+
state: "hover",
|
|
20161
|
+
chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
|
|
20162
|
+
}
|
|
20163
|
+
),
|
|
20164
|
+
fieldPickRect && fieldPickState && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20165
|
+
ItemInteractionLayer,
|
|
20166
|
+
{
|
|
20167
|
+
rect: fieldPickRect,
|
|
20168
|
+
state: "active-top",
|
|
20169
|
+
itemDragSurface: false,
|
|
20170
|
+
toolbarAlign: "left",
|
|
20171
|
+
chromeGap: 10,
|
|
20172
|
+
showHandle: true,
|
|
20173
|
+
dragHandleLabel: "Reorder field",
|
|
20174
|
+
onDragHandleDragStart: handleFieldDragStart,
|
|
20175
|
+
onDragHandleDragEnd: handleFieldDragEnd,
|
|
20176
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20177
|
+
FormFieldToolbar,
|
|
20178
|
+
{
|
|
20179
|
+
type: fieldPickState.type,
|
|
20180
|
+
required: fieldPickState.required,
|
|
20181
|
+
onTypeChange: handleFieldTypeChange,
|
|
20182
|
+
onRequiredToggle: handleFieldRequiredToggle,
|
|
20183
|
+
onDuplicate: handleFieldDuplicate,
|
|
20184
|
+
onDelete: handleFieldDelete
|
|
20185
|
+
}
|
|
20186
|
+
)
|
|
20187
|
+
}
|
|
20188
|
+
),
|
|
20189
|
+
fieldDropIndex !== null && formPickElRef.current ? (() => {
|
|
20190
|
+
const wrappers = listFieldWrappers(formPickElRef.current).filter(
|
|
20191
|
+
(el) => fieldKeyOf(el) !== fieldDragRef.current?.key
|
|
20192
|
+
);
|
|
20193
|
+
const anchor = wrappers[Math.min(fieldDropIndex, wrappers.length - 1)];
|
|
20194
|
+
if (!anchor) return null;
|
|
20195
|
+
const rect = anchor.getBoundingClientRect();
|
|
20196
|
+
const atEnd = fieldDropIndex >= wrappers.length;
|
|
20197
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20198
|
+
"div",
|
|
20199
|
+
{
|
|
20200
|
+
className: "pointer-events-none fixed z-[2147483644]",
|
|
20201
|
+
style: { top: atEnd ? rect.bottom : rect.top, left: rect.left, width: rect.width },
|
|
20202
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DropIndicator, { direction: "horizontal", state: "dragActive" })
|
|
20203
|
+
}
|
|
20204
|
+
);
|
|
20205
|
+
})() : null,
|
|
20206
|
+
fieldTypePickerOpen && formPickRect && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
20207
|
+
"div",
|
|
20208
|
+
{
|
|
20209
|
+
className: "pointer-events-none fixed z-[2147483645]",
|
|
20210
|
+
style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
|
|
20211
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(FieldTypePicker, { onPick: handleAddField })
|
|
20212
|
+
}
|
|
20213
|
+
),
|
|
20214
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
20215
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19053
20216
|
FooterContainerChrome,
|
|
19054
20217
|
{
|
|
19055
20218
|
rect: toolbarRect,
|
|
@@ -19057,7 +20220,7 @@ function OhhwellsBridge() {
|
|
|
19057
20220
|
addDisabled: !canAddFooterColumn()
|
|
19058
20221
|
}
|
|
19059
20222
|
),
|
|
19060
|
-
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0,
|
|
20223
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19061
20224
|
ItemInteractionLayer,
|
|
19062
20225
|
{
|
|
19063
20226
|
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
@@ -19072,7 +20235,7 @@ function OhhwellsBridge() {
|
|
|
19072
20235
|
onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
|
|
19073
20236
|
onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
|
|
19074
20237
|
itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
|
|
19075
|
-
toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0,
|
|
20238
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19076
20239
|
ItemActionToolbar,
|
|
19077
20240
|
{
|
|
19078
20241
|
onEditLink: openLinkPopoverForSelected,
|
|
@@ -19108,8 +20271,8 @@ function OhhwellsBridge() {
|
|
|
19108
20271
|
) : void 0
|
|
19109
20272
|
}
|
|
19110
20273
|
),
|
|
19111
|
-
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0,
|
|
19112
|
-
/* @__PURE__ */ (0,
|
|
20274
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
|
|
20275
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19113
20276
|
EditGlowChrome,
|
|
19114
20277
|
{
|
|
19115
20278
|
rect: toolbarRect,
|
|
@@ -19119,7 +20282,7 @@ function OhhwellsBridge() {
|
|
|
19119
20282
|
hideHandle: isItemDragging
|
|
19120
20283
|
}
|
|
19121
20284
|
),
|
|
19122
|
-
/* @__PURE__ */ (0,
|
|
20285
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19123
20286
|
FloatingToolbar,
|
|
19124
20287
|
{
|
|
19125
20288
|
rect: toolbarRect,
|
|
@@ -19132,7 +20295,7 @@ function OhhwellsBridge() {
|
|
|
19132
20295
|
}
|
|
19133
20296
|
)
|
|
19134
20297
|
] }),
|
|
19135
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
20298
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
19136
20299
|
"div",
|
|
19137
20300
|
{
|
|
19138
20301
|
"data-ohw-max-badge": "",
|
|
@@ -19158,7 +20321,7 @@ function OhhwellsBridge() {
|
|
|
19158
20321
|
]
|
|
19159
20322
|
}
|
|
19160
20323
|
),
|
|
19161
|
-
toggleState && !linkPopover && /* @__PURE__ */ (0,
|
|
20324
|
+
toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19162
20325
|
StateToggle,
|
|
19163
20326
|
{
|
|
19164
20327
|
rect: toggleState.rect,
|
|
@@ -19167,15 +20330,15 @@ function OhhwellsBridge() {
|
|
|
19167
20330
|
onStateChange: handleStateChange
|
|
19168
20331
|
}
|
|
19169
20332
|
),
|
|
19170
|
-
sectionGap && !linkPopover && /* @__PURE__ */ (0,
|
|
20333
|
+
sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
19171
20334
|
"div",
|
|
19172
20335
|
{
|
|
19173
20336
|
"data-ohw-section-insert-line": "",
|
|
19174
20337
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
19175
20338
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
19176
20339
|
children: [
|
|
19177
|
-
/* @__PURE__ */ (0,
|
|
19178
|
-
/* @__PURE__ */ (0,
|
|
20340
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
|
|
20341
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19179
20342
|
Badge,
|
|
19180
20343
|
{
|
|
19181
20344
|
className: "px-8 py-1 bg-primary hover:bg-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
@@ -19192,11 +20355,11 @@ function OhhwellsBridge() {
|
|
|
19192
20355
|
children: "Add Section"
|
|
19193
20356
|
}
|
|
19194
20357
|
),
|
|
19195
|
-
/* @__PURE__ */ (0,
|
|
20358
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
|
|
19196
20359
|
]
|
|
19197
20360
|
}
|
|
19198
20361
|
),
|
|
19199
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0,
|
|
20362
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19200
20363
|
LinkPopover,
|
|
19201
20364
|
{
|
|
19202
20365
|
panelRef: linkPopoverPanelRef,
|
|
@@ -19213,7 +20376,7 @@ function OhhwellsBridge() {
|
|
|
19213
20376
|
},
|
|
19214
20377
|
linkPopover.key
|
|
19215
20378
|
) : null,
|
|
19216
|
-
floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0,
|
|
20379
|
+
floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19217
20380
|
FloatingPanel,
|
|
19218
20381
|
{
|
|
19219
20382
|
open: true,
|
|
@@ -19223,7 +20386,7 @@ function OhhwellsBridge() {
|
|
|
19223
20386
|
onPositionChange: setFloatingPanelPos,
|
|
19224
20387
|
parentScroll: parentScrollSnap ?? parentScrollRef.current,
|
|
19225
20388
|
onClose: closeFloatingPanelOnly,
|
|
19226
|
-
children: /* @__PURE__ */ (0,
|
|
20389
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19227
20390
|
SocialsDisplayPanel,
|
|
19228
20391
|
{
|
|
19229
20392
|
display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
|
|
@@ -19235,7 +20398,7 @@ function OhhwellsBridge() {
|
|
|
19235
20398
|
)
|
|
19236
20399
|
}
|
|
19237
20400
|
) : null,
|
|
19238
|
-
floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ (0,
|
|
20401
|
+
floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19239
20402
|
FloatingPanel,
|
|
19240
20403
|
{
|
|
19241
20404
|
open: true,
|
|
@@ -19245,7 +20408,7 @@ function OhhwellsBridge() {
|
|
|
19245
20408
|
onPositionChange: setFloatingPanelPos,
|
|
19246
20409
|
parentScroll: parentScrollSnap ?? parentScrollRef.current,
|
|
19247
20410
|
onClose: closeFloatingPanelAndDeselect,
|
|
19248
|
-
children: /* @__PURE__ */ (0,
|
|
20411
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
19249
20412
|
LogoSizePanel,
|
|
19250
20413
|
{
|
|
19251
20414
|
viewport: editorViewport,
|
|
@@ -19293,10 +20456,10 @@ function OhhwellsBridge() {
|
|
|
19293
20456
|
|
|
19294
20457
|
// src/ui/EmptySection.tsx
|
|
19295
20458
|
var import_link = __toESM(require("next/link"), 1);
|
|
19296
|
-
var
|
|
20459
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
19297
20460
|
function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
|
|
19298
|
-
return /* @__PURE__ */ (0,
|
|
19299
|
-
/* @__PURE__ */ (0,
|
|
20461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
20462
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
19300
20463
|
"p",
|
|
19301
20464
|
{
|
|
19302
20465
|
style: {
|
|
@@ -19308,10 +20471,10 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
19308
20471
|
color: "var(--brand-accent)",
|
|
19309
20472
|
marginBottom: "1.5rem"
|
|
19310
20473
|
},
|
|
19311
|
-
children: /* @__PURE__ */ (0,
|
|
20474
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
|
|
19312
20475
|
}
|
|
19313
20476
|
),
|
|
19314
|
-
/* @__PURE__ */ (0,
|
|
20477
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
19315
20478
|
"h1",
|
|
19316
20479
|
{
|
|
19317
20480
|
style: {
|
|
@@ -19326,7 +20489,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
|
|
|
19326
20489
|
children: title
|
|
19327
20490
|
}
|
|
19328
20491
|
),
|
|
19329
|
-
/* @__PURE__ */ (0,
|
|
20492
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
19330
20493
|
"p",
|
|
19331
20494
|
{
|
|
19332
20495
|
style: {
|