@ohhwells/bridge 0.1.63-next.175 → 0.1.64-next.177

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 CHANGED
@@ -252,7 +252,10 @@ var BRAND_VAR_PREFIX = "--ohw-brand-";
252
252
  var BRAND_VAR_NAMES = ["primary", "accent", "light", "dark", "surface", "border", "muted"].map(
253
253
  (role) => `${BRAND_VAR_PREFIX}${role}`
254
254
  );
255
- var FONT_VARS = { heading: ["--font-heading", "--font-display"], body: ["--font-body"] };
255
+ var FONT_VARS = {
256
+ heading: ["--font-heading", "--font-display", "--brand-font-heading"],
257
+ body: ["--font-body", "--brand-font-body"]
258
+ };
256
259
  var BRAND_FONT_LINK_ID = "ohw-brand-fonts";
257
260
  function brandColorVars(kit) {
258
261
  const { dark, primary, accent, light } = kit.palette;
@@ -6586,6 +6589,7 @@ function getChromeStyle(state) {
6586
6589
  }
6587
6590
  function ClampedToolbarSlot({
6588
6591
  placement,
6592
+ align = "center",
6589
6593
  children
6590
6594
  }) {
6591
6595
  const slotRef = (0, import_react7.useRef)(null);
@@ -6607,7 +6611,7 @@ function ClampedToolbarSlot({
6607
6611
  Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN - half)
6608
6612
  );
6609
6613
  const offsetX = clampedCenter - centerX;
6610
- slot.style.transform = `translateX(calc(-50% + ${offsetX}px))`;
6614
+ slot.style.transform = align === "left" ? "none" : `translateX(calc(-50% + ${offsetX}px))`;
6611
6615
  };
6612
6616
  clamp();
6613
6617
  const ro = new ResizeObserver(clamp);
@@ -6618,19 +6622,20 @@ function ClampedToolbarSlot({
6618
6622
  ro.disconnect();
6619
6623
  window.removeEventListener("resize", clamp);
6620
6624
  };
6621
- }, [placement, children]);
6625
+ }, [placement, children, align]);
6622
6626
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6623
6627
  "div",
6624
6628
  {
6625
6629
  ref: slotRef,
6626
6630
  className: cn(
6627
- "pointer-events-auto absolute left-1/2",
6631
+ "pointer-events-auto absolute",
6632
+ align === "left" ? "left-0" : "left-1/2",
6628
6633
  placement === "top" ? "bottom-full" : "top-full"
6629
6634
  ),
6630
6635
  style: {
6631
6636
  marginBottom: placement === "top" ? TOOLBAR_STROKE_GAP : void 0,
6632
6637
  marginTop: placement === "bottom" ? TOOLBAR_STROKE_GAP : void 0,
6633
- transform: "translateX(-50%)"
6638
+ transform: align === "left" ? "none" : "translateX(-50%)"
6634
6639
  },
6635
6640
  "data-ohw-item-toolbar-anchor": placement,
6636
6641
  children
@@ -6699,6 +6704,7 @@ function ItemInteractionLayer({
6699
6704
  onItemClick,
6700
6705
  itemDragSurface = true,
6701
6706
  chromeGap,
6707
+ toolbarAlign = "center",
6702
6708
  className
6703
6709
  }) {
6704
6710
  if (state === "default") return null;
@@ -6786,8 +6792,8 @@ function ItemInteractionLayer({
6786
6792
  )
6787
6793
  }
6788
6794
  ),
6789
- showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { placement: "top", children: toolbar }),
6790
- showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { placement: "bottom", children: toolbar }),
6795
+ showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { align: toolbarAlign, placement: "top", children: toolbar }),
6796
+ showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { align: toolbarAlign, placement: "bottom", children: toolbar }),
6791
6797
  useDetachedBelowToolbar && toolbarBelowRect ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6792
6798
  DetachedBelowToolbarSlot,
6793
6799
  {
@@ -6801,14 +6807,580 @@ function ItemInteractionLayer({
6801
6807
  );
6802
6808
  }
6803
6809
 
6810
+ // src/lib/forms.ts
6811
+ var FORM_SELECTOR = '[data-ohw-editable="form"]';
6812
+ function getFormElement(el) {
6813
+ if (!el) return null;
6814
+ return el.closest(FORM_SELECTOR);
6815
+ }
6816
+ function formKeyOf(form) {
6817
+ return form.getAttribute("data-ohw-key");
6818
+ }
6819
+ function formHasLongText(form) {
6820
+ return form.querySelector("textarea") !== null;
6821
+ }
6822
+ function collectFormFields(form) {
6823
+ const fields = {};
6824
+ form.querySelectorAll(
6825
+ "input, textarea, select"
6826
+ ).forEach((input) => {
6827
+ const type = input.type;
6828
+ if (type === "submit" || type === "button" || type === "reset") return;
6829
+ const key = input.getAttribute("name") ?? input.getAttribute("data-ohw-key");
6830
+ if (!key) return;
6831
+ if (type === "checkbox") {
6832
+ fields[key] = input.checked ? "yes" : "no";
6833
+ return;
6834
+ }
6835
+ fields[key] = input.value;
6836
+ });
6837
+ return fields;
6838
+ }
6839
+ function formStateContainer(form) {
6840
+ return form.closest("[data-ohw-editable-state]") ?? form.parentElement ?? form;
6841
+ }
6842
+ function showSuccess(form, message) {
6843
+ const container = formStateContainer(form);
6844
+ const views = container.querySelectorAll("[data-ohw-state-view]");
6845
+ if (views.length > 0) {
6846
+ views.forEach((view) => {
6847
+ view.style.display = view.getAttribute("data-ohw-state-view") === "success" ? "block" : "none";
6848
+ });
6849
+ return;
6850
+ }
6851
+ const text = message ?? form.getAttribute("data-ohw-success-text") ?? DEFAULT_SUCCESS_TEXT;
6852
+ const note = document.createElement("p");
6853
+ note.setAttribute("data-ohw-form-success", "");
6854
+ note.setAttribute("role", "status");
6855
+ note.innerHTML = text;
6856
+ form.replaceChildren(note);
6857
+ }
6858
+ function showSubmitError(form) {
6859
+ let note = form.querySelector("[data-ohw-form-error]");
6860
+ if (!note) {
6861
+ note = document.createElement("p");
6862
+ note.setAttribute("data-ohw-form-error", "");
6863
+ note.setAttribute("role", "alert");
6864
+ note.style.marginTop = "8px";
6865
+ form.appendChild(note);
6866
+ }
6867
+ note.textContent = "Something went wrong. Please try again.";
6868
+ note.style.display = "";
6869
+ }
6870
+ function clearSubmitError(form) {
6871
+ const note = form.querySelector("[data-ohw-form-error]");
6872
+ if (note) note.style.display = "none";
6873
+ }
6874
+ var SUCCESS_TEXT_ATTR = "data-ohw-form-success-text";
6875
+ var HIDDEN_ATTR = "data-ohw-form-hidden";
6876
+ var DEFAULT_SUCCESS_TEXT = "Thanks! We'll be in touch.";
6877
+ function formSuccessKey(formKey) {
6878
+ return `${formKey}-success`;
6879
+ }
6880
+ function ensureSuccessTextEl(form, formKey, initialText) {
6881
+ let el = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
6882
+ if (el) return el;
6883
+ el = document.createElement("p");
6884
+ el.setAttribute(SUCCESS_TEXT_ATTR, "");
6885
+ el.setAttribute("data-ohw-editable", "text");
6886
+ el.setAttribute("data-ohw-key", formSuccessKey(formKey));
6887
+ el.innerHTML = initialText;
6888
+ el.style.display = "none";
6889
+ el.style.margin = "56px 4px 16px";
6890
+ form.appendChild(el);
6891
+ return el;
6892
+ }
6893
+ function setFormViewState(form, formKey, state, initialText) {
6894
+ const success = ensureSuccessTextEl(form, formKey, initialText);
6895
+ Array.from(form.children).forEach((child) => {
6896
+ if (!(child instanceof HTMLElement) || child === success) return;
6897
+ if (state === "success") {
6898
+ if (!child.hasAttribute(HIDDEN_ATTR)) {
6899
+ child.setAttribute(HIDDEN_ATTR, child.style.display);
6900
+ child.style.display = "none";
6901
+ }
6902
+ } else if (child.hasAttribute(HIDDEN_ATTR)) {
6903
+ child.style.display = child.getAttribute(HIDDEN_ATTR) ?? "";
6904
+ child.removeAttribute(HIDDEN_ATTR);
6905
+ }
6906
+ });
6907
+ success.style.display = state === "success" ? "" : "none";
6908
+ }
6909
+ var BOUND_ATTR = "data-ohw-form-bound";
6910
+ function bindPublishedForms(apiUrl, subdomain, content = {}) {
6911
+ document.querySelectorAll(FORM_SELECTOR).forEach((form) => {
6912
+ if (form.hasAttribute(BOUND_ATTR)) return;
6913
+ if (!(form instanceof HTMLFormElement)) return;
6914
+ const formKey = formKeyOf(form);
6915
+ if (!formKey) return;
6916
+ form.setAttribute(BOUND_ATTR, "");
6917
+ form.addEventListener("submit", async (e) => {
6918
+ e.preventDefault();
6919
+ clearSubmitError(form);
6920
+ const submitButton = form.querySelector(
6921
+ 'button[type="submit"], input[type="submit"], button:not([type])'
6922
+ );
6923
+ if (submitButton) submitButton.disabled = true;
6924
+ try {
6925
+ const response = await fetch(`${apiUrl}/api/public/sites/${subdomain}/forms/submissions`, {
6926
+ method: "POST",
6927
+ headers: { "Content-Type": "application/json" },
6928
+ body: JSON.stringify({
6929
+ formKey,
6930
+ fields: collectFormFields(form),
6931
+ hasLongText: formHasLongText(form)
6932
+ })
6933
+ });
6934
+ if (!response.ok) throw new Error(`submit failed: ${response.status}`);
6935
+ showSuccess(form, content[formSuccessKey(formKey)]);
6936
+ } catch {
6937
+ showSubmitError(form);
6938
+ if (submitButton) submitButton.disabled = false;
6939
+ }
6940
+ });
6941
+ });
6942
+ }
6943
+
6944
+ // src/lib/form-fields.ts
6945
+ var FIELD_DEFAULTS = {
6946
+ "short-text": { label: "Short text", placeholder: "Type placeholder text..." },
6947
+ "long-text": { label: "Long text", placeholder: "How can we help?" },
6948
+ email: { label: "Email", placeholder: "hello@example.com" },
6949
+ phone: { label: "Phone number", placeholder: "(555) 000-0000" }
6950
+ };
6951
+ var FIELD_TYPES = [
6952
+ { type: "short-text", label: "Short text" },
6953
+ { type: "long-text", label: "Long text" },
6954
+ { type: "email", label: "Email" },
6955
+ { type: "phone", label: "Phone" }
6956
+ ];
6957
+ var FIELD_ATTR = "data-ohw-form-field";
6958
+ var FIELD_TYPE_ATTR = "data-ohw-field-type";
6959
+ function fieldsKey(formKey) {
6960
+ return `${formKey}-fields`;
6961
+ }
6962
+ function inputTagFor(type) {
6963
+ if (type === "long-text") return { tag: "textarea" };
6964
+ if (type === "email") return { tag: "input", inputType: "email" };
6965
+ if (type === "phone") return { tag: "input", inputType: "tel" };
6966
+ return { tag: "input", inputType: "text" };
6967
+ }
6968
+ function inferType(input) {
6969
+ if (input.tagName === "TEXTAREA") return "long-text";
6970
+ const type = input.type;
6971
+ if (type === "email") return "email";
6972
+ if (type === "tel") return "phone";
6973
+ return "short-text";
6974
+ }
6975
+ function ensureFieldLabel(wrapper, key) {
6976
+ const existing = fieldLabelOf(wrapper);
6977
+ if (existing) {
6978
+ if (!existing.hasAttribute("data-ohw-editable")) {
6979
+ existing.setAttribute("data-ohw-editable", "text");
6980
+ existing.setAttribute("data-ohw-key", `${key}-label`);
6981
+ }
6982
+ return existing;
6983
+ }
6984
+ const input = fieldInputOf(wrapper);
6985
+ const label = document.createElement("label");
6986
+ label.setAttribute("data-ohw-editable", "text");
6987
+ label.setAttribute("data-ohw-key", `${key}-label`);
6988
+ label.setAttribute("data-ohw-field-label", "");
6989
+ label.style.display = "block";
6990
+ label.style.marginBottom = "6px";
6991
+ label.style.fontSize = "13px";
6992
+ label.style.fontWeight = "500";
6993
+ label.style.lineHeight = "1.3";
6994
+ const fromPlaceholder = input?.getAttribute("placeholder")?.trim();
6995
+ const text = fromPlaceholder && fromPlaceholder.length < 40 ? fromPlaceholder : key.replace(/[-_]/g, " ");
6996
+ label.textContent = input?.hasAttribute("required") ? `${text} *` : text;
6997
+ if (input && input.parentElement === wrapper) wrapper.insertBefore(label, input);
6998
+ else wrapper.insertBefore(label, wrapper.firstChild);
6999
+ return label;
7000
+ }
7001
+ function listFieldWrappers(form) {
7002
+ return Array.from(form.querySelectorAll(`[${FIELD_ATTR}]`));
7003
+ }
7004
+ function getFieldWrapper(el) {
7005
+ return el?.closest(`[${FIELD_ATTR}]`) ?? null;
7006
+ }
7007
+ function fieldInputOf(wrapper) {
7008
+ return wrapper.querySelector("input, textarea");
7009
+ }
7010
+ function fieldLabelOf(wrapper) {
7011
+ return wrapper.querySelector("label");
7012
+ }
7013
+ function fieldKeyOf(wrapper) {
7014
+ return wrapper.getAttribute(FIELD_ATTR) ?? "";
7015
+ }
7016
+ function fieldTypeOf(wrapper) {
7017
+ return wrapper.getAttribute(FIELD_TYPE_ATTR) ?? "short-text";
7018
+ }
7019
+ function isFieldRequired(wrapper) {
7020
+ return fieldInputOf(wrapper)?.hasAttribute("required") ?? false;
7021
+ }
7022
+ function markFormFields(form) {
7023
+ form.querySelectorAll("input, textarea").forEach((input) => {
7024
+ const type = input.type;
7025
+ if (type === "submit" || type === "button" || type === "reset" || type === "hidden") return;
7026
+ if (getFieldWrapper(input)) return;
7027
+ let wrapper = input;
7028
+ while (wrapper.parentElement && wrapper.parentElement !== form && wrapper.parentElement.querySelectorAll("input, textarea").length === 1) {
7029
+ wrapper = wrapper.parentElement;
7030
+ }
7031
+ if (wrapper === input) {
7032
+ const box = document.createElement("div");
7033
+ box.setAttribute("data-ohw-field-box", "");
7034
+ input.replaceWith(box);
7035
+ box.appendChild(input);
7036
+ wrapper = box;
7037
+ }
7038
+ const key = input.getAttribute("name") ?? input.getAttribute("data-ohw-key") ?? `field-${Date.now()}`;
7039
+ wrapper.setAttribute(FIELD_ATTR, key);
7040
+ wrapper.setAttribute(FIELD_TYPE_ATTR, inferType(input));
7041
+ ensureFieldLabel(wrapper, key);
7042
+ syncRequiredMark(wrapper);
7043
+ });
7044
+ return listFieldWrappers(form);
7045
+ }
7046
+ function readFieldsFromDom(form) {
7047
+ return listFieldWrappers(form).map((wrapper) => {
7048
+ const input = fieldInputOf(wrapper);
7049
+ return {
7050
+ key: fieldKeyOf(wrapper),
7051
+ type: fieldTypeOf(wrapper),
7052
+ label: fieldLabelOf(wrapper)?.textContent?.trim() ?? "",
7053
+ placeholder: input?.getAttribute("placeholder") ?? "",
7054
+ required: Boolean(input?.hasAttribute("required"))
7055
+ };
7056
+ });
7057
+ }
7058
+ function parseFieldSpecs(raw) {
7059
+ if (!raw) return null;
7060
+ try {
7061
+ const parsed = JSON.parse(raw);
7062
+ return Array.isArray(parsed) ? parsed : null;
7063
+ } catch {
7064
+ return null;
7065
+ }
7066
+ }
7067
+ function isDefaultText(value, pick) {
7068
+ const trimmed = value.trim().replace(/\s*\*$/, "");
7069
+ if (!trimmed) return true;
7070
+ return Object.values(FIELD_DEFAULTS).some((defaults) => pick(defaults) === trimmed);
7071
+ }
7072
+ function applyFieldType(wrapper, type) {
7073
+ const input = fieldInputOf(wrapper);
7074
+ if (!input) return;
7075
+ const defaults = FIELD_DEFAULTS[type];
7076
+ const placeholder = input.getAttribute("placeholder") ?? "";
7077
+ const label = fieldLabelOf(wrapper);
7078
+ const followsDefaults = {
7079
+ // A label the owner wrote stays; one that still reads as a type name (or as the old
7080
+ // placeholder the template shipped) follows the new type.
7081
+ label: isDefaultText(label?.textContent ?? "", (d) => d.label) || (label?.textContent ?? "").trim().replace(/\s*\*$/, "") === placeholder.trim()
7082
+ };
7083
+ const { tag, inputType } = inputTagFor(type);
7084
+ wrapper.setAttribute(FIELD_TYPE_ATTR, type);
7085
+ const shedSize = (el) => {
7086
+ if (type === "long-text") return;
7087
+ el.style.removeProperty("height");
7088
+ el.style.removeProperty("min-height");
7089
+ el.style.removeProperty("resize");
7090
+ el.removeAttribute("rows");
7091
+ };
7092
+ const applyDefaults = (el) => {
7093
+ el.setAttribute("placeholder", defaults.placeholder);
7094
+ if (label && followsDefaults.label) {
7095
+ const required = (label.textContent ?? "").trim().endsWith("*");
7096
+ label.textContent = required ? `${defaults.label} *` : defaults.label;
7097
+ }
7098
+ };
7099
+ if (input.tagName.toLowerCase() === tag) {
7100
+ if (inputType) input.type = inputType;
7101
+ shedSize(input);
7102
+ applyDefaults(input);
7103
+ return;
7104
+ }
7105
+ const next = document.createElement(tag);
7106
+ Array.from(input.attributes).forEach((attr) => {
7107
+ if (attr.name === "type") return;
7108
+ next.setAttribute(attr.name, attr.value);
7109
+ });
7110
+ if (inputType) next.setAttribute("type", inputType);
7111
+ shedSize(next);
7112
+ if (type === "long-text") next.setAttribute("rows", "4");
7113
+ input.replaceWith(next);
7114
+ applyDefaults(next);
7115
+ }
7116
+ function syncRequiredMark(wrapper) {
7117
+ const label = fieldLabelOf(wrapper);
7118
+ if (!label) return;
7119
+ const required = isFieldRequired(wrapper);
7120
+ const base = (label.textContent ?? "").replace(/\s*\*\s*$/, "").trimEnd();
7121
+ const next = required ? `${base} *` : base;
7122
+ if (label.textContent !== next) label.textContent = next;
7123
+ }
7124
+ function setFieldRequired(wrapper, required) {
7125
+ const input = fieldInputOf(wrapper);
7126
+ const label = fieldLabelOf(wrapper);
7127
+ if (!input) return;
7128
+ if (required) input.setAttribute("required", "");
7129
+ else input.removeAttribute("required");
7130
+ if (label) syncRequiredMark(wrapper);
7131
+ }
7132
+ var PLACEHOLDER_EDIT_ATTR = "data-ohw-placeholder-edit";
7133
+ function beginPlaceholderEdit(wrapper) {
7134
+ const input = fieldInputOf(wrapper);
7135
+ if (!input || input.hasAttribute(PLACEHOLDER_EDIT_ATTR)) return;
7136
+ input.setAttribute(PLACEHOLDER_EDIT_ATTR, "");
7137
+ input.value = input.getAttribute("placeholder") ?? "";
7138
+ input.setAttribute("placeholder", "");
7139
+ }
7140
+ function commitPlaceholderEdit(wrapper) {
7141
+ if (!wrapper) return false;
7142
+ const input = fieldInputOf(wrapper);
7143
+ if (!input || !input.hasAttribute(PLACEHOLDER_EDIT_ATTR)) return false;
7144
+ const typed = input.value;
7145
+ input.removeAttribute(PLACEHOLDER_EDIT_ATTR);
7146
+ input.value = "";
7147
+ const previous = input.getAttribute("placeholder") ?? "";
7148
+ input.setAttribute("placeholder", typed);
7149
+ return previous !== typed;
7150
+ }
7151
+ function setFieldPlaceholder(wrapper, placeholder) {
7152
+ fieldInputOf(wrapper)?.setAttribute("placeholder", placeholder);
7153
+ }
7154
+ function uniqueKey(form, base) {
7155
+ const taken = new Set(listFieldWrappers(form).map(fieldKeyOf));
7156
+ if (!taken.has(base)) return base;
7157
+ let n = 2;
7158
+ while (taken.has(`${base}-${n}`)) n += 1;
7159
+ return `${base}-${n}`;
7160
+ }
7161
+ function insertField(form, type) {
7162
+ const existing = listFieldWrappers(form);
7163
+ const source = existing[existing.length - 1] ?? null;
7164
+ const key = uniqueKey(form, type);
7165
+ let wrapper;
7166
+ if (source) {
7167
+ wrapper = source.cloneNode(true);
7168
+ source.after(wrapper);
7169
+ } else {
7170
+ wrapper = document.createElement("div");
7171
+ const label2 = document.createElement("label");
7172
+ const input2 = document.createElement("input");
7173
+ wrapper.append(label2, input2);
7174
+ const submit = form.querySelector('button, input[type="submit"]');
7175
+ if (submit) submit.before(wrapper);
7176
+ else form.appendChild(wrapper);
7177
+ }
7178
+ wrapper.setAttribute(FIELD_ATTR, key);
7179
+ wrapper.setAttribute(FIELD_TYPE_ATTR, type);
7180
+ applyFieldType(wrapper, type);
7181
+ const defaults = FIELD_DEFAULTS[type];
7182
+ const input = fieldInputOf(wrapper);
7183
+ if (input) {
7184
+ input.setAttribute("name", key);
7185
+ input.setAttribute("data-ohw-key", key);
7186
+ input.removeAttribute("required");
7187
+ input.setAttribute("placeholder", defaults.placeholder);
7188
+ input.value = "";
7189
+ }
7190
+ const label = ensureFieldLabel(wrapper, key);
7191
+ label.textContent = defaults.label;
7192
+ label.setAttribute("data-ohw-key", `${key}-label`);
7193
+ return wrapper;
7194
+ }
7195
+ function duplicateField(form, wrapper) {
7196
+ const copy = wrapper.cloneNode(true);
7197
+ const key = uniqueKey(form, `${fieldKeyOf(wrapper)}-copy`);
7198
+ copy.setAttribute(FIELD_ATTR, key);
7199
+ const input = fieldInputOf(copy);
7200
+ if (input) {
7201
+ input.setAttribute("name", key);
7202
+ input.setAttribute("data-ohw-key", key);
7203
+ input.value = "";
7204
+ }
7205
+ wrapper.after(copy);
7206
+ return copy;
7207
+ }
7208
+ function removeField(wrapper) {
7209
+ wrapper.remove();
7210
+ }
7211
+ function moveField(form, key, toIndex) {
7212
+ const wrappers = listFieldWrappers(form);
7213
+ const moving = wrappers.find((wrapper) => fieldKeyOf(wrapper) === key);
7214
+ if (!moving) return;
7215
+ const rest = wrappers.filter((wrapper) => wrapper !== moving);
7216
+ const target = rest[Math.max(0, Math.min(rest.length, toIndex))];
7217
+ if (target) target.before(moving);
7218
+ else rest[rest.length - 1]?.after(moving);
7219
+ }
7220
+ function reconcileFieldsFromContent(form, content) {
7221
+ const formKey = form.getAttribute("data-ohw-key");
7222
+ if (!formKey) return;
7223
+ markFormFields(form);
7224
+ const stored = parseFieldSpecs(content[fieldsKey(formKey)]);
7225
+ if (!stored) return;
7226
+ const byKey = new Map(listFieldWrappers(form).map((wrapper) => [fieldKeyOf(wrapper), wrapper]));
7227
+ stored.forEach((spec) => {
7228
+ let wrapper = byKey.get(spec.key) ?? null;
7229
+ if (!wrapper) {
7230
+ wrapper = insertField(form, spec.type);
7231
+ if (!wrapper) return;
7232
+ wrapper.setAttribute(FIELD_ATTR, spec.key);
7233
+ const input = fieldInputOf(wrapper);
7234
+ if (input) {
7235
+ input.setAttribute("name", spec.key);
7236
+ input.setAttribute("data-ohw-key", spec.key);
7237
+ }
7238
+ byKey.set(spec.key, wrapper);
7239
+ }
7240
+ applyFieldType(wrapper, spec.type);
7241
+ setFieldRequired(wrapper, spec.required);
7242
+ setFieldPlaceholder(wrapper, spec.placeholder);
7243
+ const label = fieldLabelOf(wrapper);
7244
+ if (label && spec.label) label.textContent = spec.label;
7245
+ });
7246
+ const wanted = new Set(stored.map((spec) => spec.key));
7247
+ listFieldWrappers(form).forEach((wrapper) => {
7248
+ if (!wanted.has(fieldKeyOf(wrapper))) wrapper.remove();
7249
+ });
7250
+ stored.forEach((spec, index) => moveField(form, spec.key, index));
7251
+ }
7252
+
7253
+ // src/ui/form-field-toolbar.tsx
7254
+ var import_lucide_react4 = require("lucide-react");
7255
+ var import_jsx_runtime13 = require("react/jsx-runtime");
7256
+ var TYPE_ICONS = {
7257
+ "short-text": import_lucide_react4.Type,
7258
+ "long-text": import_lucide_react4.TextQuote,
7259
+ email: import_lucide_react4.AtSign,
7260
+ phone: import_lucide_react4.Phone
7261
+ };
7262
+ function FormFieldToolbar({
7263
+ type,
7264
+ required,
7265
+ onTypeChange,
7266
+ onRequiredToggle,
7267
+ onDuplicate,
7268
+ onDelete
7269
+ }) {
7270
+ const TypeIcon = TYPE_ICONS[type];
7271
+ const typeLabel = FIELD_TYPES.find((entry) => entry.type === type)?.label ?? "Short text";
7272
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7273
+ "div",
7274
+ {
7275
+ "data-ohw-field-toolbar": "",
7276
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
7277
+ children: [
7278
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenu, { children: [
7279
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7280
+ "button",
7281
+ {
7282
+ type: "button",
7283
+ 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",
7284
+ "data-ohw-field-type-trigger": "",
7285
+ children: [
7286
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TypeIcon, { size: 14, strokeWidth: 1.75, "aria-hidden": true }),
7287
+ typeLabel,
7288
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.ChevronDown, { size: 13, className: "text-muted-foreground", "aria-hidden": true })
7289
+ ]
7290
+ }
7291
+ ) }),
7292
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[190px] p-1", children: FIELD_TYPES.map((entry) => {
7293
+ const Icon = TYPE_ICONS[entry.type];
7294
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7295
+ DropdownMenuItem,
7296
+ {
7297
+ onSelect: () => onTypeChange(entry.type),
7298
+ className: "rounded-md py-2 text-[13px] " + (entry.type === type ? "bg-primary/10" : ""),
7299
+ children: [
7300
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
7301
+ entry.label
7302
+ ]
7303
+ },
7304
+ entry.type
7305
+ );
7306
+ }) })
7307
+ ] }),
7308
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
7309
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7310
+ "button",
7311
+ {
7312
+ type: "button",
7313
+ "aria-pressed": required,
7314
+ onClick: onRequiredToggle,
7315
+ 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"),
7316
+ "data-ohw-field-required": "",
7317
+ children: [
7318
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Asterisk, { size: 14, strokeWidth: 2, "aria-hidden": true }),
7319
+ "Required"
7320
+ ]
7321
+ }
7322
+ ),
7323
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
7324
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenu, { children: [
7325
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7326
+ "button",
7327
+ {
7328
+ type: "button",
7329
+ title: "More",
7330
+ "aria-label": "More",
7331
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/70",
7332
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.MoreHorizontal, { size: 15, "aria-hidden": true })
7333
+ }
7334
+ ) }),
7335
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuContent, { align: "start", sideOffset: 8, className: "min-w-[170px] p-1", children: [
7336
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { onSelect: onDuplicate, className: "rounded-md py-2 text-[13px]", children: [
7337
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Copy, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
7338
+ "Duplicate"
7339
+ ] }),
7340
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(DropdownMenuItem, { variant: "destructive", onSelect: onDelete, className: "rounded-md py-2 text-[13px]", children: [
7341
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react4.Trash2, { size: 14, strokeWidth: 1.75, className: "shrink-0", "aria-hidden": true }),
7342
+ "Delete"
7343
+ ] })
7344
+ ] })
7345
+ ] })
7346
+ ]
7347
+ }
7348
+ );
7349
+ }
7350
+ function FieldTypePicker({ onPick }) {
7351
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7352
+ "div",
7353
+ {
7354
+ "data-ohw-field-type-picker": "",
7355
+ className: "pointer-events-auto grid w-[420px] grid-cols-3 gap-3 rounded-xl border border-border bg-background p-4 shadow-lg",
7356
+ children: FIELD_TYPES.map((entry) => {
7357
+ const Icon = TYPE_ICONS[entry.type];
7358
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
7359
+ "button",
7360
+ {
7361
+ type: "button",
7362
+ onClick: () => onPick(entry.type),
7363
+ 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",
7364
+ children: [
7365
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { size: 26, strokeWidth: 1.5, "aria-hidden": true }),
7366
+ entry.label
7367
+ ]
7368
+ },
7369
+ entry.type
7370
+ );
7371
+ })
7372
+ }
7373
+ );
7374
+ }
7375
+
6804
7376
  // src/ui/MediaOverlay.tsx
6805
7377
  var React7 = __toESM(require("react"), 1);
6806
- var import_lucide_react4 = require("lucide-react");
7378
+ var import_lucide_react5 = require("lucide-react");
6807
7379
 
6808
7380
  // src/ui/button.tsx
6809
7381
  var React6 = __toESM(require("react"), 1);
6810
7382
  var import_radix_ui5 = require("radix-ui");
6811
- var import_jsx_runtime13 = require("react/jsx-runtime");
7383
+ var import_jsx_runtime14 = require("react/jsx-runtime");
6812
7384
  var buttonVariants = cva(
6813
7385
  "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",
6814
7386
  {
@@ -6832,7 +7404,7 @@ var buttonVariants = cva(
6832
7404
  var Button = React6.forwardRef(
6833
7405
  ({ className, variant, size, asChild = false, ...props }, ref) => {
6834
7406
  const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
6835
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7407
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
6836
7408
  Comp,
6837
7409
  {
6838
7410
  ref,
@@ -6846,7 +7418,7 @@ var Button = React6.forwardRef(
6846
7418
  Button.displayName = "Button";
6847
7419
 
6848
7420
  // src/ui/MediaOverlay.tsx
6849
- var import_jsx_runtime14 = require("react/jsx-runtime");
7421
+ var import_jsx_runtime15 = require("react/jsx-runtime");
6850
7422
  var MEDIA_UPLOAD_FADE_MS = 300;
6851
7423
  var VIDEO_SETTINGS_BAR_INSET = 8;
6852
7424
  var OVERLAY_BUTTON_STYLE = {
@@ -6904,7 +7476,7 @@ function MediaOverlay({
6904
7476
  return () => anim.cancel();
6905
7477
  }, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
6906
7478
  if (isUploading) {
6907
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7479
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6908
7480
  "div",
6909
7481
  {
6910
7482
  ref: skeletonRef,
@@ -6913,11 +7485,11 @@ function MediaOverlay({
6913
7485
  "data-ohw-media-skeleton": "",
6914
7486
  "aria-hidden": true,
6915
7487
  style: { ...box, pointerEvents: "none" },
6916
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("style", { children: SKELETON_CSS })
7488
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("style", { children: SKELETON_CSS })
6917
7489
  }
6918
7490
  );
6919
7491
  }
6920
- const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7492
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
6921
7493
  "div",
6922
7494
  {
6923
7495
  "data-ohw-bridge": "",
@@ -6933,7 +7505,7 @@ function MediaOverlay({
6933
7505
  },
6934
7506
  onClick: (e) => e.stopPropagation(),
6935
7507
  children: [
6936
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7508
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6937
7509
  Button,
6938
7510
  {
6939
7511
  "data-ohw-media-overlay": "",
@@ -6948,10 +7520,10 @@ function MediaOverlay({
6948
7520
  e.stopPropagation();
6949
7521
  onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
6950
7522
  },
6951
- children: autoplay ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.Pause, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.Play, { size: 14 })
7523
+ 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 })
6952
7524
  }
6953
7525
  ),
6954
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7526
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6955
7527
  Button,
6956
7528
  {
6957
7529
  "data-ohw-media-overlay": "",
@@ -6966,15 +7538,15 @@ function MediaOverlay({
6966
7538
  e.stopPropagation();
6967
7539
  onVideoSettingsChange?.(hover.key, { muted: !muted });
6968
7540
  },
6969
- children: muted ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.VolumeX, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.Volume2, { size: 14 })
7541
+ 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 })
6970
7542
  }
6971
7543
  )
6972
7544
  ]
6973
7545
  }
6974
7546
  ) : null;
6975
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
7547
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
6976
7548
  settingsBar,
6977
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7549
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6978
7550
  "div",
6979
7551
  {
6980
7552
  "data-ohw-bridge": "",
@@ -6991,7 +7563,7 @@ function MediaOverlay({
6991
7563
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
6992
7564
  },
6993
7565
  onClick: () => onReplace(hover.key),
6994
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7566
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
6995
7567
  Button,
6996
7568
  {
6997
7569
  "data-ohw-media-overlay": "",
@@ -7009,7 +7581,7 @@ function MediaOverlay({
7009
7581
  onReplace(hover.key);
7010
7582
  },
7011
7583
  children: [
7012
- isVideo ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.Film, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.ImageIcon, { size: 14 }),
7584
+ 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 }),
7013
7585
  isVideo ? "Replace video" : "Replace image"
7014
7586
  ]
7015
7587
  }
@@ -7020,8 +7592,8 @@ function MediaOverlay({
7020
7592
  }
7021
7593
 
7022
7594
  // src/ui/CarouselOverlay.tsx
7023
- var import_lucide_react5 = require("lucide-react");
7024
- var import_jsx_runtime15 = require("react/jsx-runtime");
7595
+ var import_lucide_react6 = require("lucide-react");
7596
+ var import_jsx_runtime16 = require("react/jsx-runtime");
7025
7597
  var OVERLAY_BUTTON_STYLE2 = {
7026
7598
  pointerEvents: "auto",
7027
7599
  fontFamily: "Inter, sans-serif",
@@ -7033,7 +7605,7 @@ function CarouselOverlay({
7033
7605
  onEdit
7034
7606
  }) {
7035
7607
  const { rect } = hover;
7036
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7608
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7037
7609
  "div",
7038
7610
  {
7039
7611
  "data-ohw-bridge": "",
@@ -7051,7 +7623,7 @@ function CarouselOverlay({
7051
7623
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7052
7624
  },
7053
7625
  onClick: () => onEdit(hover.key),
7054
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7626
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
7055
7627
  Button,
7056
7628
  {
7057
7629
  "data-ohw-carousel-overlay": "",
@@ -7065,7 +7637,7 @@ function CarouselOverlay({
7065
7637
  onEdit(hover.key);
7066
7638
  },
7067
7639
  children: [
7068
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react5.GalleryHorizontal, { size: 14 }),
7640
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.GalleryHorizontal, { size: 14 }),
7069
7641
  "Edit gallery"
7070
7642
  ]
7071
7643
  }
@@ -7076,7 +7648,7 @@ function CarouselOverlay({
7076
7648
 
7077
7649
  // src/ui/ai-section/AiSectionOverlay.tsx
7078
7650
  var import_react8 = require("react");
7079
- var import_lucide_react6 = require("lucide-react");
7651
+ var import_lucide_react7 = require("lucide-react");
7080
7652
 
7081
7653
  // src/lib/sections.ts
7082
7654
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
@@ -7106,7 +7678,7 @@ function parseSectionsFromHtml(html) {
7106
7678
  }
7107
7679
 
7108
7680
  // src/ui/ai-section/AiSectionOverlay.tsx
7109
- var import_jsx_runtime16 = require("react/jsx-runtime");
7681
+ var import_jsx_runtime17 = require("react/jsx-runtime");
7110
7682
  function findSectionElement(instanceId) {
7111
7683
  const escaped = CSS.escape(instanceId);
7112
7684
  return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
@@ -7174,8 +7746,8 @@ function ReviewButton({
7174
7746
  color
7175
7747
  }) {
7176
7748
  const [hover, setHover] = (0, import_react8.useState)(false);
7177
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "relative" }, children: [
7178
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7749
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { position: "relative" }, children: [
7750
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7179
7751
  "button",
7180
7752
  {
7181
7753
  type: "button",
@@ -7199,7 +7771,7 @@ function ReviewButton({
7199
7771
  children
7200
7772
  }
7201
7773
  ),
7202
- hover && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7774
+ hover && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7203
7775
  "div",
7204
7776
  {
7205
7777
  style: {
@@ -7365,8 +7937,8 @@ function AiSectionOverlay({
7365
7937
  isLast
7366
7938
  });
7367
7939
  }, [activeSelectionId, selectionRect, postToParent2]);
7368
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7369
- hoverRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7940
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
7941
+ hoverRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7370
7942
  "div",
7371
7943
  {
7372
7944
  "data-ohw-ai-section-hover": "",
@@ -7384,7 +7956,7 @@ function AiSectionOverlay({
7384
7956
  }
7385
7957
  }
7386
7958
  ),
7387
- selectionRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7959
+ selectionRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7388
7960
  "div",
7389
7961
  {
7390
7962
  "data-ohw-ai-section-selected": "",
@@ -7402,7 +7974,7 @@ function AiSectionOverlay({
7402
7974
  }
7403
7975
  }
7404
7976
  ),
7405
- reviewRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7977
+ reviewRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7406
7978
  "div",
7407
7979
  {
7408
7980
  "data-ohw-ai-review": "",
@@ -7424,7 +7996,7 @@ function AiSectionOverlay({
7424
7996
  cursor: "default"
7425
7997
  },
7426
7998
  onClick: (e) => e.stopPropagation(),
7427
- children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
7999
+ children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7428
8000
  "div",
7429
8001
  {
7430
8002
  style: {
@@ -7437,8 +8009,8 @@ function AiSectionOverlay({
7437
8009
  paddingTop: 12
7438
8010
  },
7439
8011
  children: [
7440
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ReviewButton, { label: "Accept", onClick: () => decide("accept"), background: PRIMARY2, color: "#ffffff", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.Check, { size: 16, strokeWidth: 2.5, "aria-hidden": true }) }),
7441
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ReviewButton, { label: "Discard", onClick: () => decide("discard"), background: "#EFF6FF", color: "#0c0a09", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_lucide_react6.X, { size: 16, strokeWidth: 2, "aria-hidden": true }) })
8012
+ /* @__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 }) }),
8013
+ /* @__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 }) })
7442
8014
  ]
7443
8015
  }
7444
8016
  )
@@ -7797,23 +8369,23 @@ var import_react12 = require("react");
7797
8369
  // src/ui/dialog.tsx
7798
8370
  var React8 = __toESM(require("react"), 1);
7799
8371
  var import_radix_ui6 = require("radix-ui");
7800
- var import_lucide_react7 = require("lucide-react");
7801
- var import_jsx_runtime17 = require("react/jsx-runtime");
8372
+ var import_lucide_react8 = require("lucide-react");
8373
+ var import_jsx_runtime18 = require("react/jsx-runtime");
7802
8374
  function Dialog2({
7803
8375
  ...props
7804
8376
  }) {
7805
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
8377
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
7806
8378
  }
7807
8379
  function DialogPortal({
7808
8380
  ...props
7809
8381
  }) {
7810
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
8382
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
7811
8383
  }
7812
8384
  function DialogOverlay({
7813
8385
  className,
7814
8386
  ...props
7815
8387
  }) {
7816
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8388
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7817
8389
  import_radix_ui6.Dialog.Overlay,
7818
8390
  {
7819
8391
  "data-slot": "dialog-overlay",
@@ -7826,9 +8398,9 @@ function DialogOverlay({
7826
8398
  var DialogContent = React8.forwardRef(
7827
8399
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
7828
8400
  const positionMode = container ? "absolute" : "fixed";
7829
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(DialogPortal, { container: container ?? void 0, children: [
7830
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
7831
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
8401
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DialogPortal, { container: container ?? void 0, children: [
8402
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
8403
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
7832
8404
  import_radix_ui6.Dialog.Content,
7833
8405
  {
7834
8406
  ref,
@@ -7844,13 +8416,13 @@ var DialogContent = React8.forwardRef(
7844
8416
  ...props,
7845
8417
  children: [
7846
8418
  children,
7847
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8419
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7848
8420
  import_radix_ui6.Dialog.Close,
7849
8421
  {
7850
8422
  type: "button",
7851
8423
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
7852
8424
  "aria-label": "Close",
7853
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react7.X, { size: 16, "aria-hidden": true })
8425
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
7854
8426
  }
7855
8427
  ) : null
7856
8428
  ]
@@ -7864,13 +8436,13 @@ function DialogHeader({
7864
8436
  className,
7865
8437
  ...props
7866
8438
  }) {
7867
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
8439
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
7868
8440
  }
7869
8441
  function DialogFooter({
7870
8442
  className,
7871
8443
  ...props
7872
8444
  }) {
7873
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8445
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7874
8446
  "div",
7875
8447
  {
7876
8448
  className: cn("flex items-center justify-end gap-2", className),
@@ -7878,7 +8450,7 @@ function DialogFooter({
7878
8450
  }
7879
8451
  );
7880
8452
  }
7881
- var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8453
+ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7882
8454
  import_radix_ui6.Dialog.Title,
7883
8455
  {
7884
8456
  ref,
@@ -7890,7 +8462,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
7890
8462
  }
7891
8463
  ));
7892
8464
  DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
7893
- var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8465
+ var DialogDescription = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7894
8466
  import_radix_ui6.Dialog.Description,
7895
8467
  {
7896
8468
  ref,
@@ -7902,63 +8474,63 @@ DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
7902
8474
  var DialogClose = import_radix_ui6.Dialog.Close;
7903
8475
 
7904
8476
  // src/ui/link-modal/LinkEditorPanel.tsx
7905
- var import_lucide_react11 = require("lucide-react");
8477
+ var import_lucide_react12 = require("lucide-react");
7906
8478
 
7907
8479
  // src/ui/link-modal/DestinationBreadcrumb.tsx
7908
- var import_lucide_react8 = require("lucide-react");
7909
- var import_jsx_runtime18 = require("react/jsx-runtime");
8480
+ var import_lucide_react9 = require("lucide-react");
8481
+ var import_jsx_runtime19 = require("react/jsx-runtime");
7910
8482
  function DestinationBreadcrumb({
7911
8483
  pageTitle,
7912
8484
  sectionLabel
7913
8485
  }) {
7914
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
7915
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
7916
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-3", children: [
7917
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", children: [
7918
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
7919
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
8486
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
8487
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
8488
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-3", children: [
8489
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
8490
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react9.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
8491
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-sm font-medium leading-none text-foreground!", children: pageTitle })
7920
8492
  ] }),
7921
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7922
- import_lucide_react8.ArrowRight,
8493
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8494
+ import_lucide_react9.ArrowRight,
7923
8495
  {
7924
8496
  size: 16,
7925
8497
  className: "shrink-0 text-muted-foreground",
7926
8498
  "aria-hidden": true
7927
8499
  }
7928
8500
  ),
7929
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
7930
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7931
- import_lucide_react8.GalleryVertical,
8501
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
8502
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8503
+ import_lucide_react9.GalleryVertical,
7932
8504
  {
7933
8505
  size: 16,
7934
8506
  className: "shrink-0 text-foreground",
7935
8507
  "aria-hidden": true
7936
8508
  }
7937
8509
  ),
7938
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
8510
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-sm font-medium leading-none text-foreground", children: sectionLabel })
7939
8511
  ] })
7940
8512
  ] })
7941
8513
  ] });
7942
8514
  }
7943
8515
 
7944
8516
  // src/ui/link-modal/SectionTreeItem.tsx
7945
- var import_lucide_react9 = require("lucide-react");
7946
- var import_jsx_runtime19 = require("react/jsx-runtime");
8517
+ var import_lucide_react10 = require("lucide-react");
8518
+ var import_jsx_runtime20 = require("react/jsx-runtime");
7947
8519
  function SectionTreeItem({
7948
8520
  section,
7949
8521
  onSelect,
7950
8522
  selected
7951
8523
  }) {
7952
8524
  const interactive = Boolean(onSelect);
7953
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
7954
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8525
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
8526
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7955
8527
  "div",
7956
8528
  {
7957
8529
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
7958
8530
  "aria-hidden": true
7959
8531
  }
7960
8532
  ),
7961
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
8533
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
7962
8534
  "div",
7963
8535
  {
7964
8536
  role: interactive ? "button" : void 0,
@@ -7976,15 +8548,15 @@ function SectionTreeItem({
7976
8548
  interactive && selected && "border-primary"
7977
8549
  ),
7978
8550
  children: [
7979
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7980
- import_lucide_react9.GalleryVertical,
8551
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8552
+ import_lucide_react10.GalleryVertical,
7981
8553
  {
7982
8554
  size: 16,
7983
8555
  className: "shrink-0 text-foreground",
7984
8556
  "aria-hidden": true
7985
8557
  }
7986
8558
  ),
7987
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
8559
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "truncate text-sm font-normal leading-5 text-foreground", children: section.label })
7988
8560
  ]
7989
8561
  }
7990
8562
  )
@@ -7996,10 +8568,10 @@ var import_react9 = require("react");
7996
8568
 
7997
8569
  // src/ui/input.tsx
7998
8570
  var React9 = __toESM(require("react"), 1);
7999
- var import_jsx_runtime20 = require("react/jsx-runtime");
8571
+ var import_jsx_runtime21 = require("react/jsx-runtime");
8000
8572
  var Input = React9.forwardRef(
8001
8573
  ({ className, type, ...props }, ref) => {
8002
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8574
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8003
8575
  "input",
8004
8576
  {
8005
8577
  type,
@@ -8018,9 +8590,9 @@ Input.displayName = "Input";
8018
8590
 
8019
8591
  // src/ui/label.tsx
8020
8592
  var import_radix_ui7 = require("radix-ui");
8021
- var import_jsx_runtime21 = require("react/jsx-runtime");
8593
+ var import_jsx_runtime22 = require("react/jsx-runtime");
8022
8594
  function Label({ className, ...props }) {
8023
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8595
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8024
8596
  import_radix_ui7.Label.Root,
8025
8597
  {
8026
8598
  "data-slot": "label",
@@ -8031,12 +8603,12 @@ function Label({ className, ...props }) {
8031
8603
  }
8032
8604
 
8033
8605
  // src/ui/link-modal/UrlOrPageInput.tsx
8034
- var import_lucide_react10 = require("lucide-react");
8035
- var import_jsx_runtime22 = require("react/jsx-runtime");
8606
+ var import_lucide_react11 = require("lucide-react");
8607
+ var import_jsx_runtime23 = require("react/jsx-runtime");
8036
8608
  function FieldChevron({
8037
8609
  onClick
8038
8610
  }) {
8039
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8611
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8040
8612
  "button",
8041
8613
  {
8042
8614
  type: "button",
@@ -8044,7 +8616,7 @@ function FieldChevron({
8044
8616
  onClick,
8045
8617
  "aria-label": "Open page list",
8046
8618
  tabIndex: -1,
8047
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.ChevronDown, { size: 16 })
8619
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.ChevronDown, { size: 16 })
8048
8620
  }
8049
8621
  );
8050
8622
  }
@@ -8105,19 +8677,19 @@ function UrlOrPageInput({
8105
8677
  "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]",
8106
8678
  urlError ? "border-destructive shadow-[0_0_0_1px_var(--ohw-destructive)]" : isFocused ? "border-primary shadow-[0_0_0_1px_var(--ohw-primary)]" : "border-input"
8107
8679
  );
8108
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
8109
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
8110
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
8111
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
8112
- selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8113
- import_lucide_react10.File,
8680
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
8681
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
8682
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
8683
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
8684
+ selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8685
+ import_lucide_react11.File,
8114
8686
  {
8115
8687
  size: 16,
8116
8688
  className: "shrink-0 text-foreground",
8117
8689
  "aria-hidden": true
8118
8690
  }
8119
8691
  ) }) : null,
8120
- readOnly ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm leading-5 text-foreground", children: selectedPage?.title ?? value }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8692
+ 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)(
8121
8693
  Input,
8122
8694
  {
8123
8695
  ref: inputRef,
@@ -8143,7 +8715,7 @@ function UrlOrPageInput({
8143
8715
  )
8144
8716
  }
8145
8717
  ),
8146
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8718
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8147
8719
  "button",
8148
8720
  {
8149
8721
  type: "button",
@@ -8151,26 +8723,26 @@ function UrlOrPageInput({
8151
8723
  onMouseDown: clearSelection,
8152
8724
  "aria-label": "Clear selected page",
8153
8725
  tabIndex: -1,
8154
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.X, { size: 16, "aria-hidden": true })
8726
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.X, { size: 16, "aria-hidden": true })
8155
8727
  }
8156
8728
  ) : null,
8157
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
8729
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
8158
8730
  ] }),
8159
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8731
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8160
8732
  "div",
8161
8733
  {
8162
8734
  "data-ohw-link-page-dropdown": "",
8163
8735
  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",
8164
8736
  onMouseDown: (e) => e.preventDefault(),
8165
- children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
8737
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
8166
8738
  "button",
8167
8739
  {
8168
8740
  type: "button",
8169
8741
  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",
8170
8742
  onClick: () => onPageSelect(page),
8171
8743
  children: [
8172
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
8173
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "truncate", children: page.title })
8744
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
8745
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "truncate", children: page.title })
8174
8746
  ]
8175
8747
  },
8176
8748
  page.path
@@ -8178,34 +8750,34 @@ function UrlOrPageInput({
8178
8750
  }
8179
8751
  ) : null
8180
8752
  ] }),
8181
- urlError ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
8753
+ urlError ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-sm font-medium text-destructive", children: urlError }) : null
8182
8754
  ] });
8183
8755
  }
8184
8756
 
8185
8757
  // src/ui/link-modal/LinkEditorPanel.tsx
8186
- var import_jsx_runtime23 = require("react/jsx-runtime");
8758
+ var import_jsx_runtime24 = require("react/jsx-runtime");
8187
8759
  function LinkEditorPanel({ state, onClose }) {
8188
8760
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
8189
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8190
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8761
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
8762
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DialogClose, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8191
8763
  "button",
8192
8764
  {
8193
8765
  type: "button",
8194
8766
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
8195
8767
  "aria-label": "Close",
8196
8768
  onClick: onClose,
8197
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.X, { size: 16, "aria-hidden": true })
8769
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
8198
8770
  }
8199
8771
  ) }),
8200
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DialogHeader, { className: "w-full gap-1.5 p-6 pr-12", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DialogTitle, { className: "m-0 w-full break-words", children: state.title }) }),
8201
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
8202
- state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8772
+ /* @__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 }) }),
8773
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
8774
+ state.showBreadcrumb && state.selectedPage && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8203
8775
  DestinationBreadcrumb,
8204
8776
  {
8205
8777
  pageTitle: state.selectedPage.title,
8206
8778
  sectionLabel: state.selectedSection.label
8207
8779
  }
8208
- ) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8780
+ ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8209
8781
  UrlOrPageInput,
8210
8782
  {
8211
8783
  value: state.searchValue,
@@ -8218,8 +8790,8 @@ function LinkEditorPanel({ state, onClose }) {
8218
8790
  urlError: state.urlError
8219
8791
  }
8220
8792
  ),
8221
- state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
8222
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8793
+ state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
8794
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8223
8795
  Button,
8224
8796
  {
8225
8797
  type: "button",
@@ -8230,15 +8802,15 @@ function LinkEditorPanel({ state, onClose }) {
8230
8802
  children: "Choose a section"
8231
8803
  }
8232
8804
  ),
8233
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
8234
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
8235
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: "Pick a section this link should scroll to." })
8805
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
8806
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
8807
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: "Pick a section this link should scroll to." })
8236
8808
  ] })
8237
8809
  ] }) : null,
8238
- state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
8810
+ state.showSectionRow && state.selectedSection ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(SectionTreeItem, { section: state.selectedSection, selected: true }) : null
8239
8811
  ] }),
8240
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
8241
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8812
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
8813
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8242
8814
  Button,
8243
8815
  {
8244
8816
  type: "button",
@@ -8253,7 +8825,7 @@ function LinkEditorPanel({ state, onClose }) {
8253
8825
  children: state.secondaryLabel
8254
8826
  }
8255
8827
  ),
8256
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8828
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8257
8829
  Button,
8258
8830
  {
8259
8831
  type: "button",
@@ -8274,9 +8846,9 @@ function LinkEditorPanel({ state, onClose }) {
8274
8846
  // src/ui/link-modal/SectionPickerOverlay.tsx
8275
8847
  var import_react10 = require("react");
8276
8848
  var import_react_dom2 = require("react-dom");
8277
- var import_lucide_react12 = require("lucide-react");
8849
+ var import_lucide_react13 = require("lucide-react");
8278
8850
  var import_navigation2 = require("next/navigation");
8279
- var import_jsx_runtime24 = require("react/jsx-runtime");
8851
+ var import_jsx_runtime25 = require("react/jsx-runtime");
8280
8852
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
8281
8853
  function rectsEqual(a, b) {
8282
8854
  if (a.size !== b.size) return false;
@@ -8505,7 +9077,7 @@ function SectionPickerOverlay({
8505
9077
  const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
8506
9078
  if (!portalRoot) return null;
8507
9079
  return (0, import_react_dom2.createPortal)(
8508
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9080
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8509
9081
  "div",
8510
9082
  {
8511
9083
  "data-ohw-section-picker": "",
@@ -8515,12 +9087,12 @@ function SectionPickerOverlay({
8515
9087
  role: "dialog",
8516
9088
  "aria-label": "Choose a section",
8517
9089
  children: [
8518
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9090
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8519
9091
  "div",
8520
9092
  {
8521
9093
  className: "pointer-events-auto fixed left-5 z-[2]",
8522
9094
  style: { top: chromeClip.top + 20 },
8523
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9095
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8524
9096
  Button,
8525
9097
  {
8526
9098
  type: "button",
@@ -8529,14 +9101,14 @@ function SectionPickerOverlay({
8529
9101
  className: "h-8 min-w-0 gap-1 border-border bg-background px-2 py-1.5 shadow-sm hover:bg-muted cursor-pointer",
8530
9102
  onClick: onBack,
8531
9103
  children: [
8532
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
9104
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react13.ArrowLeft, { className: "size-4 shrink-0", "aria-hidden": true }),
8533
9105
  "Back"
8534
9106
  ]
8535
9107
  }
8536
9108
  )
8537
9109
  }
8538
9110
  ),
8539
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9111
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8540
9112
  "div",
8541
9113
  {
8542
9114
  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",
@@ -8549,7 +9121,7 @@ function SectionPickerOverlay({
8549
9121
  children: "Click on section to select"
8550
9122
  }
8551
9123
  ),
8552
- !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9124
+ !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8553
9125
  "div",
8554
9126
  {
8555
9127
  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",
@@ -8557,14 +9129,14 @@ function SectionPickerOverlay({
8557
9129
  children: "Loading page preview\u2026"
8558
9130
  }
8559
9131
  ) : null,
8560
- isOnTargetPage && liveSections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "pointer-events-auto fixed inset-0 z-[1] flex items-center justify-center bg-muted/40", children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "text-sm text-muted-foreground", children: "No sections found on this page." }) }) : null,
9132
+ 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,
8561
9133
  isOnTargetPage ? liveSections.map((section) => {
8562
9134
  const rect = rects.get(section.id);
8563
9135
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
8564
9136
  const isSelected = selectedId === section.id;
8565
9137
  const isHovered = hoveredId === section.id;
8566
9138
  const isLit = isSelected || isHovered;
8567
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9139
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8568
9140
  "button",
8569
9141
  {
8570
9142
  type: "button",
@@ -8579,7 +9151,7 @@ function SectionPickerOverlay({
8579
9151
  "aria-label": `Select section ${section.label}`,
8580
9152
  onClick: () => handleSelect(section),
8581
9153
  children: [
8582
- isLit ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9154
+ isLit ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8583
9155
  "span",
8584
9156
  {
8585
9157
  className: "pointer-events-none absolute",
@@ -8592,13 +9164,13 @@ function SectionPickerOverlay({
8592
9164
  "aria-hidden": true
8593
9165
  }
8594
9166
  ) : null,
8595
- isSelected ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9167
+ isSelected ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8596
9168
  "span",
8597
9169
  {
8598
9170
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
8599
9171
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
8600
9172
  "aria-hidden": true,
8601
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react12.Check, { className: "size-5" })
9173
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react13.Check, { className: "size-5" })
8602
9174
  }
8603
9175
  ) : null
8604
9176
  ]
@@ -8778,7 +9350,7 @@ function useLinkModalState({
8778
9350
  }
8779
9351
 
8780
9352
  // src/ui/link-modal/LinkPopover.tsx
8781
- var import_jsx_runtime25 = require("react/jsx-runtime");
9353
+ var import_jsx_runtime26 = require("react/jsx-runtime");
8782
9354
  function postToParent(data) {
8783
9355
  window.parent?.postMessage(data, "*");
8784
9356
  }
@@ -8874,15 +9446,15 @@ function LinkPopover({
8874
9446
  );
8875
9447
  };
8876
9448
  }, [open, sectionPickerActive]);
8877
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
8878
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9449
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
9450
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8879
9451
  Dialog2,
8880
9452
  {
8881
9453
  open: open && !sectionPickerActive,
8882
9454
  onOpenChange: (next) => {
8883
9455
  if (!next) onClose?.();
8884
9456
  },
8885
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9457
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8886
9458
  DialogContent,
8887
9459
  {
8888
9460
  ref: panelRef,
@@ -8892,12 +9464,12 @@ function LinkPopover({
8892
9464
  "data-ohw-bridge": "",
8893
9465
  showCloseButton: false,
8894
9466
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
8895
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LinkEditorPanel, { state, onClose })
9467
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LinkEditorPanel, { state, onClose })
8896
9468
  }
8897
9469
  )
8898
9470
  }
8899
9471
  ),
8900
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9472
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8901
9473
  SectionPickerOverlay,
8902
9474
  {
8903
9475
  pagePath: state.selectedPage.path,
@@ -10123,13 +10695,14 @@ function listSocialItems(row) {
10123
10695
  return isSocialItem(anchor) ? anchor : null;
10124
10696
  }).filter((item) => item !== null);
10125
10697
  }
10126
- function socialRowUnit(item) {
10127
- const row = findSocialsRow(item);
10698
+ function socialRowUnit(item, knownRow) {
10699
+ const row = knownRow ?? findSocialsRow(item);
10700
+ if (!row || !row.contains(item)) return null;
10128
10701
  let node = item;
10129
10702
  while (node.parentElement && node.parentElement !== row) {
10130
10703
  node = node.parentElement;
10131
10704
  }
10132
- return node;
10705
+ return node.parentElement === row ? node : null;
10133
10706
  }
10134
10707
  function listSocialsRows(root = document) {
10135
10708
  const rows = /* @__PURE__ */ new Set();
@@ -10148,7 +10721,8 @@ function markSocialsRows(root = document) {
10148
10721
  listSocialsRows(root).forEach((row) => {
10149
10722
  row.setAttribute(SOCIALS_ROW_ATTR, "");
10150
10723
  const items = listSocialItems(row);
10151
- if (items[0]) rowTemplates.set(rowKeyOf(row), socialRowUnit(items[0]).outerHTML);
10724
+ const firstUnit = items[0] ? socialRowUnit(items[0], row) : null;
10725
+ if (firstUnit) rowTemplates.set(rowKeyOf(row), firstUnit.outerHTML);
10152
10726
  items.forEach((item, index) => {
10153
10727
  item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
10154
10728
  const iconKey = socialIconKey(item);
@@ -10292,7 +10866,8 @@ function removeSocialItem(item, content) {
10292
10866
  const previousContent = Object.fromEntries(
10293
10867
  removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
10294
10868
  );
10295
- const unit = socialRowUnit(item);
10869
+ const unit = socialRowUnit(item, row);
10870
+ if (!unit) return null;
10296
10871
  const nextSibling = unit.nextElementSibling;
10297
10872
  unit.remove();
10298
10873
  markSocialsRows(row.ownerDocument);
@@ -10315,7 +10890,9 @@ function applySocialsOrder(order, root = document) {
10315
10890
  const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
10316
10891
  wanted.forEach((key) => {
10317
10892
  const item = byKey.get(key);
10318
- if (item) row.appendChild(socialRowUnit(item));
10893
+ if (!item) return;
10894
+ const unit = socialRowUnit(item, row);
10895
+ if (unit) row.appendChild(unit);
10319
10896
  });
10320
10897
  });
10321
10898
  markSocialsRows(root);
@@ -10345,7 +10922,7 @@ function reconcileSocialsFromContent(content, root = document) {
10345
10922
  });
10346
10923
  if (surviving.length) {
10347
10924
  present.forEach((item) => {
10348
- if (!surviving.includes(item)) socialRowUnit(item).remove();
10925
+ if (!surviving.includes(item)) socialRowUnit(item)?.remove();
10349
10926
  });
10350
10927
  }
10351
10928
  });
@@ -11681,8 +12258,8 @@ function addFooterColumnWithPersist({
11681
12258
 
11682
12259
  // src/ui/FloatingPanel.tsx
11683
12260
  var import_react13 = require("react");
11684
- var import_lucide_react13 = require("lucide-react");
11685
- var import_jsx_runtime26 = require("react/jsx-runtime");
12261
+ var import_lucide_react14 = require("lucide-react");
12262
+ var import_jsx_runtime27 = require("react/jsx-runtime");
11686
12263
  var PANEL_WIDTH = 256;
11687
12264
  var EDGE_MARGIN = 16;
11688
12265
  function getVisibleClip(parentScroll) {
@@ -11797,7 +12374,7 @@ function FloatingPanel({
11797
12374
  }, [open]);
11798
12375
  (0, import_react13.useEffect)(() => () => document.documentElement.removeAttribute("data-ohw-panel-dragging"), []);
11799
12376
  if (!open) return null;
11800
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
12377
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
11801
12378
  "div",
11802
12379
  {
11803
12380
  ref: panelRef,
@@ -11814,7 +12391,7 @@ function FloatingPanel({
11814
12391
  onPointerDown: (e) => e.stopPropagation(),
11815
12392
  onClick: (e) => e.stopPropagation(),
11816
12393
  children: [
11817
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
12394
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
11818
12395
  "div",
11819
12396
  {
11820
12397
  "data-ohw-floating-panel-header": "",
@@ -11824,14 +12401,14 @@ function FloatingPanel({
11824
12401
  onPointerUp: endDrag,
11825
12402
  onPointerCancel: endDrag,
11826
12403
  children: [
11827
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
11828
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2", children: [
11829
- icon ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "shrink-0 text-foreground", children: icon }) : null,
11830
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
12404
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
12405
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2", children: [
12406
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "shrink-0 text-foreground", children: icon }) : null,
12407
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "min-w-0 flex-1 text-lg font-semibold leading-7 text-foreground", children: title })
11831
12408
  ] }),
11832
- context ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
12409
+ context ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "w-full text-sm leading-5 text-muted-foreground", children: context }) : null
11833
12410
  ] }),
11834
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
12411
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11835
12412
  "button",
11836
12413
  {
11837
12414
  type: "button",
@@ -11843,13 +12420,13 @@ function FloatingPanel({
11843
12420
  onClose();
11844
12421
  },
11845
12422
  onPointerDown: (e) => e.stopPropagation(),
11846
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_lucide_react13.X, { size: 16, "aria-hidden": true })
12423
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.X, { size: 16, "aria-hidden": true })
11847
12424
  }
11848
12425
  )
11849
12426
  ]
11850
12427
  }
11851
12428
  ),
11852
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
12429
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11853
12430
  "div",
11854
12431
  {
11855
12432
  "data-ohw-floating-panel-body": "",
@@ -11863,30 +12440,30 @@ function FloatingPanel({
11863
12440
  }
11864
12441
 
11865
12442
  // src/ui/logo-size-panel.tsx
11866
- var import_lucide_react14 = require("lucide-react");
11867
- var import_jsx_runtime27 = require("react/jsx-runtime");
12443
+ var import_lucide_react15 = require("lucide-react");
12444
+ var import_jsx_runtime28 = require("react/jsx-runtime");
11868
12445
  function SizeSlider({
11869
12446
  value,
11870
12447
  onChange
11871
12448
  }) {
11872
12449
  const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
11873
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full flex-col gap-3", children: [
11874
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
11875
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
11876
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
12450
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full flex-col gap-3", children: [
12451
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
12452
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
12453
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("span", { className: "shrink-0 whitespace-nowrap text-muted-foreground", children: [
11877
12454
  value,
11878
12455
  " px"
11879
12456
  ] })
11880
12457
  ] }),
11881
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
11882
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12458
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
12459
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11883
12460
  "div",
11884
12461
  {
11885
12462
  className: "absolute inset-y-0 left-0 rounded-full bg-primary",
11886
12463
  style: { width: `${pct}%` }
11887
12464
  }
11888
12465
  ),
11889
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12466
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11890
12467
  "input",
11891
12468
  {
11892
12469
  type: "range",
@@ -11923,14 +12500,14 @@ function LogoSizePanel({
11923
12500
  const showFollowing = viewport === "mobile" && mobileFollowing;
11924
12501
  const showMobileSlider = viewport === "mobile" && !mobileFollowing;
11925
12502
  const showDesktopSlider = viewport === "desktop";
11926
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("flex w-full flex-col gap-4", className), children: [
11927
- showFollowing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
11928
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-start gap-1", children: [
11929
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.Link, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
11930
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
12503
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("flex w-full flex-col gap-4", className), children: [
12504
+ showFollowing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
12505
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-start gap-1", children: [
12506
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react15.Link, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
12507
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm font-semibold leading-5 text-foreground", children: "Following desktop size" })
11931
12508
  ] }),
11932
- /* @__PURE__ */ (0, import_jsx_runtime27.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." }),
11933
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12509
+ /* @__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." }),
12510
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11934
12511
  Button,
11935
12512
  {
11936
12513
  type: "button",
@@ -11942,8 +12519,8 @@ function LogoSizePanel({
11942
12519
  }
11943
12520
  )
11944
12521
  ] }) : null,
11945
- showDesktopSlider || showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
11946
- showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12522
+ showDesktopSlider || showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
12523
+ showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11947
12524
  Button,
11948
12525
  {
11949
12526
  type: "button",
@@ -11954,8 +12531,8 @@ function LogoSizePanel({
11954
12531
  children: "Reset to desktop size"
11955
12532
  }
11956
12533
  ) : null,
11957
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px w-full bg-border", role: "separator" }),
11958
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
12534
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "h-px w-full bg-border", role: "separator" }),
12535
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
11959
12536
  Button,
11960
12537
  {
11961
12538
  type: "button",
@@ -11965,24 +12542,24 @@ function LogoSizePanel({
11965
12542
  onClick: onUpdateEverywhere,
11966
12543
  children: [
11967
12544
  "Update logo everywhere",
11968
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.ArrowUpRight, { size: 16, "aria-hidden": true })
12545
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react15.ArrowUpRight, { size: 16, "aria-hidden": true })
11969
12546
  ]
11970
12547
  }
11971
12548
  ),
11972
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
12549
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm leading-5 text-muted-foreground", children: "Matches the right version to your background." })
11973
12550
  ] });
11974
12551
  }
11975
12552
 
11976
12553
  // src/ui/socials-display-panel.tsx
11977
- var import_jsx_runtime28 = require("react/jsx-runtime");
12554
+ var import_jsx_runtime29 = require("react/jsx-runtime");
11978
12555
  function DisplaySwitch({
11979
12556
  label,
11980
12557
  checked,
11981
12558
  disabled,
11982
12559
  onChange
11983
12560
  }) {
11984
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
11985
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12561
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
12562
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
11986
12563
  "span",
11987
12564
  {
11988
12565
  className: cn(
@@ -11992,7 +12569,7 @@ function DisplaySwitch({
11992
12569
  children: label
11993
12570
  }
11994
12571
  ),
11995
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12572
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
11996
12573
  "button",
11997
12574
  {
11998
12575
  type: "button",
@@ -12006,7 +12583,7 @@ function DisplaySwitch({
12006
12583
  checked ? "bg-primary" : "bg-primary-50",
12007
12584
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
12008
12585
  ),
12009
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12586
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12010
12587
  "span",
12011
12588
  {
12012
12589
  className: cn(
@@ -12020,8 +12597,8 @@ function DisplaySwitch({
12020
12597
  ] });
12021
12598
  }
12022
12599
  function SocialsDisplayPanel({ display, onChange, className }) {
12023
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("flex w-full flex-col gap-3", className), children: [
12024
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12600
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: cn("flex w-full flex-col gap-3", className), children: [
12601
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12025
12602
  DisplaySwitch,
12026
12603
  {
12027
12604
  label: "Text",
@@ -12030,7 +12607,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
12030
12607
  onChange: (text) => onChange({ ...display, text })
12031
12608
  }
12032
12609
  ),
12033
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12610
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12034
12611
  DisplaySwitch,
12035
12612
  {
12036
12613
  label: "Icon",
@@ -12590,8 +13167,8 @@ function useNavItemDrag({
12590
13167
  }
12591
13168
 
12592
13169
  // src/ui/footer-container-chrome.tsx
12593
- var import_lucide_react15 = require("lucide-react");
12594
- var import_jsx_runtime29 = require("react/jsx-runtime");
13170
+ var import_lucide_react16 = require("lucide-react");
13171
+ var import_jsx_runtime30 = require("react/jsx-runtime");
12595
13172
  function FooterContainerChrome({
12596
13173
  rect,
12597
13174
  onAdd,
@@ -12599,7 +13176,7 @@ function FooterContainerChrome({
12599
13176
  }) {
12600
13177
  const chromeGap = 6;
12601
13178
  const buttonMargin = 7;
12602
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13179
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
12603
13180
  "div",
12604
13181
  {
12605
13182
  "data-ohw-footer-container-chrome": "",
@@ -12611,8 +13188,8 @@ function FooterContainerChrome({
12611
13188
  width: rect.width + chromeGap * 2,
12612
13189
  height: rect.height + chromeGap * 2
12613
13190
  },
12614
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
12615
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
13191
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(Tooltip, { children: [
13192
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
12616
13193
  "button",
12617
13194
  {
12618
13195
  type: "button",
@@ -12631,10 +13208,10 @@ function FooterContainerChrome({
12631
13208
  if (addDisabled) return;
12632
13209
  onAdd();
12633
13210
  },
12634
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react15.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13211
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react16.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
12635
13212
  }
12636
13213
  ) }),
12637
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
13214
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
12638
13215
  ] })
12639
13216
  }
12640
13217
  ) });
@@ -13094,14 +13671,14 @@ function deleteSelectedNavFooterItem(deps) {
13094
13671
  }
13095
13672
 
13096
13673
  // src/ui/navbar-container-chrome.tsx
13097
- var import_lucide_react16 = require("lucide-react");
13098
- var import_jsx_runtime30 = require("react/jsx-runtime");
13674
+ var import_lucide_react17 = require("lucide-react");
13675
+ var import_jsx_runtime31 = require("react/jsx-runtime");
13099
13676
  function NavbarContainerChrome({
13100
13677
  rect,
13101
13678
  onAdd
13102
13679
  }) {
13103
13680
  const chromeGap = 6;
13104
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13681
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
13105
13682
  "div",
13106
13683
  {
13107
13684
  "data-ohw-navbar-container-chrome": "",
@@ -13113,7 +13690,7 @@ function NavbarContainerChrome({
13113
13690
  width: rect.width + chromeGap * 2,
13114
13691
  height: rect.height + chromeGap * 2
13115
13692
  },
13116
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13693
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
13117
13694
  "button",
13118
13695
  {
13119
13696
  type: "button",
@@ -13130,7 +13707,7 @@ function NavbarContainerChrome({
13130
13707
  e.stopPropagation();
13131
13708
  onAdd();
13132
13709
  },
13133
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react16.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13710
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react17.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
13134
13711
  }
13135
13712
  )
13136
13713
  }
@@ -13139,7 +13716,7 @@ function NavbarContainerChrome({
13139
13716
 
13140
13717
  // src/ui/drop-indicator.tsx
13141
13718
  var React10 = __toESM(require("react"), 1);
13142
- var import_jsx_runtime31 = require("react/jsx-runtime");
13719
+ var import_jsx_runtime32 = require("react/jsx-runtime");
13143
13720
  var dropIndicatorVariants = cva(
13144
13721
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
13145
13722
  {
@@ -13163,7 +13740,7 @@ var dropIndicatorVariants = cva(
13163
13740
  );
13164
13741
  var DropIndicator = React10.forwardRef(
13165
13742
  ({ className, direction, state, ...props }, ref) => {
13166
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
13743
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
13167
13744
  "div",
13168
13745
  {
13169
13746
  ref,
@@ -13180,7 +13757,7 @@ var DropIndicator = React10.forwardRef(
13180
13757
  DropIndicator.displayName = "DropIndicator";
13181
13758
 
13182
13759
  // src/ui/badge.tsx
13183
- var import_jsx_runtime32 = require("react/jsx-runtime");
13760
+ var import_jsx_runtime33 = require("react/jsx-runtime");
13184
13761
  var badgeVariants = cva(
13185
13762
  "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",
13186
13763
  {
@@ -13198,12 +13775,12 @@ var badgeVariants = cva(
13198
13775
  }
13199
13776
  );
13200
13777
  function Badge({ className, variant, ...props }) {
13201
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
13778
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
13202
13779
  }
13203
13780
 
13204
13781
  // src/OhhwellsBridge.tsx
13205
- var import_lucide_react17 = require("lucide-react");
13206
- var import_jsx_runtime33 = require("react/jsx-runtime");
13782
+ var import_lucide_react18 = require("lucide-react");
13783
+ var import_jsx_runtime34 = require("react/jsx-runtime");
13207
13784
  var PRIMARY3 = "#0885FE";
13208
13785
  var IMAGE_FADE_MS = 300;
13209
13786
  function runOpacityFade(el, onDone) {
@@ -13372,7 +13949,7 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
13372
13949
  const root = (0, import_client2.createRoot)(container);
13373
13950
  (0, import_react_dom3.flushSync)(() => {
13374
13951
  root.render(
13375
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13952
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
13376
13953
  SchedulingWidget,
13377
13954
  {
13378
13955
  notifyOnConnect,
@@ -13487,7 +14064,7 @@ function isIconEditable(el) {
13487
14064
  return el.dataset.ohwEditable === "icon";
13488
14065
  }
13489
14066
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
13490
- 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"])';
14067
+ 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"])';
13491
14068
  function getVideoEl2(el) {
13492
14069
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
13493
14070
  }
@@ -14048,7 +14625,7 @@ function EditGlowChrome({
14048
14625
  hideHandle = false
14049
14626
  }) {
14050
14627
  const GAP = SELECTION_CHROME_GAP2;
14051
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
14628
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
14052
14629
  "div",
14053
14630
  {
14054
14631
  ref: elRef,
@@ -14063,7 +14640,7 @@ function EditGlowChrome({
14063
14640
  zIndex: 2147483646
14064
14641
  },
14065
14642
  children: [
14066
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14643
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14067
14644
  "div",
14068
14645
  {
14069
14646
  style: {
@@ -14076,7 +14653,7 @@ function EditGlowChrome({
14076
14653
  }
14077
14654
  }
14078
14655
  ),
14079
- reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14656
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14080
14657
  "div",
14081
14658
  {
14082
14659
  "data-ohw-drag-handle-container": "",
@@ -14088,7 +14665,7 @@ function EditGlowChrome({
14088
14665
  transform: "translate(calc(-100% - 7px), -50%)",
14089
14666
  pointerEvents: dragDisabled ? "none" : "auto"
14090
14667
  },
14091
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14668
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14092
14669
  DragHandle,
14093
14670
  {
14094
14671
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -14298,7 +14875,7 @@ function FloatingToolbar({
14298
14875
  return () => ro.disconnect();
14299
14876
  }, [showEditLink, activeCommands]);
14300
14877
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
14301
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14878
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14302
14879
  "div",
14303
14880
  {
14304
14881
  ref: setRefs,
@@ -14310,12 +14887,12 @@ function FloatingToolbar({
14310
14887
  zIndex: 2147483647,
14311
14888
  pointerEvents: "auto"
14312
14889
  },
14313
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
14314
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
14315
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CustomToolbarDivider, {}),
14890
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(CustomToolbar, { children: [
14891
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_react16.default.Fragment, { children: [
14892
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CustomToolbarDivider, {}),
14316
14893
  btns.map((btn) => {
14317
14894
  const isActive = activeCommands.has(btn.cmd);
14318
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14895
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14319
14896
  CustomToolbarButton,
14320
14897
  {
14321
14898
  title: btn.title,
@@ -14324,7 +14901,7 @@ function FloatingToolbar({
14324
14901
  e.preventDefault();
14325
14902
  onCommand(btn.cmd);
14326
14903
  },
14327
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14904
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14328
14905
  "svg",
14329
14906
  {
14330
14907
  width: "16",
@@ -14345,7 +14922,7 @@ function FloatingToolbar({
14345
14922
  );
14346
14923
  })
14347
14924
  ] }, gi)),
14348
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14925
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14349
14926
  CustomToolbarButton,
14350
14927
  {
14351
14928
  type: "button",
@@ -14359,7 +14936,7 @@ function FloatingToolbar({
14359
14936
  e.preventDefault();
14360
14937
  e.stopPropagation();
14361
14938
  },
14362
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react17.Link, { className: "size-4 shrink-0", "aria-hidden": true })
14939
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Link, { className: "size-4 shrink-0", "aria-hidden": true })
14363
14940
  }
14364
14941
  ) : null
14365
14942
  ] })
@@ -14376,7 +14953,7 @@ function StateToggle({
14376
14953
  states,
14377
14954
  onStateChange
14378
14955
  }) {
14379
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14956
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14380
14957
  ToggleGroup,
14381
14958
  {
14382
14959
  "data-ohw-state-toggle": "",
@@ -14390,7 +14967,7 @@ function StateToggle({
14390
14967
  left: rect.right - 8,
14391
14968
  transform: "translateX(-100%)"
14392
14969
  },
14393
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
14970
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
14394
14971
  }
14395
14972
  );
14396
14973
  }
@@ -14513,6 +15090,157 @@ function OhhwellsBridge() {
14513
15090
  const sectionsLoadedRef = (0, import_react16.useRef)(false);
14514
15091
  const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14515
15092
  const [toolbarRect, setToolbarRect] = (0, import_react16.useState)(null);
15093
+ const [formPickRect, setFormPickRect] = (0, import_react16.useState)(null);
15094
+ const formPickElRef = (0, import_react16.useRef)(null);
15095
+ const [formViewState, setFormViewStateUi] = (0, import_react16.useState)("default");
15096
+ const [formPickCount, setFormPickCount] = (0, import_react16.useState)(null);
15097
+ const [formHoverRect, setFormHoverRect] = (0, import_react16.useState)(null);
15098
+ const formHoverElRef = (0, import_react16.useRef)(null);
15099
+ const [fieldPickRect, setFieldPickRect] = (0, import_react16.useState)(null);
15100
+ const fieldPickElRef = (0, import_react16.useRef)(null);
15101
+ const [fieldPickState, setFieldPickState] = (0, import_react16.useState)(null);
15102
+ const [fieldTypePickerOpen, setFieldTypePickerOpen] = (0, import_react16.useState)(false);
15103
+ const clearFormPick = (0, import_react16.useCallback)(() => {
15104
+ const form = formPickElRef.current;
15105
+ if (form) {
15106
+ const key = formKeyOf(form);
15107
+ if (key) setFormViewState(form, key, "default", DEFAULT_SUCCESS_TEXT);
15108
+ }
15109
+ setFormViewStateUi("default");
15110
+ setFormPickCount(null);
15111
+ setFieldTypePickerOpen(false);
15112
+ fieldPickElRef.current = null;
15113
+ setFieldPickRect(null);
15114
+ setFieldPickState(null);
15115
+ formPickElRef.current = null;
15116
+ setFormPickRect(null);
15117
+ }, []);
15118
+ const clearFieldPick = (0, import_react16.useCallback)(() => {
15119
+ const wrapper = fieldPickElRef.current;
15120
+ if (commitPlaceholderEdit(wrapper) && wrapper) {
15121
+ const form = wrapper.closest('[data-ohw-editable="form"]');
15122
+ if (form) persistFieldsRef.current(form);
15123
+ }
15124
+ fieldPickElRef.current = null;
15125
+ setFieldPickRect(null);
15126
+ setFieldPickState(null);
15127
+ }, []);
15128
+ const persistFieldsRef = (0, import_react16.useRef)(() => {
15129
+ });
15130
+ const persistFields = (0, import_react16.useCallback)(
15131
+ (form) => {
15132
+ const key = formKeyOf(form);
15133
+ if (!key) return;
15134
+ const json = JSON.stringify(readFieldsFromDom(form));
15135
+ editContentRef.current = { ...editContentRef.current, [fieldsKey(key)]: json };
15136
+ postToParentRef.current({ type: "ow:change", nodes: [{ key: fieldsKey(key), text: json }] });
15137
+ },
15138
+ []
15139
+ );
15140
+ persistFieldsRef.current = persistFields;
15141
+ const selectField = (0, import_react16.useCallback)((wrapper) => {
15142
+ if (fieldPickElRef.current && fieldPickElRef.current !== wrapper) {
15143
+ commitPlaceholderEdit(fieldPickElRef.current);
15144
+ }
15145
+ syncRequiredMark(wrapper);
15146
+ beginPlaceholderEdit(wrapper);
15147
+ formHoverElRef.current = null;
15148
+ setFormHoverRect(null);
15149
+ fieldPickElRef.current = wrapper;
15150
+ setFieldPickRect(wrapper.getBoundingClientRect());
15151
+ setFieldPickState({ type: fieldTypeOf(wrapper), required: isFieldRequired(wrapper) });
15152
+ setFieldTypePickerOpen(false);
15153
+ }, []);
15154
+ const withSelectedField = (0, import_react16.useCallback)(
15155
+ (run) => {
15156
+ const wrapper = fieldPickElRef.current;
15157
+ const form = formPickElRef.current;
15158
+ if (!wrapper || !form) return;
15159
+ commitPlaceholderEdit(wrapper);
15160
+ run(form, wrapper);
15161
+ beginPlaceholderEdit(wrapper);
15162
+ persistFields(form);
15163
+ setFormPickRect(form.getBoundingClientRect());
15164
+ },
15165
+ [persistFields]
15166
+ );
15167
+ const handleFieldTypeChange = (0, import_react16.useCallback)(
15168
+ (type) => withSelectedField((_form, wrapper) => {
15169
+ applyFieldType(wrapper, type);
15170
+ selectField(wrapper);
15171
+ }),
15172
+ [selectField, withSelectedField]
15173
+ );
15174
+ const handleFieldRequiredToggle = (0, import_react16.useCallback)(
15175
+ () => withSelectedField((_form, wrapper) => {
15176
+ setFieldRequired(wrapper, !isFieldRequired(wrapper));
15177
+ selectField(wrapper);
15178
+ }),
15179
+ [selectField, withSelectedField]
15180
+ );
15181
+ const handleFieldDuplicate = (0, import_react16.useCallback)(
15182
+ () => withSelectedField((form, wrapper) => {
15183
+ const copy = duplicateField(form, wrapper);
15184
+ selectField(copy);
15185
+ }),
15186
+ [selectField, withSelectedField]
15187
+ );
15188
+ const handleFieldDelete = (0, import_react16.useCallback)(
15189
+ () => withSelectedField((_form, wrapper) => {
15190
+ removeField(wrapper);
15191
+ clearFieldPick();
15192
+ postToParentRef.current({ type: "ow:toast", title: "Form field deleted" });
15193
+ }),
15194
+ [clearFieldPick, withSelectedField]
15195
+ );
15196
+ const handleAddField = (0, import_react16.useCallback)(
15197
+ (type) => {
15198
+ const form = formPickElRef.current;
15199
+ if (!form) return;
15200
+ const wrapper = insertField(form, type);
15201
+ setFieldTypePickerOpen(false);
15202
+ if (!wrapper) return;
15203
+ persistFields(form);
15204
+ setFormPickRect(null);
15205
+ requestAnimationFrame(() => {
15206
+ selectField(wrapper);
15207
+ wrapper.scrollIntoView({ block: "nearest", behavior: "smooth" });
15208
+ });
15209
+ },
15210
+ [persistFields, selectField]
15211
+ );
15212
+ const fieldDragRef = (0, import_react16.useRef)(null);
15213
+ const handleFieldDragStart = (0, import_react16.useCallback)(() => {
15214
+ const wrapper = fieldPickElRef.current;
15215
+ const form = formPickElRef.current;
15216
+ if (!wrapper || !form) return;
15217
+ fieldDragRef.current = { key: fieldKeyOf(wrapper), form };
15218
+ }, []);
15219
+ const handleFieldDragEnd = (0, import_react16.useCallback)(() => {
15220
+ fieldDragRef.current = null;
15221
+ setFieldDropIndex(null);
15222
+ }, []);
15223
+ const [fieldDropIndex, setFieldDropIndex] = (0, import_react16.useState)(null);
15224
+ const clearFormPickRef = (0, import_react16.useRef)(clearFormPick);
15225
+ clearFormPickRef.current = clearFormPick;
15226
+ (0, import_react16.useEffect)(() => {
15227
+ const el = fieldPickElRef.current;
15228
+ if (!el || fieldPickRect === null) return;
15229
+ const observer = new ResizeObserver(() => {
15230
+ if (fieldPickElRef.current === el) setFieldPickRect(el.getBoundingClientRect());
15231
+ });
15232
+ observer.observe(el);
15233
+ return () => observer.disconnect();
15234
+ }, [fieldPickRect !== null, fieldPickState]);
15235
+ (0, import_react16.useEffect)(() => {
15236
+ const el = formPickElRef.current;
15237
+ if (!el || formPickRect === null) return;
15238
+ const observer = new ResizeObserver(() => {
15239
+ if (formPickElRef.current === el) setFormPickRect(el.getBoundingClientRect());
15240
+ });
15241
+ observer.observe(el);
15242
+ return () => observer.disconnect();
15243
+ }, [formPickRect !== null, formViewState]);
14516
15244
  const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
14517
15245
  const toolbarVariantRef = (0, import_react16.useRef)("none");
14518
15246
  toolbarVariantRef.current = toolbarVariant;
@@ -14534,7 +15262,7 @@ function OhhwellsBridge() {
14534
15262
  (0, import_react16.useEffect)(() => {
14535
15263
  const sync = () => {
14536
15264
  const el = document.querySelector(
14537
- "[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key])"
15265
+ '[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]):not([data-ohw-editable="form"] *)'
14538
15266
  );
14539
15267
  const target = el && !el.closest("[data-ohw-href-key]") ? el : null;
14540
15268
  if (!target) {
@@ -15666,6 +16394,7 @@ function OhhwellsBridge() {
15666
16394
  setFloatingPanel(null);
15667
16395
  setLogoSizeDraft(null);
15668
16396
  }, []);
16397
+ closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
15669
16398
  const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
15670
16399
  setFloatingPanel(null);
15671
16400
  setLogoSizeDraft(null);
@@ -15921,6 +16650,98 @@ function OhhwellsBridge() {
15921
16650
  cancelled = true;
15922
16651
  };
15923
16652
  }, [subdomain, isEditMode]);
16653
+ (0, import_react16.useEffect)(() => {
16654
+ if (!isEditMode) return;
16655
+ const resolveIndex = (form, clientY) => {
16656
+ const wrappers = listFieldWrappers(form).filter((el) => fieldKeyOf(el) !== fieldDragRef.current?.key);
16657
+ for (let i = 0; i < wrappers.length; i += 1) {
16658
+ const rect = wrappers[i].getBoundingClientRect();
16659
+ if (clientY < rect.top + rect.height / 2) return i;
16660
+ }
16661
+ return wrappers.length;
16662
+ };
16663
+ const onDragOver = (e) => {
16664
+ const session = fieldDragRef.current;
16665
+ if (!session) return;
16666
+ e.preventDefault();
16667
+ e.stopPropagation();
16668
+ if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
16669
+ setFieldDropIndex(resolveIndex(session.form, e.clientY));
16670
+ };
16671
+ const onDrop = (e) => {
16672
+ const session = fieldDragRef.current;
16673
+ if (!session) return;
16674
+ e.preventDefault();
16675
+ e.stopPropagation();
16676
+ moveField(session.form, session.key, resolveIndex(session.form, e.clientY));
16677
+ persistFields(session.form);
16678
+ const moved = listFieldWrappers(session.form).find((el) => fieldKeyOf(el) === session.key);
16679
+ if (moved) selectField(moved);
16680
+ setFormPickRect(session.form.getBoundingClientRect());
16681
+ fieldDragRef.current = null;
16682
+ setFieldDropIndex(null);
16683
+ };
16684
+ window.addEventListener("dragover", onDragOver, true);
16685
+ window.addEventListener("drop", onDrop, true);
16686
+ return () => {
16687
+ window.removeEventListener("dragover", onDragOver, true);
16688
+ window.removeEventListener("drop", onDrop, true);
16689
+ };
16690
+ }, [isEditMode, persistFields, selectField]);
16691
+ (0, import_react16.useEffect)(() => {
16692
+ if (!isEditMode) return;
16693
+ const mark = () => document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
16694
+ markFormFields(form);
16695
+ });
16696
+ mark();
16697
+ const observer = new MutationObserver(() => mark());
16698
+ document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
16699
+ observer.observe(form, { childList: true, subtree: true, characterData: true });
16700
+ });
16701
+ return () => observer.disconnect();
16702
+ }, [isEditMode, fetchState, pathname]);
16703
+ (0, import_react16.useEffect)(() => {
16704
+ if (!isEditMode) return;
16705
+ let saveTimer = null;
16706
+ const onInput = (e) => {
16707
+ const input = e.target;
16708
+ if (!input || !("value" in input)) return;
16709
+ const wrapper = getFieldWrapper(input);
16710
+ if (!wrapper || wrapper !== fieldPickElRef.current) return;
16711
+ if (saveTimer) clearTimeout(saveTimer);
16712
+ saveTimer = setTimeout(() => {
16713
+ const form = formPickElRef.current;
16714
+ if (!form) return;
16715
+ const previous = input.getAttribute("placeholder");
16716
+ input.setAttribute("placeholder", input.value);
16717
+ persistFields(form);
16718
+ input.setAttribute("placeholder", previous ?? "");
16719
+ }, 400);
16720
+ };
16721
+ document.addEventListener("input", onInput, true);
16722
+ return () => document.removeEventListener("input", onInput, true);
16723
+ }, [isEditMode, persistFields]);
16724
+ (0, import_react16.useEffect)(() => {
16725
+ if (isEditMode || fetchState !== "done") return;
16726
+ const content = contentCache.get(subdomain) ?? {};
16727
+ document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
16728
+ reconcileFieldsFromContent(form, content);
16729
+ });
16730
+ }, [isEditMode, fetchState, subdomain]);
16731
+ (0, import_react16.useEffect)(() => {
16732
+ if (!isEditMode) return;
16733
+ const swallow = (e) => {
16734
+ const target = e.target;
16735
+ if (target && getFormElement(target)) e.preventDefault();
16736
+ };
16737
+ document.addEventListener("submit", swallow, true);
16738
+ return () => document.removeEventListener("submit", swallow, true);
16739
+ }, [isEditMode]);
16740
+ (0, import_react16.useEffect)(() => {
16741
+ if (isEditMode || fetchState !== "done") return;
16742
+ const apiUrl = process.env.NEXT_PUBLIC_FLOWOPS_API_URL ?? "https://flowops-backend-staging-2yfdh7pwpq-as.a.run.app";
16743
+ bindPublishedForms(apiUrl, subdomain, contentCache.get(subdomain) ?? {});
16744
+ }, [isEditMode, fetchState, subdomain]);
15924
16745
  (0, import_react16.useEffect)(() => {
15925
16746
  if (!subdomain || isEditMode) return;
15926
16747
  let debounceTimer = null;
@@ -16154,7 +16975,9 @@ function OhhwellsBridge() {
16154
16975
  [style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
16155
16976
  [style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
16156
16977
  [style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
16157
- [data-ohw-editable] {
16978
+ /* Not the form: it is a layout container (flex/grid with gaps), and forcing block
16979
+ crushed its fields together (OHH-490). */
16980
+ [data-ohw-editable]:not([data-ohw-editable="form"]) {
16158
16981
  display: block;
16159
16982
  }
16160
16983
  /* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
@@ -16180,6 +17003,35 @@ function OhhwellsBridge() {
16180
17003
  [data-ohw-editable="video"], [data-ohw-editable="video"] *,
16181
17004
  [data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
16182
17005
  [data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
17006
+ /* A form field is a design surface in the editor: its input takes the pointer so the
17007
+ field can be picked and hovered from anywhere inside it (OHH-642). */
17008
+ [data-ohw-editable="form"] [data-ohw-form-field] input,
17009
+ [data-ohw-editable="form"] [data-ohw-form-field] textarea,
17010
+ [data-ohw-editable="form"] [data-ohw-form-field] label {
17011
+ pointer-events: auto !important;
17012
+ cursor: pointer !important;
17013
+ }
17014
+ /* While a field is selected its placeholder is being written in the value, so the
17015
+ text reads as a placeholder rather than as an answer (OHH-642). */
17016
+ /* A field is a design surface here: dragging its corner resized it past the form and
17017
+ left the chrome behind. Height stays adjustable, width does not (OHH-642). */
17018
+ [data-ohw-editable="form"] [data-ohw-form-field] textarea {
17019
+ resize: vertical !important;
17020
+ max-width: 100% !important;
17021
+ }
17022
+ [data-ohw-editable="form"] [data-ohw-form-field] input,
17023
+ [data-ohw-editable="form"] [data-ohw-form-field] textarea {
17024
+ box-sizing: border-box !important;
17025
+ width: 100% !important;
17026
+ }
17027
+ /* Somewhere to click the block itself, on every side (OHH-642) \u2014 editor only. */
17028
+ [data-ohw-editable="form"] {
17029
+ padding: 18px !important;
17030
+ }
17031
+ [data-ohw-placeholder-edit] {
17032
+ color: color-mix(in srgb, currentColor 55%, transparent) !important;
17033
+ cursor: text !important;
17034
+ }
16183
17035
  /* Text hover chrome is drawn by the overlay (see hoveredTextRect) \u2014 the CSS outline
16184
17036
  that used to draw it dashes denser than the overlay border, so identical specs
16185
17037
  still read as two different frames (OHH-695). The attribute stays: hover paths
@@ -16266,6 +17118,49 @@ function OhhwellsBridge() {
16266
17118
  if (target.closest("[data-ohw-max-badge]")) return;
16267
17119
  if (isInsideLinkEditor(target)) return;
16268
17120
  if (isInsideFloatingPanel(target)) return;
17121
+ if (target.closest("[data-ohw-form-toolbar]")) return;
17122
+ if (target.closest(
17123
+ '[data-ohw-field-toolbar], [data-ohw-field-type-picker], [data-radix-popper-content-wrapper], [role="menu"], [data-slot="dropdown-menu-content"]'
17124
+ )) {
17125
+ return;
17126
+ }
17127
+ {
17128
+ const formEl = getFormElement(target);
17129
+ const onSuccessText = target.closest(`[${SUCCESS_TEXT_ATTR}]`);
17130
+ if (formEl && formKeyOf(formEl) && !onSuccessText) {
17131
+ const fieldEl = getFieldWrapper(target);
17132
+ if (fieldEl) {
17133
+ const label = target.closest("label");
17134
+ if (label && fieldPickElRef.current === fieldEl) return;
17135
+ e.preventDefault();
17136
+ e.stopPropagation();
17137
+ deactivateRef.current();
17138
+ deselectRef.current();
17139
+ formPickElRef.current = formEl;
17140
+ setFormPickRect(null);
17141
+ selectField(fieldEl);
17142
+ if (!label) fieldEl.querySelector("input, textarea")?.focus();
17143
+ return;
17144
+ }
17145
+ clearFieldPick();
17146
+ e.preventDefault();
17147
+ e.stopPropagation();
17148
+ deactivateRef.current();
17149
+ deselectRef.current();
17150
+ markFormFields(formEl);
17151
+ formHoverElRef.current = null;
17152
+ setFormHoverRect(null);
17153
+ formPickElRef.current = formEl;
17154
+ setFormPickRect(formEl.getBoundingClientRect());
17155
+ postToParentRef.current({
17156
+ type: "ow:form-selected",
17157
+ formKey: formKeyOf(formEl),
17158
+ hasLongText: formHasLongText(formEl)
17159
+ });
17160
+ return;
17161
+ }
17162
+ if (!formEl && formPickElRef.current) clearFormPick();
17163
+ }
16269
17164
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
16270
17165
  const beneath = document.elementsFromPoint(e.clientX, e.clientY).find(
16271
17166
  (el) => el instanceof HTMLElement && !el.closest("[data-ohw-bridge-root]") && el.closest("[data-ohw-section]") != null
@@ -16605,6 +17500,26 @@ function OhhwellsBridge() {
16605
17500
  return;
16606
17501
  }
16607
17502
  const editable = target.closest("[data-ohw-editable]");
17503
+ const hoverForm = getFormElement(target);
17504
+ if (hoverForm) {
17505
+ const hoverField = getFieldWrapper(target);
17506
+ const hoverTarget = hoverField ?? hoverForm;
17507
+ const selectedHere = hoverTarget === fieldPickElRef.current || hoverTarget === formPickElRef.current;
17508
+ hoveredItemElRef.current = null;
17509
+ setHoveredItemRect(null);
17510
+ if (selectedHere) {
17511
+ formHoverElRef.current = null;
17512
+ setFormHoverRect(null);
17513
+ } else {
17514
+ formHoverElRef.current = hoverTarget;
17515
+ setFormHoverRect(hoverTarget.getBoundingClientRect());
17516
+ }
17517
+ return;
17518
+ }
17519
+ if (formHoverElRef.current) {
17520
+ formHoverElRef.current = null;
17521
+ setFormHoverRect(null);
17522
+ }
16608
17523
  if (!editable) return;
16609
17524
  const selected = selectedElRef.current;
16610
17525
  if (selected && (selected === editable || selected.contains(editable))) return;
@@ -17241,6 +18156,13 @@ function OhhwellsBridge() {
17241
18156
  setSectionGap(null);
17242
18157
  }
17243
18158
  };
18159
+ const pointOwnedByFloatingPanel = (clientX, clientY) => {
18160
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging")) return true;
18161
+ const panel = document.querySelector("[data-ohw-floating-panel]");
18162
+ if (!panel) return false;
18163
+ const rect = panel.getBoundingClientRect();
18164
+ return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
18165
+ };
17244
18166
  const handleMouseMove = (e) => {
17245
18167
  const { clientX, clientY } = e;
17246
18168
  if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
@@ -17806,6 +18728,13 @@ function OhhwellsBridge() {
17806
18728
  }
17807
18729
  }
17808
18730
  };
18731
+ const handleFormCount = (e) => {
18732
+ if (e.data?.type !== "ow:form-count") return;
18733
+ const form = formPickElRef.current;
18734
+ if (!form || formKeyOf(form) !== e.data.formKey) return;
18735
+ setFormPickCount(typeof e.data.count === "number" ? e.data.count : null);
18736
+ };
18737
+ window.addEventListener("message", handleFormCount);
17809
18738
  window.addEventListener("message", handleUiEscape);
17810
18739
  const handleKeyDown = (e) => {
17811
18740
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
@@ -17825,6 +18754,11 @@ function OhhwellsBridge() {
17825
18754
  closeFloatingPanelOnlyRef.current();
17826
18755
  return;
17827
18756
  }
18757
+ if (e.key === "Escape" && formPickElRef.current) {
18758
+ e.preventDefault();
18759
+ clearFormPickRef.current();
18760
+ return;
18761
+ }
17828
18762
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
17829
18763
  if (toolbarVariantRef.current === "logo") {
17830
18764
  deselectRef.current();
@@ -18377,6 +19311,7 @@ function OhhwellsBridge() {
18377
19311
  window.removeEventListener("message", handleGetBrand);
18378
19312
  window.removeEventListener("message", handleDeactivate);
18379
19313
  window.removeEventListener("message", handleToastAction);
19314
+ window.removeEventListener("message", handleFormCount);
18380
19315
  window.removeEventListener("message", handleUiEscape);
18381
19316
  autoSaveTimers.current.forEach(clearTimeout);
18382
19317
  autoSaveTimers.current.clear();
@@ -18400,7 +19335,9 @@ function OhhwellsBridge() {
18400
19335
  if (footerDragRef.current) return;
18401
19336
  const target = e.target;
18402
19337
  if (!target) return;
18403
- if (target.closest('[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]')) {
19338
+ if (target.closest(
19339
+ '[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"]'
19340
+ )) {
18404
19341
  return;
18405
19342
  }
18406
19343
  if (target.closest("[data-ohw-item-drag-surface]")) return;
@@ -18578,7 +19515,7 @@ function OhhwellsBridge() {
18578
19515
  postToParent2({
18579
19516
  type: "ow:ready",
18580
19517
  version: "1",
18581
- bridgeVersion: "0.1.63",
19518
+ bridgeVersion: "0.1.64",
18582
19519
  path: pathname,
18583
19520
  nodes: collectEditableNodes(editContentRef.current),
18584
19521
  sections
@@ -18973,10 +19910,10 @@ function OhhwellsBridge() {
18973
19910
  [postToParent2]
18974
19911
  );
18975
19912
  return bridgeRoot ? (0, import_react_dom4.createPortal)(
18976
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
18977
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
18978
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
18979
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19913
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
19914
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
19915
+ isEditMode && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
19916
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
18980
19917
  MediaOverlay,
18981
19918
  {
18982
19919
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -18987,7 +19924,7 @@ function OhhwellsBridge() {
18987
19924
  },
18988
19925
  `uploading-${key}`
18989
19926
  )),
18990
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19927
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
18991
19928
  MediaOverlay,
18992
19929
  {
18993
19930
  hover: mediaHover,
@@ -18996,11 +19933,11 @@ function OhhwellsBridge() {
18996
19933
  onVideoSettingsChange: handleVideoSettingsChange
18997
19934
  }
18998
19935
  ),
18999
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19000
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19001
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19002
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19003
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19936
+ carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19937
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19938
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19939
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19940
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19004
19941
  "div",
19005
19942
  {
19006
19943
  className: "pointer-events-none fixed z-2147483646",
@@ -19010,7 +19947,7 @@ function OhhwellsBridge() {
19010
19947
  width: slot.width,
19011
19948
  height: slot.height
19012
19949
  },
19013
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19950
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19014
19951
  DropIndicator,
19015
19952
  {
19016
19953
  direction: slot.direction,
@@ -19021,7 +19958,7 @@ function OhhwellsBridge() {
19021
19958
  },
19022
19959
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19023
19960
  )),
19024
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19961
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19025
19962
  "div",
19026
19963
  {
19027
19964
  className: "pointer-events-none fixed z-2147483646",
@@ -19031,7 +19968,7 @@ function OhhwellsBridge() {
19031
19968
  width: slot.width,
19032
19969
  height: slot.height
19033
19970
  },
19034
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19971
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19035
19972
  DropIndicator,
19036
19973
  {
19037
19974
  direction: slot.direction,
@@ -19042,11 +19979,179 @@ function OhhwellsBridge() {
19042
19979
  },
19043
19980
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19044
19981
  )),
19045
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19046
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19047
- hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19048
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19049
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19982
+ hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19983
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19984
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19985
+ formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19986
+ ItemInteractionLayer,
19987
+ {
19988
+ rect: formPickRect,
19989
+ state: "active-top",
19990
+ itemDragSurface: false,
19991
+ toolbarAlign: "left",
19992
+ chromeGap: 24,
19993
+ toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
19994
+ "div",
19995
+ {
19996
+ "data-ohw-form-toolbar": "",
19997
+ className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
19998
+ children: [
19999
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20000
+ "button",
20001
+ {
20002
+ type: "button",
20003
+ "aria-label": "Add field",
20004
+ className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
20005
+ onClick: () => setFieldTypePickerOpen((open) => !open),
20006
+ "data-ohw-add-field": "",
20007
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Plus, { size: 15, "aria-hidden": true })
20008
+ }
20009
+ ),
20010
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20011
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
20012
+ "button",
20013
+ {
20014
+ type: "button",
20015
+ 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",
20016
+ onClick: () => {
20017
+ const form = formPickElRef.current;
20018
+ if (!form) return;
20019
+ postToParent2({
20020
+ type: "ow:form-pick",
20021
+ formKey: formKeyOf(form),
20022
+ hasLongText: formHasLongText(form)
20023
+ });
20024
+ },
20025
+ children: [
20026
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Settings, { size: 14, "aria-hidden": true }),
20027
+ "Form settings",
20028
+ formPickCount ? (
20029
+ // Counter pill, per the design — not a text suffix.
20030
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20031
+ "span",
20032
+ {
20033
+ "data-ohw-form-count": "",
20034
+ 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",
20035
+ children: formPickCount
20036
+ }
20037
+ )
20038
+ ) : null
20039
+ ]
20040
+ }
20041
+ ),
20042
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20043
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
20044
+ "button",
20045
+ {
20046
+ type: "button",
20047
+ 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",
20048
+ onClick: () => {
20049
+ const form = formPickElRef.current;
20050
+ if (!form) return;
20051
+ postToParent2({
20052
+ type: "ow:form-submissions",
20053
+ formKey: formKeyOf(form),
20054
+ hasLongText: formHasLongText(form)
20055
+ });
20056
+ },
20057
+ "data-ohw-view-submissions": "",
20058
+ children: [
20059
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react18.Table, { size: 14, "aria-hidden": true }),
20060
+ "View submissions"
20061
+ ]
20062
+ }
20063
+ ),
20064
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
20065
+ /* @__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)(
20066
+ "button",
20067
+ {
20068
+ type: "button",
20069
+ "aria-pressed": formViewState === state,
20070
+ 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"),
20071
+ onClick: () => {
20072
+ const form = formPickElRef.current;
20073
+ const key = form ? formKeyOf(form) : null;
20074
+ if (!form || !key) return;
20075
+ const initial = editContentRef.current[formSuccessKey(key)] ?? DEFAULT_SUCCESS_TEXT;
20076
+ setFormViewState(form, key, state, initial);
20077
+ setFormViewStateUi(state);
20078
+ setFormPickRect(form.getBoundingClientRect());
20079
+ if (state === "success") {
20080
+ const successEl = form.querySelector(`[${SUCCESS_TEXT_ATTR}]`);
20081
+ if (successEl) requestAnimationFrame(() => activateRef.current(successEl));
20082
+ } else {
20083
+ deactivateRef.current();
20084
+ }
20085
+ },
20086
+ children: state
20087
+ },
20088
+ state
20089
+ )) })
20090
+ ]
20091
+ }
20092
+ )
20093
+ }
20094
+ ),
20095
+ formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20096
+ ItemInteractionLayer,
20097
+ {
20098
+ rect: formHoverRect,
20099
+ state: "hover",
20100
+ chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
20101
+ }
20102
+ ),
20103
+ fieldPickRect && fieldPickState && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20104
+ ItemInteractionLayer,
20105
+ {
20106
+ rect: fieldPickRect,
20107
+ state: "active-top",
20108
+ itemDragSurface: false,
20109
+ toolbarAlign: "left",
20110
+ chromeGap: 10,
20111
+ showHandle: true,
20112
+ dragHandleLabel: "Reorder field",
20113
+ onDragHandleDragStart: handleFieldDragStart,
20114
+ onDragHandleDragEnd: handleFieldDragEnd,
20115
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20116
+ FormFieldToolbar,
20117
+ {
20118
+ type: fieldPickState.type,
20119
+ required: fieldPickState.required,
20120
+ onTypeChange: handleFieldTypeChange,
20121
+ onRequiredToggle: handleFieldRequiredToggle,
20122
+ onDuplicate: handleFieldDuplicate,
20123
+ onDelete: handleFieldDelete
20124
+ }
20125
+ )
20126
+ }
20127
+ ),
20128
+ fieldDropIndex !== null && formPickElRef.current ? (() => {
20129
+ const wrappers = listFieldWrappers(formPickElRef.current).filter(
20130
+ (el) => fieldKeyOf(el) !== fieldDragRef.current?.key
20131
+ );
20132
+ const anchor = wrappers[Math.min(fieldDropIndex, wrappers.length - 1)];
20133
+ if (!anchor) return null;
20134
+ const rect = anchor.getBoundingClientRect();
20135
+ const atEnd = fieldDropIndex >= wrappers.length;
20136
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20137
+ "div",
20138
+ {
20139
+ className: "pointer-events-none fixed z-[2147483644]",
20140
+ style: { top: atEnd ? rect.bottom : rect.top, left: rect.left, width: rect.width },
20141
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(DropIndicator, { direction: "horizontal", state: "dragActive" })
20142
+ }
20143
+ );
20144
+ })() : null,
20145
+ fieldTypePickerOpen && formPickRect && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20146
+ "div",
20147
+ {
20148
+ className: "pointer-events-none fixed z-[2147483645]",
20149
+ style: { top: formPickRect.top + 16, left: formPickRect.left + 24 },
20150
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(FieldTypePicker, { onPick: handleAddField })
20151
+ }
20152
+ ),
20153
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
20154
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19050
20155
  FooterContainerChrome,
19051
20156
  {
19052
20157
  rect: toolbarRect,
@@ -19054,7 +20159,7 @@ function OhhwellsBridge() {
19054
20159
  addDisabled: !canAddFooterColumn()
19055
20160
  }
19056
20161
  ),
19057
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20162
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19058
20163
  ItemInteractionLayer,
19059
20164
  {
19060
20165
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -19069,7 +20174,7 @@ function OhhwellsBridge() {
19069
20174
  onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19070
20175
  onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19071
20176
  itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19072
- toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20177
+ toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19073
20178
  ItemActionToolbar,
19074
20179
  {
19075
20180
  onEditLink: openLinkPopoverForSelected,
@@ -19105,8 +20210,8 @@ function OhhwellsBridge() {
19105
20210
  ) : void 0
19106
20211
  }
19107
20212
  ),
19108
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19109
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20213
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
20214
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19110
20215
  EditGlowChrome,
19111
20216
  {
19112
20217
  rect: toolbarRect,
@@ -19116,7 +20221,7 @@ function OhhwellsBridge() {
19116
20221
  hideHandle: isItemDragging
19117
20222
  }
19118
20223
  ),
19119
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20224
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19120
20225
  FloatingToolbar,
19121
20226
  {
19122
20227
  rect: toolbarRect,
@@ -19129,7 +20234,7 @@ function OhhwellsBridge() {
19129
20234
  }
19130
20235
  )
19131
20236
  ] }),
19132
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20237
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
19133
20238
  "div",
19134
20239
  {
19135
20240
  "data-ohw-max-badge": "",
@@ -19155,7 +20260,7 @@ function OhhwellsBridge() {
19155
20260
  ]
19156
20261
  }
19157
20262
  ),
19158
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20263
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19159
20264
  StateToggle,
19160
20265
  {
19161
20266
  rect: toggleState.rect,
@@ -19164,15 +20269,15 @@ function OhhwellsBridge() {
19164
20269
  onStateChange: handleStateChange
19165
20270
  }
19166
20271
  ),
19167
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20272
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
19168
20273
  "div",
19169
20274
  {
19170
20275
  "data-ohw-section-insert-line": "",
19171
20276
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19172
20277
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
19173
20278
  children: [
19174
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19175
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20279
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
20280
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19176
20281
  Badge,
19177
20282
  {
19178
20283
  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",
@@ -19189,11 +20294,11 @@ function OhhwellsBridge() {
19189
20294
  children: "Add Section"
19190
20295
  }
19191
20296
  ),
19192
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
20297
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
19193
20298
  ]
19194
20299
  }
19195
20300
  ),
19196
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20301
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19197
20302
  LinkPopover,
19198
20303
  {
19199
20304
  panelRef: linkPopoverPanelRef,
@@ -19210,7 +20315,7 @@ function OhhwellsBridge() {
19210
20315
  },
19211
20316
  linkPopover.key
19212
20317
  ) : null,
19213
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20318
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19214
20319
  FloatingPanel,
19215
20320
  {
19216
20321
  open: true,
@@ -19220,7 +20325,7 @@ function OhhwellsBridge() {
19220
20325
  onPositionChange: setFloatingPanelPos,
19221
20326
  parentScroll: parentScrollSnap ?? parentScrollRef.current,
19222
20327
  onClose: closeFloatingPanelOnly,
19223
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20328
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19224
20329
  SocialsDisplayPanel,
19225
20330
  {
19226
20331
  display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
@@ -19232,7 +20337,7 @@ function OhhwellsBridge() {
19232
20337
  )
19233
20338
  }
19234
20339
  ) : null,
19235
- floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20340
+ floatingPanel && floatingPanel.kind === "logo-size" && logoSizeDraft ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19236
20341
  FloatingPanel,
19237
20342
  {
19238
20343
  open: true,
@@ -19242,7 +20347,7 @@ function OhhwellsBridge() {
19242
20347
  onPositionChange: setFloatingPanelPos,
19243
20348
  parentScroll: parentScrollSnap ?? parentScrollRef.current,
19244
20349
  onClose: closeFloatingPanelAndDeselect,
19245
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20350
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19246
20351
  LogoSizePanel,
19247
20352
  {
19248
20353
  viewport: editorViewport,
@@ -19290,10 +20395,10 @@ function OhhwellsBridge() {
19290
20395
 
19291
20396
  // src/ui/EmptySection.tsx
19292
20397
  var import_link = __toESM(require("next/link"), 1);
19293
- var import_jsx_runtime34 = require("react/jsx-runtime");
20398
+ var import_jsx_runtime35 = require("react/jsx-runtime");
19294
20399
  function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
19295
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
19296
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20400
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
20401
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
19297
20402
  "p",
19298
20403
  {
19299
20404
  style: {
@@ -19305,10 +20410,10 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
19305
20410
  color: "var(--brand-accent)",
19306
20411
  marginBottom: "1.5rem"
19307
20412
  },
19308
- children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_link.default, { href: homeHref, style: { color: "inherit" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { ...eyebrowKey ? { "data-ohw-editable": "text", "data-ohw-key": eyebrowKey } : {}, children: "Home" }) })
20413
+ 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" }) })
19309
20414
  }
19310
20415
  ),
19311
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20416
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
19312
20417
  "h1",
19313
20418
  {
19314
20419
  style: {
@@ -19323,7 +20428,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
19323
20428
  children: title
19324
20429
  }
19325
20430
  ),
19326
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20431
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
19327
20432
  "p",
19328
20433
  {
19329
20434
  style: {