@ohhwells/bridge 0.1.64-next.176 → 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
@@ -6589,6 +6589,7 @@ function getChromeStyle(state) {
6589
6589
  }
6590
6590
  function ClampedToolbarSlot({
6591
6591
  placement,
6592
+ align = "center",
6592
6593
  children
6593
6594
  }) {
6594
6595
  const slotRef = (0, import_react7.useRef)(null);
@@ -6610,7 +6611,7 @@ function ClampedToolbarSlot({
6610
6611
  Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN - half)
6611
6612
  );
6612
6613
  const offsetX = clampedCenter - centerX;
6613
- slot.style.transform = `translateX(calc(-50% + ${offsetX}px))`;
6614
+ slot.style.transform = align === "left" ? "none" : `translateX(calc(-50% + ${offsetX}px))`;
6614
6615
  };
6615
6616
  clamp();
6616
6617
  const ro = new ResizeObserver(clamp);
@@ -6621,19 +6622,20 @@ function ClampedToolbarSlot({
6621
6622
  ro.disconnect();
6622
6623
  window.removeEventListener("resize", clamp);
6623
6624
  };
6624
- }, [placement, children]);
6625
+ }, [placement, children, align]);
6625
6626
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6626
6627
  "div",
6627
6628
  {
6628
6629
  ref: slotRef,
6629
6630
  className: cn(
6630
- "pointer-events-auto absolute left-1/2",
6631
+ "pointer-events-auto absolute",
6632
+ align === "left" ? "left-0" : "left-1/2",
6631
6633
  placement === "top" ? "bottom-full" : "top-full"
6632
6634
  ),
6633
6635
  style: {
6634
6636
  marginBottom: placement === "top" ? TOOLBAR_STROKE_GAP : void 0,
6635
6637
  marginTop: placement === "bottom" ? TOOLBAR_STROKE_GAP : void 0,
6636
- transform: "translateX(-50%)"
6638
+ transform: align === "left" ? "none" : "translateX(-50%)"
6637
6639
  },
6638
6640
  "data-ohw-item-toolbar-anchor": placement,
6639
6641
  children
@@ -6702,6 +6704,7 @@ function ItemInteractionLayer({
6702
6704
  onItemClick,
6703
6705
  itemDragSurface = true,
6704
6706
  chromeGap,
6707
+ toolbarAlign = "center",
6705
6708
  className
6706
6709
  }) {
6707
6710
  if (state === "default") return null;
@@ -6789,8 +6792,8 @@ function ItemInteractionLayer({
6789
6792
  )
6790
6793
  }
6791
6794
  ),
6792
- showToolbar && state === "active-top" && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { placement: "top", children: toolbar }),
6793
- showToolbar && state === "active-bottom" && !useDetachedBelowToolbar && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ClampedToolbarSlot, { placement: "bottom", children: toolbar }),
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 }),
6794
6797
  useDetachedBelowToolbar && toolbarBelowRect ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
6795
6798
  DetachedBelowToolbarSlot,
6796
6799
  {
@@ -6804,14 +6807,580 @@ function ItemInteractionLayer({
6804
6807
  );
6805
6808
  }
6806
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
+
6807
7376
  // src/ui/MediaOverlay.tsx
6808
7377
  var React7 = __toESM(require("react"), 1);
6809
- var import_lucide_react4 = require("lucide-react");
7378
+ var import_lucide_react5 = require("lucide-react");
6810
7379
 
6811
7380
  // src/ui/button.tsx
6812
7381
  var React6 = __toESM(require("react"), 1);
6813
7382
  var import_radix_ui5 = require("radix-ui");
6814
- var import_jsx_runtime13 = require("react/jsx-runtime");
7383
+ var import_jsx_runtime14 = require("react/jsx-runtime");
6815
7384
  var buttonVariants = cva(
6816
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",
6817
7386
  {
@@ -6835,7 +7404,7 @@ var buttonVariants = cva(
6835
7404
  var Button = React6.forwardRef(
6836
7405
  ({ className, variant, size, asChild = false, ...props }, ref) => {
6837
7406
  const Comp = asChild ? import_radix_ui5.Slot.Root : "button";
6838
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
7407
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
6839
7408
  Comp,
6840
7409
  {
6841
7410
  ref,
@@ -6849,7 +7418,7 @@ var Button = React6.forwardRef(
6849
7418
  Button.displayName = "Button";
6850
7419
 
6851
7420
  // src/ui/MediaOverlay.tsx
6852
- var import_jsx_runtime14 = require("react/jsx-runtime");
7421
+ var import_jsx_runtime15 = require("react/jsx-runtime");
6853
7422
  var MEDIA_UPLOAD_FADE_MS = 300;
6854
7423
  var VIDEO_SETTINGS_BAR_INSET = 8;
6855
7424
  var OVERLAY_BUTTON_STYLE = {
@@ -6907,7 +7476,7 @@ function MediaOverlay({
6907
7476
  return () => anim.cancel();
6908
7477
  }, [isUploading, fadingOut, onFadeOutComplete, hover.key]);
6909
7478
  if (isUploading) {
6910
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7479
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6911
7480
  "div",
6912
7481
  {
6913
7482
  ref: skeletonRef,
@@ -6916,11 +7485,11 @@ function MediaOverlay({
6916
7485
  "data-ohw-media-skeleton": "",
6917
7486
  "aria-hidden": true,
6918
7487
  style: { ...box, pointerEvents: "none" },
6919
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("style", { children: SKELETON_CSS })
7488
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("style", { children: SKELETON_CSS })
6920
7489
  }
6921
7490
  );
6922
7491
  }
6923
- const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7492
+ const settingsBar = isVideo && !hover.isDragOver ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
6924
7493
  "div",
6925
7494
  {
6926
7495
  "data-ohw-bridge": "",
@@ -6936,7 +7505,7 @@ function MediaOverlay({
6936
7505
  },
6937
7506
  onClick: (e) => e.stopPropagation(),
6938
7507
  children: [
6939
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7508
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6940
7509
  Button,
6941
7510
  {
6942
7511
  "data-ohw-media-overlay": "",
@@ -6951,10 +7520,10 @@ function MediaOverlay({
6951
7520
  e.stopPropagation();
6952
7521
  onVideoSettingsChange?.(hover.key, { autoplay: !autoplay });
6953
7522
  },
6954
- 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 })
6955
7524
  }
6956
7525
  ),
6957
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7526
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6958
7527
  Button,
6959
7528
  {
6960
7529
  "data-ohw-media-overlay": "",
@@ -6969,15 +7538,15 @@ function MediaOverlay({
6969
7538
  e.stopPropagation();
6970
7539
  onVideoSettingsChange?.(hover.key, { muted: !muted });
6971
7540
  },
6972
- 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 })
6973
7542
  }
6974
7543
  )
6975
7544
  ]
6976
7545
  }
6977
7546
  ) : null;
6978
- 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: [
6979
7548
  settingsBar,
6980
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
7549
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
6981
7550
  "div",
6982
7551
  {
6983
7552
  "data-ohw-bridge": "",
@@ -6994,7 +7563,7 @@ function MediaOverlay({
6994
7563
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
6995
7564
  },
6996
7565
  onClick: () => onReplace(hover.key),
6997
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
7566
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
6998
7567
  Button,
6999
7568
  {
7000
7569
  "data-ohw-media-overlay": "",
@@ -7012,7 +7581,7 @@ function MediaOverlay({
7012
7581
  onReplace(hover.key);
7013
7582
  },
7014
7583
  children: [
7015
- 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 }),
7016
7585
  isVideo ? "Replace video" : "Replace image"
7017
7586
  ]
7018
7587
  }
@@ -7023,8 +7592,8 @@ function MediaOverlay({
7023
7592
  }
7024
7593
 
7025
7594
  // src/ui/CarouselOverlay.tsx
7026
- var import_lucide_react5 = require("lucide-react");
7027
- 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");
7028
7597
  var OVERLAY_BUTTON_STYLE2 = {
7029
7598
  pointerEvents: "auto",
7030
7599
  fontFamily: "Inter, sans-serif",
@@ -7036,7 +7605,7 @@ function CarouselOverlay({
7036
7605
  onEdit
7037
7606
  }) {
7038
7607
  const { rect } = hover;
7039
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
7608
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7040
7609
  "div",
7041
7610
  {
7042
7611
  "data-ohw-bridge": "",
@@ -7054,7 +7623,7 @@ function CarouselOverlay({
7054
7623
  background: "color-mix(in srgb, var(--color-primary) 20%, transparent)"
7055
7624
  },
7056
7625
  onClick: () => onEdit(hover.key),
7057
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
7626
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
7058
7627
  Button,
7059
7628
  {
7060
7629
  "data-ohw-carousel-overlay": "",
@@ -7068,7 +7637,7 @@ function CarouselOverlay({
7068
7637
  onEdit(hover.key);
7069
7638
  },
7070
7639
  children: [
7071
- /* @__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 }),
7072
7641
  "Edit gallery"
7073
7642
  ]
7074
7643
  }
@@ -7079,7 +7648,7 @@ function CarouselOverlay({
7079
7648
 
7080
7649
  // src/ui/ai-section/AiSectionOverlay.tsx
7081
7650
  var import_react8 = require("react");
7082
- var import_lucide_react6 = require("lucide-react");
7651
+ var import_lucide_react7 = require("lucide-react");
7083
7652
 
7084
7653
  // src/lib/sections.ts
7085
7654
  var LINK_PICKER_EXCLUDED_IDS = /* @__PURE__ */ new Set(["navbar", "footer"]);
@@ -7109,7 +7678,7 @@ function parseSectionsFromHtml(html) {
7109
7678
  }
7110
7679
 
7111
7680
  // src/ui/ai-section/AiSectionOverlay.tsx
7112
- var import_jsx_runtime16 = require("react/jsx-runtime");
7681
+ var import_jsx_runtime17 = require("react/jsx-runtime");
7113
7682
  function findSectionElement(instanceId) {
7114
7683
  const escaped = CSS.escape(instanceId);
7115
7684
  return document.querySelector(`[data-ohw-instance="${escaped}"]`) ?? document.querySelector(`[data-ohw-section="${escaped}"]:not([data-ohw-instance])`);
@@ -7177,8 +7746,8 @@ function ReviewButton({
7177
7746
  color
7178
7747
  }) {
7179
7748
  const [hover, setHover] = (0, import_react8.useState)(false);
7180
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "relative" }, children: [
7181
- /* @__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)(
7182
7751
  "button",
7183
7752
  {
7184
7753
  type: "button",
@@ -7202,7 +7771,7 @@ function ReviewButton({
7202
7771
  children
7203
7772
  }
7204
7773
  ),
7205
- hover && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7774
+ hover && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7206
7775
  "div",
7207
7776
  {
7208
7777
  style: {
@@ -7368,8 +7937,8 @@ function AiSectionOverlay({
7368
7937
  isLast
7369
7938
  });
7370
7939
  }, [activeSelectionId, selectionRect, postToParent2]);
7371
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
7372
- 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)(
7373
7942
  "div",
7374
7943
  {
7375
7944
  "data-ohw-ai-section-hover": "",
@@ -7387,7 +7956,7 @@ function AiSectionOverlay({
7387
7956
  }
7388
7957
  }
7389
7958
  ),
7390
- selectionRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7959
+ selectionRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7391
7960
  "div",
7392
7961
  {
7393
7962
  "data-ohw-ai-section-selected": "",
@@ -7405,7 +7974,7 @@ function AiSectionOverlay({
7405
7974
  }
7406
7975
  }
7407
7976
  ),
7408
- reviewRect && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
7977
+ reviewRect && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
7409
7978
  "div",
7410
7979
  {
7411
7980
  "data-ohw-ai-review": "",
@@ -7427,7 +7996,7 @@ function AiSectionOverlay({
7427
7996
  cursor: "default"
7428
7997
  },
7429
7998
  onClick: (e) => e.stopPropagation(),
7430
- children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
7999
+ children: !reviewButtonsHidden && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
7431
8000
  "div",
7432
8001
  {
7433
8002
  style: {
@@ -7440,8 +8009,8 @@ function AiSectionOverlay({
7440
8009
  paddingTop: 12
7441
8010
  },
7442
8011
  children: [
7443
- /* @__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 }) }),
7444
- /* @__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 }) })
7445
8014
  ]
7446
8015
  }
7447
8016
  )
@@ -7800,23 +8369,23 @@ var import_react12 = require("react");
7800
8369
  // src/ui/dialog.tsx
7801
8370
  var React8 = __toESM(require("react"), 1);
7802
8371
  var import_radix_ui6 = require("radix-ui");
7803
- var import_lucide_react7 = require("lucide-react");
7804
- 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");
7805
8374
  function Dialog2({
7806
8375
  ...props
7807
8376
  }) {
7808
- 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 });
7809
8378
  }
7810
8379
  function DialogPortal({
7811
8380
  ...props
7812
8381
  }) {
7813
- 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 });
7814
8383
  }
7815
8384
  function DialogOverlay({
7816
8385
  className,
7817
8386
  ...props
7818
8387
  }) {
7819
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8388
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7820
8389
  import_radix_ui6.Dialog.Overlay,
7821
8390
  {
7822
8391
  "data-slot": "dialog-overlay",
@@ -7829,9 +8398,9 @@ function DialogOverlay({
7829
8398
  var DialogContent = React8.forwardRef(
7830
8399
  ({ className, children, showCloseButton = true, container, ...props }, ref) => {
7831
8400
  const positionMode = container ? "absolute" : "fixed";
7832
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(DialogPortal, { container: container ?? void 0, children: [
7833
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
7834
- /* @__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)(
7835
8404
  import_radix_ui6.Dialog.Content,
7836
8405
  {
7837
8406
  ref,
@@ -7847,13 +8416,13 @@ var DialogContent = React8.forwardRef(
7847
8416
  ...props,
7848
8417
  children: [
7849
8418
  children,
7850
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8419
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7851
8420
  import_radix_ui6.Dialog.Close,
7852
8421
  {
7853
8422
  type: "button",
7854
8423
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
7855
8424
  "aria-label": "Close",
7856
- 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 })
7857
8426
  }
7858
8427
  ) : null
7859
8428
  ]
@@ -7867,13 +8436,13 @@ function DialogHeader({
7867
8436
  className,
7868
8437
  ...props
7869
8438
  }) {
7870
- 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 });
7871
8440
  }
7872
8441
  function DialogFooter({
7873
8442
  className,
7874
8443
  ...props
7875
8444
  }) {
7876
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
8445
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7877
8446
  "div",
7878
8447
  {
7879
8448
  className: cn("flex items-center justify-end gap-2", className),
@@ -7881,7 +8450,7 @@ function DialogFooter({
7881
8450
  }
7882
8451
  );
7883
8452
  }
7884
- 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)(
7885
8454
  import_radix_ui6.Dialog.Title,
7886
8455
  {
7887
8456
  ref,
@@ -7893,7 +8462,7 @@ var DialogTitle = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE
7893
8462
  }
7894
8463
  ));
7895
8464
  DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
7896
- 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)(
7897
8466
  import_radix_ui6.Dialog.Description,
7898
8467
  {
7899
8468
  ref,
@@ -7905,63 +8474,63 @@ DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
7905
8474
  var DialogClose = import_radix_ui6.Dialog.Close;
7906
8475
 
7907
8476
  // src/ui/link-modal/LinkEditorPanel.tsx
7908
- var import_lucide_react11 = require("lucide-react");
8477
+ var import_lucide_react12 = require("lucide-react");
7909
8478
 
7910
8479
  // src/ui/link-modal/DestinationBreadcrumb.tsx
7911
- var import_lucide_react8 = require("lucide-react");
7912
- 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");
7913
8482
  function DestinationBreadcrumb({
7914
8483
  pageTitle,
7915
8484
  sectionLabel
7916
8485
  }) {
7917
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
7918
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm font-medium! text-foreground m-0", children: "Destination" }),
7919
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-3", children: [
7920
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", children: [
7921
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react8.File, { size: 16, className: "shrink-0 text-foreground", "aria-hidden": true }),
7922
- /* @__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 })
7923
8492
  ] }),
7924
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7925
- import_lucide_react8.ArrowRight,
8493
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
8494
+ import_lucide_react9.ArrowRight,
7926
8495
  {
7927
8496
  size: 16,
7928
8497
  className: "shrink-0 text-muted-foreground",
7929
8498
  "aria-hidden": true
7930
8499
  }
7931
8500
  ),
7932
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
7933
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
7934
- 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,
7935
8504
  {
7936
8505
  size: 16,
7937
8506
  className: "shrink-0 text-foreground",
7938
8507
  "aria-hidden": true
7939
8508
  }
7940
8509
  ),
7941
- /* @__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 })
7942
8511
  ] })
7943
8512
  ] })
7944
8513
  ] });
7945
8514
  }
7946
8515
 
7947
8516
  // src/ui/link-modal/SectionTreeItem.tsx
7948
- var import_lucide_react9 = require("lucide-react");
7949
- 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");
7950
8519
  function SectionTreeItem({
7951
8520
  section,
7952
8521
  onSelect,
7953
8522
  selected
7954
8523
  }) {
7955
8524
  const interactive = Boolean(onSelect);
7956
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex h-9 w-full items-end pl-3", children: [
7957
- /* @__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)(
7958
8527
  "div",
7959
8528
  {
7960
8529
  className: "mr-[-1px] h-9 w-2 shrink-0 rounded-bl-sm border-b border-l border-border mb-4",
7961
8530
  "aria-hidden": true
7962
8531
  }
7963
8532
  ),
7964
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
8533
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
7965
8534
  "div",
7966
8535
  {
7967
8536
  role: interactive ? "button" : void 0,
@@ -7979,15 +8548,15 @@ function SectionTreeItem({
7979
8548
  interactive && selected && "border-primary"
7980
8549
  ),
7981
8550
  children: [
7982
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
7983
- import_lucide_react9.GalleryVertical,
8551
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8552
+ import_lucide_react10.GalleryVertical,
7984
8553
  {
7985
8554
  size: 16,
7986
8555
  className: "shrink-0 text-foreground",
7987
8556
  "aria-hidden": true
7988
8557
  }
7989
8558
  ),
7990
- /* @__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 })
7991
8560
  ]
7992
8561
  }
7993
8562
  )
@@ -7999,10 +8568,10 @@ var import_react9 = require("react");
7999
8568
 
8000
8569
  // src/ui/input.tsx
8001
8570
  var React9 = __toESM(require("react"), 1);
8002
- var import_jsx_runtime20 = require("react/jsx-runtime");
8571
+ var import_jsx_runtime21 = require("react/jsx-runtime");
8003
8572
  var Input = React9.forwardRef(
8004
8573
  ({ className, type, ...props }, ref) => {
8005
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
8574
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8006
8575
  "input",
8007
8576
  {
8008
8577
  type,
@@ -8021,9 +8590,9 @@ Input.displayName = "Input";
8021
8590
 
8022
8591
  // src/ui/label.tsx
8023
8592
  var import_radix_ui7 = require("radix-ui");
8024
- var import_jsx_runtime21 = require("react/jsx-runtime");
8593
+ var import_jsx_runtime22 = require("react/jsx-runtime");
8025
8594
  function Label({ className, ...props }) {
8026
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8595
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8027
8596
  import_radix_ui7.Label.Root,
8028
8597
  {
8029
8598
  "data-slot": "label",
@@ -8034,12 +8603,12 @@ function Label({ className, ...props }) {
8034
8603
  }
8035
8604
 
8036
8605
  // src/ui/link-modal/UrlOrPageInput.tsx
8037
- var import_lucide_react10 = require("lucide-react");
8038
- 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");
8039
8608
  function FieldChevron({
8040
8609
  onClick
8041
8610
  }) {
8042
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8611
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8043
8612
  "button",
8044
8613
  {
8045
8614
  type: "button",
@@ -8047,7 +8616,7 @@ function FieldChevron({
8047
8616
  onClick,
8048
8617
  "aria-label": "Open page list",
8049
8618
  tabIndex: -1,
8050
- 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 })
8051
8620
  }
8052
8621
  );
8053
8622
  }
@@ -8108,19 +8677,19 @@ function UrlOrPageInput({
8108
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]",
8109
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"
8110
8679
  );
8111
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "flex w-full flex-col gap-2 p-0", children: [
8112
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Label, { htmlFor: inputId, className: cn(urlError && "text-destructive"), children: "Destination" }),
8113
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { ref: rootRef, className: "relative w-full", children: [
8114
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { "data-ohw-link-field": true, className: fieldClassName, children: [
8115
- selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex shrink-0 items-center pr-2", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8116
- 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,
8117
8686
  {
8118
8687
  size: 16,
8119
8688
  className: "shrink-0 text-foreground",
8120
8689
  "aria-hidden": true
8121
8690
  }
8122
8691
  ) }) : null,
8123
- 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)(
8124
8693
  Input,
8125
8694
  {
8126
8695
  ref: inputRef,
@@ -8146,7 +8715,7 @@ function UrlOrPageInput({
8146
8715
  )
8147
8716
  }
8148
8717
  ),
8149
- selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8718
+ selectedPage && !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8150
8719
  "button",
8151
8720
  {
8152
8721
  type: "button",
@@ -8154,26 +8723,26 @@ function UrlOrPageInput({
8154
8723
  onMouseDown: clearSelection,
8155
8724
  "aria-label": "Clear selected page",
8156
8725
  tabIndex: -1,
8157
- 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 })
8158
8727
  }
8159
8728
  ) : null,
8160
- !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
8729
+ !readOnly ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FieldChevron, { onClick: toggleDropdown }) : null
8161
8730
  ] }),
8162
- dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8731
+ dropdownOpen && !readOnly && filteredPages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8163
8732
  "div",
8164
8733
  {
8165
8734
  "data-ohw-link-page-dropdown": "",
8166
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",
8167
8736
  onMouseDown: (e) => e.preventDefault(),
8168
- children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
8737
+ children: filteredPages.map((page) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
8169
8738
  "button",
8170
8739
  {
8171
8740
  type: "button",
8172
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",
8173
8742
  onClick: () => onPageSelect(page),
8174
8743
  children: [
8175
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.File, { size: 16, className: "shrink-0", "aria-hidden": true }),
8176
- /* @__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 })
8177
8746
  ]
8178
8747
  },
8179
8748
  page.path
@@ -8181,34 +8750,34 @@ function UrlOrPageInput({
8181
8750
  }
8182
8751
  ) : null
8183
8752
  ] }),
8184
- 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
8185
8754
  ] });
8186
8755
  }
8187
8756
 
8188
8757
  // src/ui/link-modal/LinkEditorPanel.tsx
8189
- var import_jsx_runtime23 = require("react/jsx-runtime");
8758
+ var import_jsx_runtime24 = require("react/jsx-runtime");
8190
8759
  function LinkEditorPanel({ state, onClose }) {
8191
8760
  const isCancel = state.secondaryLabel === "Cancel" || state.secondaryLabel === "Back to sections";
8192
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
8193
- /* @__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)(
8194
8763
  "button",
8195
8764
  {
8196
8765
  type: "button",
8197
8766
  className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50 h-7",
8198
8767
  "aria-label": "Close",
8199
8768
  onClick: onClose,
8200
- 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 })
8201
8770
  }
8202
8771
  ) }),
8203
- /* @__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 }) }),
8204
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex w-full flex-col gap-3 px-6 pb-8 pt-1", children: [
8205
- 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)(
8206
8775
  DestinationBreadcrumb,
8207
8776
  {
8208
8777
  pageTitle: state.selectedPage.title,
8209
8778
  sectionLabel: state.selectedSection.label
8210
8779
  }
8211
- ) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8780
+ ) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8212
8781
  UrlOrPageInput,
8213
8782
  {
8214
8783
  value: state.searchValue,
@@ -8221,8 +8790,8 @@ function LinkEditorPanel({ state, onClose }) {
8221
8790
  urlError: state.urlError
8222
8791
  }
8223
8792
  ),
8224
- state.showChooseSection ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex flex-col justify-center gap-2", children: [
8225
- /* @__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)(
8226
8795
  Button,
8227
8796
  {
8228
8797
  type: "button",
@@ -8233,15 +8802,15 @@ function LinkEditorPanel({ state, onClose }) {
8233
8802
  children: "Choose a section"
8234
8803
  }
8235
8804
  ),
8236
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
8237
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react11.Info, { size: 16, className: "shrink-0", "aria-hidden": true }),
8238
- /* @__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." })
8239
8808
  ] })
8240
8809
  ] }) : null,
8241
- 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
8242
8811
  ] }),
8243
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DialogFooter, { className: "w-full px-6 pb-6", children: [
8244
- /* @__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)(
8245
8814
  Button,
8246
8815
  {
8247
8816
  type: "button",
@@ -8256,7 +8825,7 @@ function LinkEditorPanel({ state, onClose }) {
8256
8825
  children: state.secondaryLabel
8257
8826
  }
8258
8827
  ),
8259
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
8828
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8260
8829
  Button,
8261
8830
  {
8262
8831
  type: "button",
@@ -8277,9 +8846,9 @@ function LinkEditorPanel({ state, onClose }) {
8277
8846
  // src/ui/link-modal/SectionPickerOverlay.tsx
8278
8847
  var import_react10 = require("react");
8279
8848
  var import_react_dom2 = require("react-dom");
8280
- var import_lucide_react12 = require("lucide-react");
8849
+ var import_lucide_react13 = require("lucide-react");
8281
8850
  var import_navigation2 = require("next/navigation");
8282
- var import_jsx_runtime24 = require("react/jsx-runtime");
8851
+ var import_jsx_runtime25 = require("react/jsx-runtime");
8283
8852
  var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
8284
8853
  function rectsEqual(a, b) {
8285
8854
  if (a.size !== b.size) return false;
@@ -8508,7 +9077,7 @@ function SectionPickerOverlay({
8508
9077
  const portalRoot = typeof document !== "undefined" ? document.querySelector("[data-ohw-bridge-root]") ?? document.body : null;
8509
9078
  if (!portalRoot) return null;
8510
9079
  return (0, import_react_dom2.createPortal)(
8511
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9080
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8512
9081
  "div",
8513
9082
  {
8514
9083
  "data-ohw-section-picker": "",
@@ -8518,12 +9087,12 @@ function SectionPickerOverlay({
8518
9087
  role: "dialog",
8519
9088
  "aria-label": "Choose a section",
8520
9089
  children: [
8521
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9090
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8522
9091
  "div",
8523
9092
  {
8524
9093
  className: "pointer-events-auto fixed left-5 z-[2]",
8525
9094
  style: { top: chromeClip.top + 20 },
8526
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9095
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8527
9096
  Button,
8528
9097
  {
8529
9098
  type: "button",
@@ -8532,14 +9101,14 @@ function SectionPickerOverlay({
8532
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",
8533
9102
  onClick: onBack,
8534
9103
  children: [
8535
- /* @__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 }),
8536
9105
  "Back"
8537
9106
  ]
8538
9107
  }
8539
9108
  )
8540
9109
  }
8541
9110
  ),
8542
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9111
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8543
9112
  "div",
8544
9113
  {
8545
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",
@@ -8552,7 +9121,7 @@ function SectionPickerOverlay({
8552
9121
  children: "Click on section to select"
8553
9122
  }
8554
9123
  ),
8555
- !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9124
+ !isOnTargetPage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8556
9125
  "div",
8557
9126
  {
8558
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",
@@ -8560,14 +9129,14 @@ function SectionPickerOverlay({
8560
9129
  children: "Loading page preview\u2026"
8561
9130
  }
8562
9131
  ) : null,
8563
- 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,
8564
9133
  isOnTargetPage ? liveSections.map((section) => {
8565
9134
  const rect = rects.get(section.id);
8566
9135
  if (!rect || rect.width <= 0 || rect.height <= 0) return null;
8567
9136
  const isSelected = selectedId === section.id;
8568
9137
  const isHovered = hoveredId === section.id;
8569
9138
  const isLit = isSelected || isHovered;
8570
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
9139
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8571
9140
  "button",
8572
9141
  {
8573
9142
  type: "button",
@@ -8582,7 +9151,7 @@ function SectionPickerOverlay({
8582
9151
  "aria-label": `Select section ${section.label}`,
8583
9152
  onClick: () => handleSelect(section),
8584
9153
  children: [
8585
- isLit ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9154
+ isLit ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8586
9155
  "span",
8587
9156
  {
8588
9157
  className: "pointer-events-none absolute",
@@ -8595,13 +9164,13 @@ function SectionPickerOverlay({
8595
9164
  "aria-hidden": true
8596
9165
  }
8597
9166
  ) : null,
8598
- isSelected ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9167
+ isSelected ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8599
9168
  "span",
8600
9169
  {
8601
9170
  className: "absolute right-3 top-3 flex size-8 items-center justify-center rounded-full text-white",
8602
9171
  style: { backgroundColor: "var(--ohw-primary, #0885fe)" },
8603
9172
  "aria-hidden": true,
8604
- 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" })
8605
9174
  }
8606
9175
  ) : null
8607
9176
  ]
@@ -8781,7 +9350,7 @@ function useLinkModalState({
8781
9350
  }
8782
9351
 
8783
9352
  // src/ui/link-modal/LinkPopover.tsx
8784
- var import_jsx_runtime25 = require("react/jsx-runtime");
9353
+ var import_jsx_runtime26 = require("react/jsx-runtime");
8785
9354
  function postToParent(data) {
8786
9355
  window.parent?.postMessage(data, "*");
8787
9356
  }
@@ -8877,15 +9446,15 @@ function LinkPopover({
8877
9446
  );
8878
9447
  };
8879
9448
  }, [open, sectionPickerActive]);
8880
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
8881
- /* @__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)(
8882
9451
  Dialog2,
8883
9452
  {
8884
9453
  open: open && !sectionPickerActive,
8885
9454
  onOpenChange: (next) => {
8886
9455
  if (!next) onClose?.();
8887
9456
  },
8888
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9457
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8889
9458
  DialogContent,
8890
9459
  {
8891
9460
  ref: panelRef,
@@ -8895,12 +9464,12 @@ function LinkPopover({
8895
9464
  "data-ohw-bridge": "",
8896
9465
  showCloseButton: false,
8897
9466
  className: "gap-0 p-0 w-full max-w-[448px] pointer-events-auto z-[2147483646] overflow-visible",
8898
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LinkEditorPanel, { state, onClose })
9467
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(LinkEditorPanel, { state, onClose })
8899
9468
  }
8900
9469
  )
8901
9470
  }
8902
9471
  ),
8903
- sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
9472
+ sectionPickerActive && state.selectedPage ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
8904
9473
  SectionPickerOverlay,
8905
9474
  {
8906
9475
  pagePath: state.selectedPage.path,
@@ -10126,13 +10695,14 @@ function listSocialItems(row) {
10126
10695
  return isSocialItem(anchor) ? anchor : null;
10127
10696
  }).filter((item) => item !== null);
10128
10697
  }
10129
- function socialRowUnit(item) {
10130
- const row = findSocialsRow(item);
10698
+ function socialRowUnit(item, knownRow) {
10699
+ const row = knownRow ?? findSocialsRow(item);
10700
+ if (!row || !row.contains(item)) return null;
10131
10701
  let node = item;
10132
10702
  while (node.parentElement && node.parentElement !== row) {
10133
10703
  node = node.parentElement;
10134
10704
  }
10135
- return node;
10705
+ return node.parentElement === row ? node : null;
10136
10706
  }
10137
10707
  function listSocialsRows(root = document) {
10138
10708
  const rows = /* @__PURE__ */ new Set();
@@ -10151,7 +10721,8 @@ function markSocialsRows(root = document) {
10151
10721
  listSocialsRows(root).forEach((row) => {
10152
10722
  row.setAttribute(SOCIALS_ROW_ATTR, "");
10153
10723
  const items = listSocialItems(row);
10154
- 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);
10155
10726
  items.forEach((item, index) => {
10156
10727
  item.setAttribute(SOCIALS_ITEM_ATTR, String(index));
10157
10728
  const iconKey = socialIconKey(item);
@@ -10295,7 +10866,8 @@ function removeSocialItem(item, content) {
10295
10866
  const previousContent = Object.fromEntries(
10296
10867
  removedKeys.filter((key) => key in content).map((key) => [key, content[key]])
10297
10868
  );
10298
- const unit = socialRowUnit(item);
10869
+ const unit = socialRowUnit(item, row);
10870
+ if (!unit) return null;
10299
10871
  const nextSibling = unit.nextElementSibling;
10300
10872
  unit.remove();
10301
10873
  markSocialsRows(row.ownerDocument);
@@ -10318,7 +10890,9 @@ function applySocialsOrder(order, root = document) {
10318
10890
  const byKey = new Map(listSocialItems(row).map((item) => [socialHrefKey(item), item]));
10319
10891
  wanted.forEach((key) => {
10320
10892
  const item = byKey.get(key);
10321
- if (item) row.appendChild(socialRowUnit(item));
10893
+ if (!item) return;
10894
+ const unit = socialRowUnit(item, row);
10895
+ if (unit) row.appendChild(unit);
10322
10896
  });
10323
10897
  });
10324
10898
  markSocialsRows(root);
@@ -10348,7 +10922,7 @@ function reconcileSocialsFromContent(content, root = document) {
10348
10922
  });
10349
10923
  if (surviving.length) {
10350
10924
  present.forEach((item) => {
10351
- if (!surviving.includes(item)) socialRowUnit(item).remove();
10925
+ if (!surviving.includes(item)) socialRowUnit(item)?.remove();
10352
10926
  });
10353
10927
  }
10354
10928
  });
@@ -11684,8 +12258,8 @@ function addFooterColumnWithPersist({
11684
12258
 
11685
12259
  // src/ui/FloatingPanel.tsx
11686
12260
  var import_react13 = require("react");
11687
- var import_lucide_react13 = require("lucide-react");
11688
- 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");
11689
12263
  var PANEL_WIDTH = 256;
11690
12264
  var EDGE_MARGIN = 16;
11691
12265
  function getVisibleClip(parentScroll) {
@@ -11800,7 +12374,7 @@ function FloatingPanel({
11800
12374
  }, [open]);
11801
12375
  (0, import_react13.useEffect)(() => () => document.documentElement.removeAttribute("data-ohw-panel-dragging"), []);
11802
12376
  if (!open) return null;
11803
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
12377
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
11804
12378
  "div",
11805
12379
  {
11806
12380
  ref: panelRef,
@@ -11817,7 +12391,7 @@ function FloatingPanel({
11817
12391
  onPointerDown: (e) => e.stopPropagation(),
11818
12392
  onClick: (e) => e.stopPropagation(),
11819
12393
  children: [
11820
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
12394
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
11821
12395
  "div",
11822
12396
  {
11823
12397
  "data-ohw-floating-panel-header": "",
@@ -11827,14 +12401,14 @@ function FloatingPanel({
11827
12401
  onPointerUp: endDrag,
11828
12402
  onPointerCancel: endDrag,
11829
12403
  children: [
11830
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-1.5", children: [
11831
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center gap-2", children: [
11832
- icon ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "shrink-0 text-foreground", children: icon }) : null,
11833
- /* @__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 })
11834
12408
  ] }),
11835
- 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
11836
12410
  ] }),
11837
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
12411
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11838
12412
  "button",
11839
12413
  {
11840
12414
  type: "button",
@@ -11846,13 +12420,13 @@ function FloatingPanel({
11846
12420
  onClose();
11847
12421
  },
11848
12422
  onPointerDown: (e) => e.stopPropagation(),
11849
- 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 })
11850
12424
  }
11851
12425
  )
11852
12426
  ]
11853
12427
  }
11854
12428
  ),
11855
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
12429
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
11856
12430
  "div",
11857
12431
  {
11858
12432
  "data-ohw-floating-panel-body": "",
@@ -11866,30 +12440,30 @@ function FloatingPanel({
11866
12440
  }
11867
12441
 
11868
12442
  // src/ui/logo-size-panel.tsx
11869
- var import_lucide_react14 = require("lucide-react");
11870
- 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");
11871
12445
  function SizeSlider({
11872
12446
  value,
11873
12447
  onChange
11874
12448
  }) {
11875
12449
  const pct = (value - LOGO_SIZE_MIN) / (LOGO_SIZE_MAX - LOGO_SIZE_MIN) * 100;
11876
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full flex-col gap-3", children: [
11877
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full items-center gap-2 text-sm font-medium leading-5", children: [
11878
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "min-w-0 flex-1 text-foreground", children: "Size" }),
11879
- /* @__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: [
11880
12454
  value,
11881
12455
  " px"
11882
12456
  ] })
11883
12457
  ] }),
11884
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "relative h-2 w-full rounded-full bg-primary-50", children: [
11885
- /* @__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)(
11886
12460
  "div",
11887
12461
  {
11888
12462
  className: "absolute inset-y-0 left-0 rounded-full bg-primary",
11889
12463
  style: { width: `${pct}%` }
11890
12464
  }
11891
12465
  ),
11892
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
12466
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
11893
12467
  "input",
11894
12468
  {
11895
12469
  type: "range",
@@ -11926,14 +12500,14 @@ function LogoSizePanel({
11926
12500
  const showFollowing = viewport === "mobile" && mobileFollowing;
11927
12501
  const showMobileSlider = viewport === "mobile" && !mobileFollowing;
11928
12502
  const showDesktopSlider = viewport === "desktop";
11929
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("flex w-full flex-col gap-4", className), children: [
11930
- showFollowing ? /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex w-full flex-col gap-2", children: [
11931
- /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-start gap-1", children: [
11932
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react14.Link, { size: 16, className: "mt-0.5 shrink-0 text-foreground", "aria-hidden": true }),
11933
- /* @__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" })
11934
12508
  ] }),
11935
- /* @__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." }),
11936
- /* @__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)(
11937
12511
  Button,
11938
12512
  {
11939
12513
  type: "button",
@@ -11945,8 +12519,8 @@ function LogoSizePanel({
11945
12519
  }
11946
12520
  )
11947
12521
  ] }) : null,
11948
- showDesktopSlider || showMobileSlider ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SizeSlider, { value: sizePx, onChange: onSizeChange }) : null,
11949
- 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)(
11950
12524
  Button,
11951
12525
  {
11952
12526
  type: "button",
@@ -11957,8 +12531,8 @@ function LogoSizePanel({
11957
12531
  children: "Reset to desktop size"
11958
12532
  }
11959
12533
  ) : null,
11960
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "h-px w-full bg-border", role: "separator" }),
11961
- /* @__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)(
11962
12536
  Button,
11963
12537
  {
11964
12538
  type: "button",
@@ -11968,24 +12542,24 @@ function LogoSizePanel({
11968
12542
  onClick: onUpdateEverywhere,
11969
12543
  children: [
11970
12544
  "Update logo everywhere",
11971
- /* @__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 })
11972
12546
  ]
11973
12547
  }
11974
12548
  ),
11975
- /* @__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." })
11976
12550
  ] });
11977
12551
  }
11978
12552
 
11979
12553
  // src/ui/socials-display-panel.tsx
11980
- var import_jsx_runtime28 = require("react/jsx-runtime");
12554
+ var import_jsx_runtime29 = require("react/jsx-runtime");
11981
12555
  function DisplaySwitch({
11982
12556
  label,
11983
12557
  checked,
11984
12558
  disabled,
11985
12559
  onChange
11986
12560
  }) {
11987
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex w-full items-center gap-2", children: [
11988
- /* @__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)(
11989
12563
  "span",
11990
12564
  {
11991
12565
  className: cn(
@@ -11995,7 +12569,7 @@ function DisplaySwitch({
11995
12569
  children: label
11996
12570
  }
11997
12571
  ),
11998
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12572
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
11999
12573
  "button",
12000
12574
  {
12001
12575
  type: "button",
@@ -12009,7 +12583,7 @@ function DisplaySwitch({
12009
12583
  checked ? "bg-primary" : "bg-primary-50",
12010
12584
  disabled ? "cursor-default opacity-50" : "cursor-pointer"
12011
12585
  ),
12012
- children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12586
+ children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12013
12587
  "span",
12014
12588
  {
12015
12589
  className: cn(
@@ -12023,8 +12597,8 @@ function DisplaySwitch({
12023
12597
  ] });
12024
12598
  }
12025
12599
  function SocialsDisplayPanel({ display, onChange, className }) {
12026
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: cn("flex w-full flex-col gap-3", className), children: [
12027
- /* @__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)(
12028
12602
  DisplaySwitch,
12029
12603
  {
12030
12604
  label: "Text",
@@ -12033,7 +12607,7 @@ function SocialsDisplayPanel({ display, onChange, className }) {
12033
12607
  onChange: (text) => onChange({ ...display, text })
12034
12608
  }
12035
12609
  ),
12036
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
12610
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
12037
12611
  DisplaySwitch,
12038
12612
  {
12039
12613
  label: "Icon",
@@ -12593,8 +13167,8 @@ function useNavItemDrag({
12593
13167
  }
12594
13168
 
12595
13169
  // src/ui/footer-container-chrome.tsx
12596
- var import_lucide_react15 = require("lucide-react");
12597
- 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");
12598
13172
  function FooterContainerChrome({
12599
13173
  rect,
12600
13174
  onAdd,
@@ -12602,7 +13176,7 @@ function FooterContainerChrome({
12602
13176
  }) {
12603
13177
  const chromeGap = 6;
12604
13178
  const buttonMargin = 7;
12605
- 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)(
12606
13180
  "div",
12607
13181
  {
12608
13182
  "data-ohw-footer-container-chrome": "",
@@ -12614,8 +13188,8 @@ function FooterContainerChrome({
12614
13188
  width: rect.width + chromeGap * 2,
12615
13189
  height: rect.height + chromeGap * 2
12616
13190
  },
12617
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(Tooltip, { children: [
12618
- /* @__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)(
12619
13193
  "button",
12620
13194
  {
12621
13195
  type: "button",
@@ -12634,10 +13208,10 @@ function FooterContainerChrome({
12634
13208
  if (addDisabled) return;
12635
13209
  onAdd();
12636
13210
  },
12637
- 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 })
12638
13212
  }
12639
13213
  ) }),
12640
- /* @__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" })
12641
13215
  ] })
12642
13216
  }
12643
13217
  ) });
@@ -13097,14 +13671,14 @@ function deleteSelectedNavFooterItem(deps) {
13097
13671
  }
13098
13672
 
13099
13673
  // src/ui/navbar-container-chrome.tsx
13100
- var import_lucide_react16 = require("lucide-react");
13101
- 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");
13102
13676
  function NavbarContainerChrome({
13103
13677
  rect,
13104
13678
  onAdd
13105
13679
  }) {
13106
13680
  const chromeGap = 6;
13107
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13681
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
13108
13682
  "div",
13109
13683
  {
13110
13684
  "data-ohw-navbar-container-chrome": "",
@@ -13116,7 +13690,7 @@ function NavbarContainerChrome({
13116
13690
  width: rect.width + chromeGap * 2,
13117
13691
  height: rect.height + chromeGap * 2
13118
13692
  },
13119
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
13693
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
13120
13694
  "button",
13121
13695
  {
13122
13696
  type: "button",
@@ -13133,7 +13707,7 @@ function NavbarContainerChrome({
13133
13707
  e.stopPropagation();
13134
13708
  onAdd();
13135
13709
  },
13136
- 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 })
13137
13711
  }
13138
13712
  )
13139
13713
  }
@@ -13142,7 +13716,7 @@ function NavbarContainerChrome({
13142
13716
 
13143
13717
  // src/ui/drop-indicator.tsx
13144
13718
  var React10 = __toESM(require("react"), 1);
13145
- var import_jsx_runtime31 = require("react/jsx-runtime");
13719
+ var import_jsx_runtime32 = require("react/jsx-runtime");
13146
13720
  var dropIndicatorVariants = cva(
13147
13721
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
13148
13722
  {
@@ -13166,7 +13740,7 @@ var dropIndicatorVariants = cva(
13166
13740
  );
13167
13741
  var DropIndicator = React10.forwardRef(
13168
13742
  ({ className, direction, state, ...props }, ref) => {
13169
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
13743
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
13170
13744
  "div",
13171
13745
  {
13172
13746
  ref,
@@ -13183,7 +13757,7 @@ var DropIndicator = React10.forwardRef(
13183
13757
  DropIndicator.displayName = "DropIndicator";
13184
13758
 
13185
13759
  // src/ui/badge.tsx
13186
- var import_jsx_runtime32 = require("react/jsx-runtime");
13760
+ var import_jsx_runtime33 = require("react/jsx-runtime");
13187
13761
  var badgeVariants = cva(
13188
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",
13189
13763
  {
@@ -13201,12 +13775,12 @@ var badgeVariants = cva(
13201
13775
  }
13202
13776
  );
13203
13777
  function Badge({ className, variant, ...props }) {
13204
- 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 });
13205
13779
  }
13206
13780
 
13207
13781
  // src/OhhwellsBridge.tsx
13208
- var import_lucide_react17 = require("lucide-react");
13209
- 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");
13210
13784
  var PRIMARY3 = "#0885FE";
13211
13785
  var IMAGE_FADE_MS = 300;
13212
13786
  function runOpacityFade(el, onDone) {
@@ -13375,7 +13949,7 @@ function mountSchedulingWidget(anchorId, notifyOnConnect = false, scheduleId, be
13375
13949
  const root = (0, import_client2.createRoot)(container);
13376
13950
  (0, import_react_dom3.flushSync)(() => {
13377
13951
  root.render(
13378
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
13952
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
13379
13953
  SchedulingWidget,
13380
13954
  {
13381
13955
  notifyOnConnect,
@@ -13490,7 +14064,7 @@ function isIconEditable(el) {
13490
14064
  return el.dataset.ohwEditable === "icon";
13491
14065
  }
13492
14066
  var MEDIA_SELECTOR = '[data-ohw-editable="image"], [data-ohw-editable="bg-image"], [data-ohw-editable="video"]';
13493
- var NON_MEDIA_SELECTOR = '[data-ohw-editable]:not([data-ohw-editable="image"]):not([data-ohw-editable="bg-image"]):not([data-ohw-editable="video"]):not([data-ohw-editable="icon"])';
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"])';
13494
14068
  function getVideoEl2(el) {
13495
14069
  return el instanceof HTMLVideoElement ? el : el.querySelector("video");
13496
14070
  }
@@ -14051,7 +14625,7 @@ function EditGlowChrome({
14051
14625
  hideHandle = false
14052
14626
  }) {
14053
14627
  const GAP = SELECTION_CHROME_GAP2;
14054
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
14628
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
14055
14629
  "div",
14056
14630
  {
14057
14631
  ref: elRef,
@@ -14066,7 +14640,7 @@ function EditGlowChrome({
14066
14640
  zIndex: 2147483646
14067
14641
  },
14068
14642
  children: [
14069
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14643
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14070
14644
  "div",
14071
14645
  {
14072
14646
  style: {
@@ -14079,7 +14653,7 @@ function EditGlowChrome({
14079
14653
  }
14080
14654
  }
14081
14655
  ),
14082
- reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14656
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14083
14657
  "div",
14084
14658
  {
14085
14659
  "data-ohw-drag-handle-container": "",
@@ -14091,7 +14665,7 @@ function EditGlowChrome({
14091
14665
  transform: "translate(calc(-100% - 7px), -50%)",
14092
14666
  pointerEvents: dragDisabled ? "none" : "auto"
14093
14667
  },
14094
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14668
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14095
14669
  DragHandle,
14096
14670
  {
14097
14671
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -14301,7 +14875,7 @@ function FloatingToolbar({
14301
14875
  return () => ro.disconnect();
14302
14876
  }, [showEditLink, activeCommands]);
14303
14877
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
14304
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14878
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14305
14879
  "div",
14306
14880
  {
14307
14881
  ref: setRefs,
@@ -14313,12 +14887,12 @@ function FloatingToolbar({
14313
14887
  zIndex: 2147483647,
14314
14888
  pointerEvents: "auto"
14315
14889
  },
14316
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(CustomToolbar, { children: [
14317
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_react16.default.Fragment, { children: [
14318
- 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, {}),
14319
14893
  btns.map((btn) => {
14320
14894
  const isActive = activeCommands.has(btn.cmd);
14321
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14895
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14322
14896
  CustomToolbarButton,
14323
14897
  {
14324
14898
  title: btn.title,
@@ -14327,7 +14901,7 @@ function FloatingToolbar({
14327
14901
  e.preventDefault();
14328
14902
  onCommand(btn.cmd);
14329
14903
  },
14330
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14904
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14331
14905
  "svg",
14332
14906
  {
14333
14907
  width: "16",
@@ -14348,7 +14922,7 @@ function FloatingToolbar({
14348
14922
  );
14349
14923
  })
14350
14924
  ] }, gi)),
14351
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14925
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14352
14926
  CustomToolbarButton,
14353
14927
  {
14354
14928
  type: "button",
@@ -14362,7 +14936,7 @@ function FloatingToolbar({
14362
14936
  e.preventDefault();
14363
14937
  e.stopPropagation();
14364
14938
  },
14365
- 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 })
14366
14940
  }
14367
14941
  ) : null
14368
14942
  ] })
@@ -14379,7 +14953,7 @@ function StateToggle({
14379
14953
  states,
14380
14954
  onStateChange
14381
14955
  }) {
14382
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
14956
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
14383
14957
  ToggleGroup,
14384
14958
  {
14385
14959
  "data-ohw-state-toggle": "",
@@ -14393,7 +14967,7 @@ function StateToggle({
14393
14967
  left: rect.right - 8,
14394
14968
  transform: "translateX(-100%)"
14395
14969
  },
14396
- 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))
14397
14971
  }
14398
14972
  );
14399
14973
  }
@@ -14516,6 +15090,157 @@ function OhhwellsBridge() {
14516
15090
  const sectionsLoadedRef = (0, import_react16.useRef)(false);
14517
15091
  const pendingScheduleConfigRequests = (0, import_react16.useRef)([]);
14518
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]);
14519
15244
  const [toolbarVariant, setToolbarVariant] = (0, import_react16.useState)("none");
14520
15245
  const toolbarVariantRef = (0, import_react16.useRef)("none");
14521
15246
  toolbarVariantRef.current = toolbarVariant;
@@ -14537,7 +15262,7 @@ function OhhwellsBridge() {
14537
15262
  (0, import_react16.useEffect)(() => {
14538
15263
  const sync = () => {
14539
15264
  const el = document.querySelector(
14540
- "[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"] *)'
14541
15266
  );
14542
15267
  const target = el && !el.closest("[data-ohw-href-key]") ? el : null;
14543
15268
  if (!target) {
@@ -15669,6 +16394,7 @@ function OhhwellsBridge() {
15669
16394
  setFloatingPanel(null);
15670
16395
  setLogoSizeDraft(null);
15671
16396
  }, []);
16397
+ closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
15672
16398
  const closeFloatingPanelAndDeselect = (0, import_react16.useCallback)(() => {
15673
16399
  setFloatingPanel(null);
15674
16400
  setLogoSizeDraft(null);
@@ -15924,6 +16650,98 @@ function OhhwellsBridge() {
15924
16650
  cancelled = true;
15925
16651
  };
15926
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]);
15927
16745
  (0, import_react16.useEffect)(() => {
15928
16746
  if (!subdomain || isEditMode) return;
15929
16747
  let debounceTimer = null;
@@ -16157,7 +16975,9 @@ function OhhwellsBridge() {
16157
16975
  [style*="100vh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
16158
16976
  [style*="100svh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
16159
16977
  [style*="100dvh"] { min-height: ${initialVh}px !important; height: ${initialVh}px !important; }
16160
- [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"]) {
16161
16981
  display: block;
16162
16982
  }
16163
16983
  /* Body text (no item-action toolbar) \u2014 first click enters text edit \u2192 I-beam.
@@ -16183,6 +17003,35 @@ function OhhwellsBridge() {
16183
17003
  [data-ohw-editable="video"], [data-ohw-editable="video"] *,
16184
17004
  [data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
16185
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
+ }
16186
17035
  /* Text hover chrome is drawn by the overlay (see hoveredTextRect) \u2014 the CSS outline
16187
17036
  that used to draw it dashes denser than the overlay border, so identical specs
16188
17037
  still read as two different frames (OHH-695). The attribute stays: hover paths
@@ -16269,6 +17118,49 @@ function OhhwellsBridge() {
16269
17118
  if (target.closest("[data-ohw-max-badge]")) return;
16270
17119
  if (isInsideLinkEditor(target)) return;
16271
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
+ }
16272
17164
  if (target.closest('[data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-drag-handle-container], [data-slot="drag-handle"]')) {
16273
17165
  const beneath = document.elementsFromPoint(e.clientX, e.clientY).find(
16274
17166
  (el) => el instanceof HTMLElement && !el.closest("[data-ohw-bridge-root]") && el.closest("[data-ohw-section]") != null
@@ -16608,6 +17500,26 @@ function OhhwellsBridge() {
16608
17500
  return;
16609
17501
  }
16610
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
+ }
16611
17523
  if (!editable) return;
16612
17524
  const selected = selectedElRef.current;
16613
17525
  if (selected && (selected === editable || selected.contains(editable))) return;
@@ -17244,6 +18156,13 @@ function OhhwellsBridge() {
17244
18156
  setSectionGap(null);
17245
18157
  }
17246
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
+ };
17247
18166
  const handleMouseMove = (e) => {
17248
18167
  const { clientX, clientY } = e;
17249
18168
  if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
@@ -17809,6 +18728,13 @@ function OhhwellsBridge() {
17809
18728
  }
17810
18729
  }
17811
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);
17812
18738
  window.addEventListener("message", handleUiEscape);
17813
18739
  const handleKeyDown = (e) => {
17814
18740
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
@@ -17828,6 +18754,11 @@ function OhhwellsBridge() {
17828
18754
  closeFloatingPanelOnlyRef.current();
17829
18755
  return;
17830
18756
  }
18757
+ if (e.key === "Escape" && formPickElRef.current) {
18758
+ e.preventDefault();
18759
+ clearFormPickRef.current();
18760
+ return;
18761
+ }
17831
18762
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
17832
18763
  if (toolbarVariantRef.current === "logo") {
17833
18764
  deselectRef.current();
@@ -18380,6 +19311,7 @@ function OhhwellsBridge() {
18380
19311
  window.removeEventListener("message", handleGetBrand);
18381
19312
  window.removeEventListener("message", handleDeactivate);
18382
19313
  window.removeEventListener("message", handleToastAction);
19314
+ window.removeEventListener("message", handleFormCount);
18383
19315
  window.removeEventListener("message", handleUiEscape);
18384
19316
  autoSaveTimers.current.forEach(clearTimeout);
18385
19317
  autoSaveTimers.current.clear();
@@ -18403,7 +19335,9 @@ function OhhwellsBridge() {
18403
19335
  if (footerDragRef.current) return;
18404
19336
  const target = e.target;
18405
19337
  if (!target) return;
18406
- 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
+ )) {
18407
19341
  return;
18408
19342
  }
18409
19343
  if (target.closest("[data-ohw-item-drag-surface]")) return;
@@ -18976,10 +19910,10 @@ function OhhwellsBridge() {
18976
19910
  [postToParent2]
18977
19911
  );
18978
19912
  return bridgeRoot ? (0, import_react_dom4.createPortal)(
18979
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
18980
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
18981
- isEditMode && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AiSectionOverlay, { postToParent: postToParent2, apiRef: aiSectionApiRef }),
18982
- 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)(
18983
19917
  MediaOverlay,
18984
19918
  {
18985
19919
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -18990,7 +19924,7 @@ function OhhwellsBridge() {
18990
19924
  },
18991
19925
  `uploading-${key}`
18992
19926
  )),
18993
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19927
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
18994
19928
  MediaOverlay,
18995
19929
  {
18996
19930
  hover: mediaHover,
@@ -18999,11 +19933,11 @@ function OhhwellsBridge() {
18999
19933
  onVideoSettingsChange: handleVideoSettingsChange
19000
19934
  }
19001
19935
  ),
19002
- carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(CarouselOverlay, { hover: carouselHover, onEdit: handleEditCarousel }),
19003
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
19004
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
19005
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
19006
- 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)(
19007
19941
  "div",
19008
19942
  {
19009
19943
  className: "pointer-events-none fixed z-2147483646",
@@ -19013,7 +19947,7 @@ function OhhwellsBridge() {
19013
19947
  width: slot.width,
19014
19948
  height: slot.height
19015
19949
  },
19016
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19950
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19017
19951
  DropIndicator,
19018
19952
  {
19019
19953
  direction: slot.direction,
@@ -19024,7 +19958,7 @@ function OhhwellsBridge() {
19024
19958
  },
19025
19959
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
19026
19960
  )),
19027
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19961
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19028
19962
  "div",
19029
19963
  {
19030
19964
  className: "pointer-events-none fixed z-2147483646",
@@ -19034,7 +19968,7 @@ function OhhwellsBridge() {
19034
19968
  width: slot.width,
19035
19969
  height: slot.height
19036
19970
  },
19037
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
19971
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19038
19972
  DropIndicator,
19039
19973
  {
19040
19974
  direction: slot.direction,
@@ -19045,11 +19979,179 @@ function OhhwellsBridge() {
19045
19979
  },
19046
19980
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
19047
19981
  )),
19048
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
19049
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
19050
- hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
19051
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
19052
- 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)(
19053
20155
  FooterContainerChrome,
19054
20156
  {
19055
20157
  rect: toolbarRect,
@@ -19057,7 +20159,7 @@ function OhhwellsBridge() {
19057
20159
  addDisabled: !canAddFooterColumn()
19058
20160
  }
19059
20161
  ),
19060
- 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)(
19061
20163
  ItemInteractionLayer,
19062
20164
  {
19063
20165
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -19072,7 +20174,7 @@ function OhhwellsBridge() {
19072
20174
  onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
19073
20175
  onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
19074
20176
  itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection,
19075
- 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)(
19076
20178
  ItemActionToolbar,
19077
20179
  {
19078
20180
  onEditLink: openLinkPopoverForSelected,
@@ -19108,8 +20210,8 @@ function OhhwellsBridge() {
19108
20210
  ) : void 0
19109
20211
  }
19110
20212
  ),
19111
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
19112
- /* @__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)(
19113
20215
  EditGlowChrome,
19114
20216
  {
19115
20217
  rect: toolbarRect,
@@ -19119,7 +20221,7 @@ function OhhwellsBridge() {
19119
20221
  hideHandle: isItemDragging
19120
20222
  }
19121
20223
  ),
19122
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20224
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19123
20225
  FloatingToolbar,
19124
20226
  {
19125
20227
  rect: toolbarRect,
@@ -19132,7 +20234,7 @@ function OhhwellsBridge() {
19132
20234
  }
19133
20235
  )
19134
20236
  ] }),
19135
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20237
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
19136
20238
  "div",
19137
20239
  {
19138
20240
  "data-ohw-max-badge": "",
@@ -19158,7 +20260,7 @@ function OhhwellsBridge() {
19158
20260
  ]
19159
20261
  }
19160
20262
  ),
19161
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20263
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19162
20264
  StateToggle,
19163
20265
  {
19164
20266
  rect: toggleState.rect,
@@ -19167,15 +20269,15 @@ function OhhwellsBridge() {
19167
20269
  onStateChange: handleStateChange
19168
20270
  }
19169
20271
  ),
19170
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
20272
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
19171
20273
  "div",
19172
20274
  {
19173
20275
  "data-ohw-section-insert-line": "",
19174
20276
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
19175
20277
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
19176
20278
  children: [
19177
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
19178
- /* @__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)(
19179
20281
  Badge,
19180
20282
  {
19181
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",
@@ -19192,11 +20294,11 @@ function OhhwellsBridge() {
19192
20294
  children: "Add Section"
19193
20295
  }
19194
20296
  ),
19195
- /* @__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 } })
19196
20298
  ]
19197
20299
  }
19198
20300
  ),
19199
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20301
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19200
20302
  LinkPopover,
19201
20303
  {
19202
20304
  panelRef: linkPopoverPanelRef,
@@ -19213,7 +20315,7 @@ function OhhwellsBridge() {
19213
20315
  },
19214
20316
  linkPopover.key
19215
20317
  ) : null,
19216
- floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20318
+ floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19217
20319
  FloatingPanel,
19218
20320
  {
19219
20321
  open: true,
@@ -19223,7 +20325,7 @@ function OhhwellsBridge() {
19223
20325
  onPositionChange: setFloatingPanelPos,
19224
20326
  parentScroll: parentScrollSnap ?? parentScrollRef.current,
19225
20327
  onClose: closeFloatingPanelOnly,
19226
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20328
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19227
20329
  SocialsDisplayPanel,
19228
20330
  {
19229
20331
  display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
@@ -19235,7 +20337,7 @@ function OhhwellsBridge() {
19235
20337
  )
19236
20338
  }
19237
20339
  ) : null,
19238
- 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)(
19239
20341
  FloatingPanel,
19240
20342
  {
19241
20343
  open: true,
@@ -19245,7 +20347,7 @@ function OhhwellsBridge() {
19245
20347
  onPositionChange: setFloatingPanelPos,
19246
20348
  parentScroll: parentScrollSnap ?? parentScrollRef.current,
19247
20349
  onClose: closeFloatingPanelAndDeselect,
19248
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
20350
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
19249
20351
  LogoSizePanel,
19250
20352
  {
19251
20353
  viewport: editorViewport,
@@ -19293,10 +20395,10 @@ function OhhwellsBridge() {
19293
20395
 
19294
20396
  // src/ui/EmptySection.tsx
19295
20397
  var import_link = __toESM(require("next/link"), 1);
19296
- var import_jsx_runtime34 = require("react/jsx-runtime");
20398
+ var import_jsx_runtime35 = require("react/jsx-runtime");
19297
20399
  function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey }) {
19298
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
19299
- /* @__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)(
19300
20402
  "p",
19301
20403
  {
19302
20404
  style: {
@@ -19308,10 +20410,10 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
19308
20410
  color: "var(--brand-accent)",
19309
20411
  marginBottom: "1.5rem"
19310
20412
  },
19311
- 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" }) })
19312
20414
  }
19313
20415
  ),
19314
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20416
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
19315
20417
  "h1",
19316
20418
  {
19317
20419
  style: {
@@ -19326,7 +20428,7 @@ function EmptySection({ title, homeHref = "/", eyebrowKey, titleKey, subtitleKey
19326
20428
  children: title
19327
20429
  }
19328
20430
  ),
19329
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
20431
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
19330
20432
  "p",
19331
20433
  {
19332
20434
  style: {