@ohhwells/bridge 0.1.46-next.109 → 0.1.46

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
@@ -115,7 +115,6 @@ var import_react3 = require("react");
115
115
  var import_react2 = require("react");
116
116
  var import_radix_ui = require("radix-ui");
117
117
  var import_jsx_runtime = require("react/jsx-runtime");
118
- var isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
119
118
  function Spinner() {
120
119
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
121
120
  "svg",
@@ -149,17 +148,12 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
149
148
  const [error, setError] = (0, import_react2.useState)(null);
150
149
  const isBook = title === "Confirm your spot";
151
150
  const handleSubmit = async () => {
152
- const trimmed = email.trim();
153
- if (!trimmed) return;
154
- if (!isValidEmail(trimmed)) {
155
- setError("Please enter a valid email address.");
156
- return;
157
- }
151
+ if (!email.trim()) return;
158
152
  setLoading(true);
159
153
  setError(null);
160
154
  try {
161
- await onSubmit(trimmed);
162
- setSubmittedEmail(trimmed);
155
+ await onSubmit(email.trim());
156
+ setSubmittedEmail(email.trim());
163
157
  setSuccess(true);
164
158
  } catch (e) {
165
159
  setError(e instanceof Error ? e.message : "Something went wrong. Please try again.");
@@ -234,10 +228,7 @@ function EmailCaptureModal({ title, subtitle, onSubmit, onClose }) {
234
228
  {
235
229
  type: "email",
236
230
  value: email,
237
- onChange: (e) => {
238
- setEmail(e.target.value);
239
- if (error) setError(null);
240
- },
231
+ onChange: (e) => setEmail(e.target.value),
241
232
  onKeyDown: handleKeyDown,
242
233
  placeholder: "hello@gmail.com",
243
234
  autoFocus: true,
@@ -294,20 +285,12 @@ function formatClassTime(cls) {
294
285
  const em = endTotal % 60;
295
286
  return `${h}:${cls.startTime.minutes}-${eh}:${String(em).padStart(2, "0")}`;
296
287
  }
297
- function formatBookingLabel(cls) {
298
- const price = cls.price;
299
- const isFree = price === null || price === void 0 || `${price}` === "" || `${price}` === "0";
300
- return isFree ? "Book for free" : `Book for ${cls.currency ?? ""} ${price}`.trim();
301
- }
302
288
  function getBookingsOnDate(cls, date) {
303
289
  if (!cls.bookings?.length) return 0;
304
- const target = new Date(date);
305
- target.setHours(0, 0, 0, 0);
290
+ const ds = date.toISOString().split("T")[0];
306
291
  return cls.bookings.filter((b) => {
307
292
  try {
308
- const bookingDate = new Date(b.classDate);
309
- bookingDate.setHours(0, 0, 0, 0);
310
- return bookingDate.getTime() === target.getTime();
293
+ return new Date(b.classDate).toISOString().split("T")[0] === ds;
311
294
  } catch {
312
295
  return false;
313
296
  }
@@ -572,7 +555,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
572
555
  }
573
556
  )
574
557
  ] }),
575
- cls.showAvailability !== false && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
558
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "sm:hidden flex flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
576
559
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
577
560
  available,
578
561
  "/",
@@ -584,17 +567,9 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
584
567
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-1 flex-col gap-2 min-w-0 sm:contents", children: [
585
568
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex-1 flex flex-col gap-2 min-w-0", children: [
586
569
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-bold text-(--color-dark,#200C02) block truncate", children: cls.name }),
587
- cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName }),
588
- cls.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
589
- "span",
590
- {
591
- className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block",
592
- style: { wordBreak: "break-word" },
593
- children: cls.description
594
- }
595
- )
570
+ cls.hostName && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-base font-normal text-(--color-dark,#200C02) opacity-80 block truncate", children: cls.hostName })
596
571
  ] }),
597
- cls.showAvailability !== false && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
572
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hidden sm:flex w-14 shrink-0 flex-col gap-px", children: isFull ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: "Full" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
598
573
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-body text-sm text-(--color-dark,#200C02) opacity-80", children: [
599
574
  available,
600
575
  "/",
@@ -619,7 +594,7 @@ function ScheduleView({ schedule, dates, selectedIdx, onSelectDate, onOpenModal
619
594
  if (!cls.id) return;
620
595
  onOpenModal?.(isFull ? "waitlist" : "book", cls.id, selectedDate);
621
596
  },
622
- children: isFull ? "Join Waitlist" : formatBookingLabel(cls)
597
+ children: isFull ? "Join Waitlist" : "Book Now"
623
598
  }
624
599
  )
625
600
  ] })
@@ -661,17 +636,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
661
636
  const [isHovered, setIsHovered] = (0, import_react3.useState)(false);
662
637
  const [modalState, setModalState] = (0, import_react3.useState)(null);
663
638
  const switchScheduleIdRef = (0, import_react3.useRef)(null);
664
- const liveScheduleIdRef = (0, import_react3.useRef)(null);
665
- const refetchLiveSchedule = (0, import_react3.useCallback)(async () => {
666
- const id = liveScheduleIdRef.current;
667
- if (!id) return;
668
- try {
669
- const res = await fetch(`${API_URL}/api/schedule/id/${id}`);
670
- const data = await res.json();
671
- if (data?.id) setSchedule(data);
672
- } catch {
673
- }
674
- }, []);
675
639
  const dates = (0, import_react3.useMemo)(() => {
676
640
  const today = /* @__PURE__ */ new Date();
677
641
  today.setHours(0, 0, 0, 0);
@@ -691,18 +655,6 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
691
655
  }
692
656
  }
693
657
  }, [schedule, dates]);
694
- (0, import_react3.useEffect)(() => {
695
- if (typeof window === "undefined") return;
696
- const onVisible = () => {
697
- if (!document.hidden) void refetchLiveSchedule();
698
- };
699
- window.addEventListener("focus", refetchLiveSchedule);
700
- document.addEventListener("visibilitychange", onVisible);
701
- return () => {
702
- window.removeEventListener("focus", refetchLiveSchedule);
703
- document.removeEventListener("visibilitychange", onVisible);
704
- };
705
- }, [refetchLiveSchedule]);
706
658
  (0, import_react3.useEffect)(() => {
707
659
  if (typeof window === "undefined") return;
708
660
  const isInEditor = window.self !== window.top;
@@ -764,7 +716,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
764
716
  setLoading(false);
765
717
  return;
766
718
  }
767
- liveScheduleIdRef.current = effectiveId;
719
+ ;
768
720
  (async () => {
769
721
  try {
770
722
  const res = await fetch(`${API_URL}/api/schedule/id/${effectiveId}`);
@@ -821,14 +773,18 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
821
773
  const data = await res.json().catch(() => ({}));
822
774
  throw new Error(data?.message ?? "Something went wrong. Please try again.");
823
775
  }
824
- await refetchLiveSchedule();
825
776
  };
826
777
  const handleReplaceSchedule = () => {
827
778
  setIsHovered(false);
828
- window.parent.postMessage(
829
- { type: "ow:scheduling-not-connected", insertAfter, currentScheduleId: schedule?.id },
830
- "*"
831
- );
779
+ if (schedule) {
780
+ window.parent.postMessage({
781
+ type: "ow:schedule-connected",
782
+ schedule: { id: schedule.id, name: schedule.name },
783
+ insertAfter
784
+ }, "*");
785
+ } else {
786
+ window.parent.postMessage({ type: "ow:scheduling-not-connected", insertAfter }, "*");
787
+ }
832
788
  };
833
789
  if (!inEditor && !loading && !schedule) return null;
834
790
  const sectionId = `scheduling-${insertAfter}`;
@@ -871,19 +827,7 @@ function SchedulingWidget({ notifyOnConnect = false, initialScheduleId, insertAf
871
827
  ),
872
828
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "max-w-[1280px] mx-auto flex flex-col items-center gap-16", children: [
873
829
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
874
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
875
- "h2",
876
- {
877
- className: "font-display text-center m-0 text-(--color-dark,#200C02)",
878
- style: {
879
- fontSize: "var(--fs-section-h2, clamp(40px, 4.4vw, 64px))",
880
- fontWeight: "var(--font-weight-heading, 400)",
881
- lineHeight: 1.05,
882
- letterSpacing: "-0.02em"
883
- },
884
- children: schedule?.name ?? "Book an appointment"
885
- }
886
- ),
830
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "font-display text-4xl sm:text-5xl font-bold text-center m-0 text-(--color-dark,#200C02)", children: schedule?.name ?? "Book an appointment" }),
887
831
  schedule?.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "font-body text-body text-center m-0 text-(--color-accent,#A89B83)", children: schedule.description })
888
832
  ] }),
889
833
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "w-full flex flex-col items-end gap-3", children: [
@@ -4943,11 +4887,7 @@ function MediaOverlay({
4943
4887
  variant: "outline",
4944
4888
  size: "sm",
4945
4889
  className: "gap-1.5 cursor-pointer hover:bg-background",
4946
- style: {
4947
- ...OVERLAY_BUTTON_STYLE,
4948
- // Don't let Replace steal clicks when text (e.g. nav) sits on top of this media.
4949
- pointerEvents: hover.hasTextOverlap ? "none" : "auto"
4950
- },
4890
+ style: OVERLAY_BUTTON_STYLE,
4951
4891
  onMouseDown: (e) => e.preventDefault(),
4952
4892
  onClick: (e) => {
4953
4893
  e.stopPropagation();
@@ -6721,8 +6661,6 @@ function applyNavOrderToContainer(container, order) {
6721
6661
  if (current.length === expected.length && current.every((key, i) => key === expected[i])) {
6722
6662
  return;
6723
6663
  }
6724
- const lastCurrentLinkEl = current.length > 0 ? findCounterpartByHrefKey(current[current.length - 1], container) : null;
6725
- const anchor = lastCurrentLinkEl?.parentElement === container ? lastCurrentLinkEl.nextElementSibling : null;
6726
6664
  const seen = /* @__PURE__ */ new Set();
6727
6665
  for (const hrefKey of desired) {
6728
6666
  if (seen.has(hrefKey)) continue;
@@ -6737,9 +6675,7 @@ function applyNavOrderToContainer(container, order) {
6737
6675
  orderedEls.push(el);
6738
6676
  }
6739
6677
  for (const el of orderedEls) {
6740
- if (anchor) {
6741
- if (el.nextSibling !== anchor) container.insertBefore(el, anchor);
6742
- } else if (container.lastElementChild !== el) {
6678
+ if (container.lastElementChild !== el) {
6743
6679
  container.appendChild(el);
6744
6680
  }
6745
6681
  }
@@ -7071,195 +7007,7 @@ function parseFooterOrder(content) {
7071
7007
  return null;
7072
7008
  }
7073
7009
  }
7074
- var FOOTER_HEADING_RE = /^footer-(\d+)-heading$/;
7075
- var FOOTER_LABEL_RE = /^footer-(\d+)-(\d+)-label$/;
7076
- var DEFAULT_FOOTER_COLUMN_HEADING = "New";
7077
- var DEFAULT_FOOTER_COLUMN_LINK_LABEL = "New link";
7078
- var DEFAULT_FOOTER_COLUMN_LINK_HREF = "";
7079
- function isFooterLinksContainer(el) {
7080
- return el.hasAttribute("data-ohw-footer-links") || el.classList.contains("rb-footer-links");
7081
- }
7082
- function getFooterColumnIndicesInDom() {
7083
- const indices = /* @__PURE__ */ new Set();
7084
- for (const col of listFooterColumns()) {
7085
- const attr = col.getAttribute("data-ohw-footer-col");
7086
- if (attr != null) {
7087
- const n = parseInt(attr, 10);
7088
- if (Number.isFinite(n)) indices.add(n);
7089
- }
7090
- for (const link of listFooterLinksInColumn(col)) {
7091
- const parsed = parseFooterHrefKey(link.getAttribute("data-ohw-href-key"));
7092
- if (parsed) indices.add(parsed.col);
7093
- }
7094
- const heading = col.querySelector('[data-ohw-key^="footer-"][data-ohw-key$="-heading"]');
7095
- const headingKey = heading?.getAttribute("data-ohw-key");
7096
- if (headingKey) {
7097
- const match = headingKey.match(FOOTER_HEADING_RE);
7098
- if (match) indices.add(parseInt(match[1], 10));
7099
- }
7100
- }
7101
- return [...indices].sort((a, b) => a - b);
7102
- }
7103
- function getNextFooterColumnIndex() {
7104
- const indices = getFooterColumnIndicesInDom();
7105
- if (indices.length === 0) return 0;
7106
- return Math.max(...indices) + 1;
7107
- }
7108
- function cloneFooterLinkShell(template) {
7109
- const anchor = document.createElement("a");
7110
- if (template) {
7111
- anchor.style.cssText = template.style.cssText;
7112
- if (template.className) anchor.className = template.className;
7113
- }
7114
- anchor.style.cursor = "pointer";
7115
- anchor.style.textDecoration = "none";
7116
- return anchor;
7117
- }
7118
- function buildFooterHeading(colIndex, text) {
7119
- const heading = document.createElement("p");
7120
- heading.setAttribute("data-ohw-editable", "text");
7121
- heading.setAttribute("data-ohw-key", `footer-${colIndex}-heading`);
7122
- heading.textContent = text;
7123
- heading.style.cssText = [
7124
- "color: var(--espresso, #3d312b)",
7125
- "font-size: 14px",
7126
- "font-weight: 800",
7127
- "opacity: 0.82",
7128
- "margin: 0 0 6px",
7129
- "padding: 0",
7130
- "line-height: 1.2"
7131
- ].join(";");
7132
- return heading;
7133
- }
7134
- function buildFooterLink(colIndex, itemIndex, href, label, template) {
7135
- const anchor = cloneFooterLinkShell(template);
7136
- anchor.setAttribute("href", href);
7137
- anchor.setAttribute("data-ohw-href-key", `footer-${colIndex}-${itemIndex}-href`);
7138
- const span = document.createElement("span");
7139
- span.setAttribute("data-ohw-editable", "text");
7140
- span.setAttribute("data-ohw-key", `footer-${colIndex}-${itemIndex}-label`);
7141
- span.textContent = label;
7142
- anchor.appendChild(span);
7143
- return anchor;
7144
- }
7145
- function footerColumnExistsInDom(colIndex) {
7146
- return document.querySelector(`[data-ohw-footer-col="${colIndex}"]`) !== null || document.querySelector(`[data-ohw-href-key^="footer-${colIndex}-"]`) !== null || document.querySelector(`[data-ohw-key="footer-${colIndex}-heading"]`) !== null;
7147
- }
7148
- function getFooterLinkTemplate() {
7149
- for (const col of listFooterColumns()) {
7150
- const link = listFooterLinksInColumn(col)[0];
7151
- if (link) return link;
7152
- }
7153
- return null;
7154
- }
7155
- function getFooterColumnTemplate() {
7156
- return listFooterColumns()[0] ?? null;
7157
- }
7158
- function insertFooterColumnDom(colIndex, heading, items) {
7159
- const container = getFooterLinksContainer();
7160
- if (!container) return null;
7161
- const colTemplate = getFooterColumnTemplate();
7162
- const linkTemplate = getFooterLinkTemplate();
7163
- const column = document.createElement("div");
7164
- if (colTemplate?.className) column.className = colTemplate.className;
7165
- else column.className = "rb-footer-link-col";
7166
- column.setAttribute("data-ohw-footer-col", String(colIndex));
7167
- if (colTemplate) {
7168
- const gap = getComputedStyle(colTemplate).gap;
7169
- if (gap && gap !== "normal") column.style.gap = gap;
7170
- column.style.display = getComputedStyle(colTemplate).display || "flex";
7171
- column.style.flexDirection = "column";
7172
- }
7173
- column.appendChild(buildFooterHeading(colIndex, heading));
7174
- let firstLink = null;
7175
- items.forEach((item, itemIndex) => {
7176
- const link = buildFooterLink(colIndex, itemIndex, item.href, item.label, linkTemplate);
7177
- column.appendChild(link);
7178
- if (!firstLink) firstLink = link;
7179
- });
7180
- container.appendChild(column);
7181
- return { column, firstLink };
7182
- }
7183
- function insertFooterColumn(heading = DEFAULT_FOOTER_COLUMN_HEADING, linkLabel = DEFAULT_FOOTER_COLUMN_LINK_LABEL, linkHref = DEFAULT_FOOTER_COLUMN_LINK_HREF) {
7184
- const colIndex = getNextFooterColumnIndex();
7185
- const inserted = insertFooterColumnDom(colIndex, heading, [{ href: linkHref, label: linkLabel }]);
7186
- if (!inserted?.firstLink) throw new Error("Failed to insert footer column");
7187
- syncFooterColumnIndices(listFooterColumns());
7188
- return {
7189
- column: inserted.column,
7190
- firstLink: inserted.firstLink,
7191
- colIndex,
7192
- headingKey: `footer-${colIndex}-heading`,
7193
- hrefKey: `footer-${colIndex}-0-href`,
7194
- labelKey: `footer-${colIndex}-0-label`,
7195
- heading,
7196
- label: linkLabel,
7197
- href: linkHref,
7198
- order: getFooterOrderFromDom()
7199
- };
7200
- }
7201
- function collectFooterColumnIndicesFromContent(content) {
7202
- const indices = /* @__PURE__ */ new Set();
7203
- for (const key of Object.keys(content)) {
7204
- const href = parseFooterHrefKey(key);
7205
- if (href) indices.add(href.col);
7206
- const heading = key.match(FOOTER_HEADING_RE);
7207
- if (heading) indices.add(parseInt(heading[1], 10));
7208
- const label = key.match(FOOTER_LABEL_RE);
7209
- if (label) indices.add(parseInt(label[1], 10));
7210
- }
7211
- const order = parseFooterOrder(content);
7212
- if (order) {
7213
- for (const col of order) {
7214
- for (const hrefKey of col) {
7215
- const parsed = parseFooterHrefKey(hrefKey);
7216
- if (parsed) indices.add(parsed.col);
7217
- }
7218
- }
7219
- }
7220
- return [...indices].sort((a, b) => a - b);
7221
- }
7222
- function collectFooterItemsForColumn(content, colIndex) {
7223
- const itemIndices = /* @__PURE__ */ new Set();
7224
- for (const key of Object.keys(content)) {
7225
- const href = parseFooterHrefKey(key);
7226
- if (href?.col === colIndex) itemIndices.add(href.item);
7227
- const label = key.match(FOOTER_LABEL_RE);
7228
- if (label && parseInt(label[1], 10) === colIndex) {
7229
- itemIndices.add(parseInt(label[2], 10));
7230
- }
7231
- }
7232
- const sorted = [...itemIndices].sort((a, b) => a - b);
7233
- if (sorted.length === 0) {
7234
- return [
7235
- {
7236
- href: content[`footer-${colIndex}-0-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7237
- label: content[`footer-${colIndex}-0-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7238
- }
7239
- ];
7240
- }
7241
- return sorted.map((itemIndex) => ({
7242
- href: content[`footer-${colIndex}-${itemIndex}-href`] ?? DEFAULT_FOOTER_COLUMN_LINK_HREF,
7243
- label: content[`footer-${colIndex}-${itemIndex}-label`] ?? DEFAULT_FOOTER_COLUMN_LINK_LABEL
7244
- }));
7245
- }
7246
- function reconcileFooterColumnsFromContent(content) {
7247
- const indices = collectFooterColumnIndicesFromContent(content);
7248
- for (const colIndex of indices) {
7249
- if (footerColumnExistsInDom(colIndex)) continue;
7250
- const heading = content[`footer-${colIndex}-heading`] ?? DEFAULT_FOOTER_COLUMN_HEADING;
7251
- const items = collectFooterItemsForColumn(content, colIndex);
7252
- const hasPayload = Boolean(content[`footer-${colIndex}-heading`]) || items.some(
7253
- (_, i) => content[`footer-${colIndex}-${i}-href`] !== void 0 || content[`footer-${colIndex}-${i}-label`] !== void 0
7254
- ) || (parseFooterOrder(content)?.some(
7255
- (col) => col.some((k) => parseFooterHrefKey(k)?.col === colIndex)
7256
- ) ?? false);
7257
- if (!hasPayload) continue;
7258
- insertFooterColumnDom(colIndex, heading, items);
7259
- }
7260
- }
7261
7010
  function reconcileFooterOrderFromContent(content) {
7262
- reconcileFooterColumnsFromContent(content);
7263
7011
  const order = parseFooterOrder(content);
7264
7012
  if (!order?.length) return;
7265
7013
  const current = getFooterOrderFromDom();
@@ -7269,31 +7017,6 @@ function reconcileFooterOrderFromContent(content) {
7269
7017
  }
7270
7018
  applyFooterOrder(order);
7271
7019
  }
7272
- function resolveFooterLinksContainerSelectionTarget(target, clientX, clientY, isPointOverItem) {
7273
- const container = getFooterLinksContainer();
7274
- if (!container) return null;
7275
- const inContainer = target === container || container.contains(target) && Boolean(target.closest("[data-ohw-footer-links], .rb-footer-links"));
7276
- if (!inContainer && target !== container) {
7277
- const r2 = container.getBoundingClientRect();
7278
- const over = clientX >= r2.left && clientX <= r2.right && clientY >= r2.top && clientY <= r2.bottom;
7279
- if (!over) return null;
7280
- }
7281
- if (isPointOverItem(container, clientX, clientY)) return null;
7282
- const column = target.closest("[data-ohw-footer-col], [data-ohw-footer-column]") ?? null;
7283
- if (column && container.contains(column)) {
7284
- if (target === column || column.contains(target)) return null;
7285
- }
7286
- if (target === container || container.contains(target) || inContainer) {
7287
- if (target === container || isFooterLinksContainer(target)) return container;
7288
- if (!column) return container;
7289
- }
7290
- return null;
7291
- }
7292
- function isRowLayoutColumn(links) {
7293
- if (links.length < 2) return false;
7294
- const firstTop = links[0].getBoundingClientRect().top;
7295
- return links.every((link) => Math.abs(link.getBoundingClientRect().top - firstTop) < 4);
7296
- }
7297
7020
  function buildLinkDropSlots(column, columnIndex) {
7298
7021
  const links = listFooterLinksInColumn(column);
7299
7022
  const colRect = column.getBoundingClientRect();
@@ -7311,32 +7034,6 @@ function buildLinkDropSlots(column, columnIndex) {
7311
7034
  });
7312
7035
  return slots;
7313
7036
  }
7314
- if (isRowLayoutColumn(links)) {
7315
- for (let i = 0; i <= links.length; i++) {
7316
- let left;
7317
- if (i === 0) {
7318
- left = links[0].getBoundingClientRect().left - barThickness / 2;
7319
- } else if (i === links.length) {
7320
- const last = links[links.length - 1].getBoundingClientRect();
7321
- left = last.right - barThickness / 2;
7322
- } else {
7323
- const prev = links[i - 1].getBoundingClientRect();
7324
- const next = links[i].getBoundingClientRect();
7325
- left = (prev.right + next.left) / 2 - barThickness / 2;
7326
- }
7327
- const heightRef = i === 0 ? links[0].getBoundingClientRect() : i === links.length ? links[links.length - 1].getBoundingClientRect() : links[i].getBoundingClientRect();
7328
- slots.push({
7329
- insertIndex: i,
7330
- columnIndex,
7331
- left,
7332
- top: heightRef.top,
7333
- width: barThickness,
7334
- height: Math.max(heightRef.height, colRect.height * 0.8),
7335
- direction: "vertical"
7336
- });
7337
- }
7338
- return slots;
7339
- }
7340
7037
  for (let i = 0; i <= links.length; i++) {
7341
7038
  let top;
7342
7039
  if (i === 0) {
@@ -7420,7 +7117,8 @@ function hitTestLinkDropSlot(clientX, clientY, draggedHrefKey) {
7420
7117
  return true;
7421
7118
  });
7422
7119
  for (const slot of slots) {
7423
- const dist = slot.direction === "vertical" ? Math.abs(clientX - (slot.left + slot.width / 2)) : Math.abs(clientY - (slot.top + slot.height / 2));
7120
+ const cy = slot.top + slot.height / 2;
7121
+ const dist = Math.abs(clientY - cy) + (inColX ? 0 : 1e3);
7424
7122
  if (!best || dist < best.dist) best = { slot, dist };
7425
7123
  }
7426
7124
  }
@@ -7444,30 +7142,6 @@ function hitTestColumnDropSlot(clientX, _clientY) {
7444
7142
  return best?.slot ?? null;
7445
7143
  }
7446
7144
 
7447
- // src/lib/add-footer-column.ts
7448
- function buildFooterColumnEditContentPatch(result) {
7449
- return {
7450
- [result.headingKey]: result.heading,
7451
- [result.hrefKey]: result.href,
7452
- [result.labelKey]: result.label,
7453
- [FOOTER_ORDER_KEY]: JSON.stringify(result.order)
7454
- };
7455
- }
7456
- function addFooterColumnWithPersist({
7457
- postToParent: postToParent2
7458
- }) {
7459
- const result = insertFooterColumn();
7460
- const patch = buildFooterColumnEditContentPatch(result);
7461
- setStoredLinkHref(result.hrefKey, result.href);
7462
- postToParent2({
7463
- type: "ow:change",
7464
- nodes: Object.entries(patch).map(([key, text]) => ({ key, text }))
7465
- });
7466
- postToParent2({ type: "ow:toast", title: "Item added", toastType: "success" });
7467
- enforceLinkHrefs();
7468
- return result;
7469
- }
7470
-
7471
7145
  // src/lib/item-drag-interaction.ts
7472
7146
  function disableNativeHrefDrag(el) {
7473
7147
  if (el.draggable) el.draggable = false;
@@ -7488,10 +7162,9 @@ function lockItemDuringDrag() {
7488
7162
  clearTextSelection();
7489
7163
  }
7490
7164
  function unlockItemDragInteraction() {
7491
- const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
7492
7165
  document.documentElement.removeAttribute("data-ohw-footer-press-drag");
7493
7166
  document.documentElement.removeAttribute("data-ohw-item-dragging");
7494
- if (wasDragging) clearTextSelection();
7167
+ clearTextSelection();
7495
7168
  }
7496
7169
  var armFooterPressDrag = armItemPressDrag;
7497
7170
  var lockFooterDuringDrag = lockItemDuringDrag;
@@ -7868,6 +7541,7 @@ function useNavItemDrag({
7868
7541
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
7869
7542
  if (!anchor || !isNavbarHrefKey(hrefKey)) return;
7870
7543
  if (isNavbarButton3(anchor) || isDragHandleDisabled2(anchor)) return;
7544
+ armItemPressDrag();
7871
7545
  navPointerDragRef.current = {
7872
7546
  el: anchor,
7873
7547
  startX: e.clientX,
@@ -7894,7 +7568,6 @@ function useNavItemDrag({
7894
7568
  if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
7895
7569
  e.preventDefault();
7896
7570
  pending.started = true;
7897
- armItemPressDrag();
7898
7571
  clearTextSelection();
7899
7572
  try {
7900
7573
  document.body.setPointerCapture(pending.pointerId);
@@ -7922,8 +7595,7 @@ function useNavItemDrag({
7922
7595
  }
7923
7596
  } catch {
7924
7597
  }
7925
- if (!pending) return;
7926
- if (!pending.started) {
7598
+ if (!pending?.started) {
7927
7599
  unlockItemDragInteraction();
7928
7600
  return;
7929
7601
  }
@@ -7975,6 +7647,7 @@ function useNavItemDrag({
7975
7647
  const hrefKey = selected.getAttribute("data-ohw-href-key");
7976
7648
  if (!hrefKey || !isNavbarHrefKey(hrefKey)) return false;
7977
7649
  if (isNavbarButton3(selected) || isDragHandleDisabled2(selected)) return false;
7650
+ armItemPressDrag();
7978
7651
  navPointerDragRef.current = {
7979
7652
  el: selected,
7980
7653
  startX: clientX,
@@ -8000,60 +7673,15 @@ function useNavItemDrag({
8000
7673
  };
8001
7674
  }
8002
7675
 
8003
- // src/ui/footer-container-chrome.tsx
7676
+ // src/ui/navbar-container-chrome.tsx
8004
7677
  var import_lucide_react10 = require("lucide-react");
8005
7678
  var import_jsx_runtime21 = require("react/jsx-runtime");
8006
- function FooterContainerChrome({ rect, onAdd }) {
8007
- const chromeGap = 6;
8008
- const buttonMargin = 7;
8009
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8010
- "div",
8011
- {
8012
- "data-ohw-footer-container-chrome": "",
8013
- "data-ohw-bridge": "",
8014
- className: "pointer-events-none fixed z-[2147483647]",
8015
- style: {
8016
- top: rect.top - chromeGap,
8017
- left: rect.left - chromeGap,
8018
- width: rect.width + chromeGap * 2,
8019
- height: rect.height + chromeGap * 2
8020
- },
8021
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
8022
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8023
- "button",
8024
- {
8025
- type: "button",
8026
- "data-ohw-footer-add-button": "",
8027
- className: "pointer-events-auto absolute left-1/2 flex size-7 -translate-x-1/2 -translate-y-full items-center justify-center rounded-[10px] border border-border bg-background p-0.5 shadow-sm transition-colors hover:bg-muted/80",
8028
- style: { top: chromeGap - buttonMargin },
8029
- "aria-label": "Add item",
8030
- onMouseDown: (e) => {
8031
- e.preventDefault();
8032
- e.stopPropagation();
8033
- },
8034
- onClick: (e) => {
8035
- e.preventDefault();
8036
- e.stopPropagation();
8037
- onAdd();
8038
- },
8039
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8040
- }
8041
- ) }),
8042
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: "Add item" })
8043
- ] })
8044
- }
8045
- ) });
8046
- }
8047
-
8048
- // src/ui/navbar-container-chrome.tsx
8049
- var import_lucide_react11 = require("lucide-react");
8050
- var import_jsx_runtime22 = require("react/jsx-runtime");
8051
7679
  function NavbarContainerChrome({
8052
7680
  rect,
8053
7681
  onAdd
8054
7682
  }) {
8055
7683
  const chromeGap = 6;
8056
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7684
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8057
7685
  "div",
8058
7686
  {
8059
7687
  "data-ohw-navbar-container-chrome": "",
@@ -8065,7 +7693,7 @@ function NavbarContainerChrome({
8065
7693
  width: rect.width + chromeGap * 2,
8066
7694
  height: rect.height + chromeGap * 2
8067
7695
  },
8068
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7696
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
8069
7697
  "button",
8070
7698
  {
8071
7699
  type: "button",
@@ -8082,7 +7710,7 @@ function NavbarContainerChrome({
8082
7710
  e.stopPropagation();
8083
7711
  onAdd();
8084
7712
  },
8085
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
7713
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
8086
7714
  }
8087
7715
  )
8088
7716
  }
@@ -8091,7 +7719,7 @@ function NavbarContainerChrome({
8091
7719
 
8092
7720
  // src/ui/drop-indicator.tsx
8093
7721
  var React10 = __toESM(require("react"), 1);
8094
- var import_jsx_runtime23 = require("react/jsx-runtime");
7722
+ var import_jsx_runtime22 = require("react/jsx-runtime");
8095
7723
  var dropIndicatorVariants = cva(
8096
7724
  "ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
8097
7725
  {
@@ -8115,7 +7743,7 @@ var dropIndicatorVariants = cva(
8115
7743
  );
8116
7744
  var DropIndicator = React10.forwardRef(
8117
7745
  ({ className, direction, state, ...props }, ref) => {
8118
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
7746
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
8119
7747
  "div",
8120
7748
  {
8121
7749
  ref,
@@ -8132,7 +7760,7 @@ var DropIndicator = React10.forwardRef(
8132
7760
  DropIndicator.displayName = "DropIndicator";
8133
7761
 
8134
7762
  // src/ui/badge.tsx
8135
- var import_jsx_runtime24 = require("react/jsx-runtime");
7763
+ var import_jsx_runtime23 = require("react/jsx-runtime");
8136
7764
  var badgeVariants = cva(
8137
7765
  "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",
8138
7766
  {
@@ -8150,12 +7778,12 @@ var badgeVariants = cva(
8150
7778
  }
8151
7779
  );
8152
7780
  function Badge({ className, variant, ...props }) {
8153
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
7781
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
8154
7782
  }
8155
7783
 
8156
7784
  // src/OhhwellsBridge.tsx
8157
- var import_lucide_react12 = require("lucide-react");
8158
- var import_jsx_runtime25 = require("react/jsx-runtime");
7785
+ var import_lucide_react11 = require("lucide-react");
7786
+ var import_jsx_runtime24 = require("react/jsx-runtime");
8159
7787
  var PRIMARY2 = "#0885FE";
8160
7788
  var IMAGE_FADE_MS = 300;
8161
7789
  function runOpacityFade(el, onDone) {
@@ -8334,7 +7962,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
8334
7962
  const root = (0, import_client.createRoot)(container);
8335
7963
  (0, import_react_dom2.flushSync)(() => {
8336
7964
  root.render(
8337
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
7965
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8338
7966
  SchedulingWidget,
8339
7967
  {
8340
7968
  notifyOnConnect,
@@ -8535,7 +8163,7 @@ function applyLinkByKey(key, val) {
8535
8163
  }
8536
8164
  function isInsideLinkEditor(target) {
8537
8165
  return Boolean(
8538
- target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest("[data-ohw-footer-container-chrome]") || target.closest("[data-ohw-footer-add-button]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
8166
+ target.closest("[data-ohw-link-popover-root]") || target.closest("[data-ohw-link-modal-root]") || target.closest("[data-ohw-link-page-dropdown]") || target.closest("[data-ohw-section-picker]") || target.closest("[data-ohw-navbar-container-chrome]") || target.closest("[data-ohw-navbar-add-button]") || target.closest('[data-slot="popover-content"]') || target.closest('[data-slot="dialog-content"]') || target.closest('[data-slot="dialog-overlay"]')
8539
8167
  );
8540
8168
  }
8541
8169
  function getHrefKeyFromElement(el) {
@@ -8616,7 +8244,7 @@ function isInferredFooterGroup(el) {
8616
8244
  return countFooterNavItems(el) >= 2;
8617
8245
  }
8618
8246
  function isNavigationContainer(el) {
8619
- return el.hasAttribute("data-ohw-nav-container") || isFooterLinksContainer(el) || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
8247
+ return el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isNavigationRoot(el) || isInferredFooterGroup(el);
8620
8248
  }
8621
8249
  function isNavbarLinksContainer(el) {
8622
8250
  return el.hasAttribute("data-ohw-nav-container");
@@ -8635,9 +8263,6 @@ function isPointOverNavigation(x, y) {
8635
8263
  const roots = /* @__PURE__ */ new Set();
8636
8264
  const navRoot = document.querySelector("[data-ohw-nav-root]") ?? document.querySelector("nav");
8637
8265
  if (navRoot) roots.add(navRoot);
8638
- document.querySelectorAll("[data-ohw-nav-drawer], [data-ohw-nav-container]").forEach((el) => {
8639
- roots.add(el);
8640
- });
8641
8266
  const footer = document.querySelector("footer");
8642
8267
  if (footer) roots.add(footer);
8643
8268
  for (const root of roots) {
@@ -8666,12 +8291,6 @@ function isPointOverNavItem(container, x, y) {
8666
8291
  return x >= itemRect.left && x <= itemRect.right && y >= itemRect.top && y <= itemRect.bottom;
8667
8292
  });
8668
8293
  }
8669
- function isPointOverFooterColumn(x, y) {
8670
- return listFooterColumns().some((col) => {
8671
- const r2 = col.getBoundingClientRect();
8672
- return x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom;
8673
- });
8674
- }
8675
8294
  function resolveNavContainerSelectionTarget(target, clientX, clientY) {
8676
8295
  if (getNavigationItemAnchor(target)) return null;
8677
8296
  if (target.closest('[data-ohw-role="navbar-button"]')) return null;
@@ -8702,10 +8321,7 @@ function getNavigationSelectionParent(el) {
8702
8321
  if (footerGroup) return footerGroup;
8703
8322
  return getNavigationRoot(el);
8704
8323
  }
8705
- if (!isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el))) {
8706
- return getFooterLinksContainer();
8707
- }
8708
- if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isFooterLinksContainer(el) || isInferredFooterGroup(el)) {
8324
+ if (el.hasAttribute("data-ohw-nav-container") || el.hasAttribute("data-ohw-footer-col") || el.hasAttribute("data-ohw-footer-column") || isInferredFooterGroup(el)) {
8709
8325
  return getNavigationRoot(el);
8710
8326
  }
8711
8327
  return null;
@@ -8876,16 +8492,9 @@ function sanitizeHtml(html) {
8876
8492
  if (!SAFE_TAGS.has(el.tagName)) {
8877
8493
  parent.replaceChild(document.createTextNode(el.textContent ?? ""), el);
8878
8494
  } else {
8879
- const htmlEl = el;
8880
- const textAlign = htmlEl.style?.textAlign || el.getAttribute("align") || "";
8881
- const fontWeight = htmlEl.style?.fontWeight || "";
8882
- const fontStyle = htmlEl.style?.fontStyle || "";
8883
- const textDecorationLine = htmlEl.style?.textDecorationLine || htmlEl.style?.textDecoration || "";
8495
+ const textAlign = el.style?.textAlign || el.getAttribute("align") || "";
8884
8496
  for (const attr of Array.from(el.attributes)) el.removeAttribute(attr.name);
8885
- if (textAlign) htmlEl.style.textAlign = textAlign;
8886
- if (fontWeight) htmlEl.style.fontWeight = fontWeight;
8887
- if (fontStyle) htmlEl.style.fontStyle = fontStyle;
8888
- if (textDecorationLine) htmlEl.style.textDecorationLine = textDecorationLine;
8497
+ if (textAlign) el.style.textAlign = textAlign;
8889
8498
  walk(el);
8890
8499
  }
8891
8500
  }
@@ -8932,7 +8541,7 @@ function EditGlowChrome({
8932
8541
  hideHandle = false
8933
8542
  }) {
8934
8543
  const GAP = SELECTION_CHROME_GAP2;
8935
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
8544
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
8936
8545
  "div",
8937
8546
  {
8938
8547
  ref: elRef,
@@ -8947,7 +8556,7 @@ function EditGlowChrome({
8947
8556
  zIndex: 2147483646
8948
8557
  },
8949
8558
  children: [
8950
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8559
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8951
8560
  "div",
8952
8561
  {
8953
8562
  style: {
@@ -8960,7 +8569,7 @@ function EditGlowChrome({
8960
8569
  }
8961
8570
  }
8962
8571
  ),
8963
- reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8572
+ reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8964
8573
  "div",
8965
8574
  {
8966
8575
  "data-ohw-drag-handle-container": "",
@@ -8972,7 +8581,7 @@ function EditGlowChrome({
8972
8581
  transform: "translate(calc(-100% - 7px), -50%)",
8973
8582
  pointerEvents: dragDisabled ? "none" : "auto"
8974
8583
  },
8975
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8584
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
8976
8585
  DragHandle,
8977
8586
  {
8978
8587
  "aria-label": `Reorder ${reorderHrefKey}`,
@@ -9073,79 +8682,6 @@ function resolveItemInteractionState(rect, parentScroll) {
9073
8682
  const { transform } = calcToolbarPos(rect, parentScroll, 120);
9074
8683
  return transform.includes("translateY(-100%)") ? "active-top" : "active-bottom";
9075
8684
  }
9076
- function resolveSelectionStartElement(sel) {
9077
- if (!sel || sel.rangeCount === 0) return null;
9078
- const range = sel.getRangeAt(0);
9079
- let startNode = range.startContainer;
9080
- if (startNode.nodeType === Node.ELEMENT_NODE) {
9081
- const el = startNode;
9082
- startNode = el.childNodes[range.startOffset] ?? el.childNodes[range.startOffset - 1] ?? el;
9083
- }
9084
- return startNode.nodeType === Node.TEXT_NODE ? startNode.parentElement : startNode;
9085
- }
9086
- function detectActiveFormats(startEl, activeRoot) {
9087
- const formats = /* @__PURE__ */ new Set();
9088
- const cs = getComputedStyle(startEl);
9089
- const weight = parseInt(cs.fontWeight, 10);
9090
- let hasBold = cs.fontWeight === "bold" || !Number.isNaN(weight) && weight >= 600;
9091
- let hasItalic = cs.fontStyle === "italic" || cs.fontStyle === "oblique";
9092
- let hasUnderline = false;
9093
- let hasStrike = false;
9094
- let hasUl = false;
9095
- let hasOl = false;
9096
- for (let el = startEl; el; el = el.parentElement) {
9097
- if (el.tagName === "B" || el.tagName === "STRONG") hasBold = true;
9098
- if (el.tagName === "I" || el.tagName === "EM") hasItalic = true;
9099
- const decoration = getComputedStyle(el).textDecorationLine;
9100
- if (decoration.includes("underline") || el.tagName === "U" || el.tagName === "INS") hasUnderline = true;
9101
- if (decoration.includes("line-through") || el.tagName === "S" || el.tagName === "STRIKE" || el.tagName === "DEL") hasStrike = true;
9102
- if (el.tagName === "UL") hasUl = true;
9103
- if (el.tagName === "OL") hasOl = true;
9104
- if (el === activeRoot) break;
9105
- }
9106
- if (hasBold) formats.add("bold");
9107
- if (hasItalic) formats.add("italic");
9108
- if (hasUnderline) formats.add("underline");
9109
- if (hasStrike) formats.add("strikeThrough");
9110
- if (hasUl) formats.add("insertUnorderedList");
9111
- if (hasOl) formats.add("insertOrderedList");
9112
- const block = startEl.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? startEl;
9113
- const align = getComputedStyle(block).textAlign;
9114
- if (align === "center") formats.add("justifyCenter");
9115
- else if (align === "right" || align === "end") formats.add("justifyRight");
9116
- else formats.add("justifyLeft");
9117
- return formats;
9118
- }
9119
- function setsEqual(a, b) {
9120
- if (a.size !== b.size) return false;
9121
- for (const item of a) {
9122
- if (!b.has(item)) return false;
9123
- }
9124
- return true;
9125
- }
9126
- function textOffsetInRoot(root, node, offset) {
9127
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
9128
- let total = 0;
9129
- let current;
9130
- while (current = walker.nextNode()) {
9131
- if (current === node) return total + offset;
9132
- total += (current.textContent ?? "").length;
9133
- }
9134
- return total;
9135
- }
9136
- function pointAtTextOffset(root, targetOffset) {
9137
- const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
9138
- let total = 0;
9139
- let current;
9140
- let last = null;
9141
- while (current = walker.nextNode()) {
9142
- const len = (current.textContent ?? "").length;
9143
- if (total + len >= targetOffset) return { node: current, offset: targetOffset - total };
9144
- total += len;
9145
- last = current;
9146
- }
9147
- return last ? { node: last, offset: (last.textContent ?? "").length } : null;
9148
- }
9149
8685
  function FloatingToolbar({
9150
8686
  rect,
9151
8687
  parentScroll,
@@ -9182,7 +8718,7 @@ function FloatingToolbar({
9182
8718
  return () => ro.disconnect();
9183
8719
  }, [showEditLink, activeCommands]);
9184
8720
  const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
9185
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8721
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9186
8722
  "div",
9187
8723
  {
9188
8724
  ref: setRefs,
@@ -9194,12 +8730,12 @@ function FloatingToolbar({
9194
8730
  zIndex: 2147483647,
9195
8731
  pointerEvents: "auto"
9196
8732
  },
9197
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(CustomToolbar, { children: [
9198
- TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react9.default.Fragment, { children: [
9199
- gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(CustomToolbarDivider, {}),
8733
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(CustomToolbar, { children: [
8734
+ TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react9.default.Fragment, { children: [
8735
+ gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CustomToolbarDivider, {}),
9200
8736
  btns.map((btn) => {
9201
8737
  const isActive = activeCommands.has(btn.cmd);
9202
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8738
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9203
8739
  CustomToolbarButton,
9204
8740
  {
9205
8741
  title: btn.title,
@@ -9208,7 +8744,7 @@ function FloatingToolbar({
9208
8744
  e.preventDefault();
9209
8745
  onCommand(btn.cmd);
9210
8746
  },
9211
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8747
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9212
8748
  "svg",
9213
8749
  {
9214
8750
  width: "16",
@@ -9229,7 +8765,7 @@ function FloatingToolbar({
9229
8765
  );
9230
8766
  })
9231
8767
  ] }, gi)),
9232
- showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8768
+ showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9233
8769
  CustomToolbarButton,
9234
8770
  {
9235
8771
  type: "button",
@@ -9243,7 +8779,7 @@ function FloatingToolbar({
9243
8779
  e.preventDefault();
9244
8780
  e.stopPropagation();
9245
8781
  },
9246
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react12.Link, { className: "size-4 shrink-0", "aria-hidden": true })
8782
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react11.Link, { className: "size-4 shrink-0", "aria-hidden": true })
9247
8783
  }
9248
8784
  ) : null
9249
8785
  ] })
@@ -9260,7 +8796,7 @@ function StateToggle({
9260
8796
  states,
9261
8797
  onStateChange
9262
8798
  }) {
9263
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
8799
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
9264
8800
  ToggleGroup,
9265
8801
  {
9266
8802
  "data-ohw-state-toggle": "",
@@ -9274,7 +8810,7 @@ function StateToggle({
9274
8810
  left: rect.right - 8,
9275
8811
  transform: "translateX(-100%)"
9276
8812
  },
9277
- children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
8813
+ children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
9278
8814
  }
9279
8815
  );
9280
8816
  }
@@ -9338,7 +8874,6 @@ function OhhwellsBridge() {
9338
8874
  const [fetchState, setFetchState] = (0, import_react9.useState)("idle");
9339
8875
  const autoSaveTimers = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
9340
8876
  const activeElRef = (0, import_react9.useRef)(null);
9341
- const pointerHeldRef = (0, import_react9.useRef)(false);
9342
8877
  const selectedElRef = (0, import_react9.useRef)(null);
9343
8878
  const selectedHrefKeyRef = (0, import_react9.useRef)(null);
9344
8879
  const selectedFooterColAttrRef = (0, import_react9.useRef)(null);
@@ -9770,18 +9305,6 @@ function OhhwellsBridge() {
9770
9305
  intent: "add-nav"
9771
9306
  });
9772
9307
  }, []);
9773
- const handleAddFooterColumn = (0, import_react9.useCallback)(() => {
9774
- deselectRef.current();
9775
- deactivateRef.current();
9776
- const result = addFooterColumnWithPersist({ postToParent: postToParent2 });
9777
- editContentRef.current = {
9778
- ...editContentRef.current,
9779
- ...buildFooterColumnEditContentPatch(result)
9780
- };
9781
- requestAnimationFrame(() => {
9782
- selectRef.current(result.firstLink);
9783
- });
9784
- }, [postToParent2]);
9785
9308
  const clearFooterDragVisuals = (0, import_react9.useCallback)(() => {
9786
9309
  footerDragRef.current = null;
9787
9310
  setSiblingHintRects([]);
@@ -10037,6 +9560,7 @@ function OhhwellsBridge() {
10037
9560
  if (e.button !== 0) return;
10038
9561
  const selected = selectedElRef.current;
10039
9562
  if (!selected) return;
9563
+ armFooterPressDrag();
10040
9564
  const hrefKey = selected.getAttribute("data-ohw-href-key");
10041
9565
  if (hrefKey && isFooterHrefKey(hrefKey)) {
10042
9566
  footerPointerDragRef.current = {
@@ -10106,7 +9630,7 @@ function OhhwellsBridge() {
10106
9630
  const selectFrame = (0, import_react9.useCallback)((el) => {
10107
9631
  if (!isNavigationContainer(el)) return;
10108
9632
  if (activeElRef.current) deactivate();
10109
- const isFooterColumn = !isFooterLinksContainer(el) && (el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el)));
9633
+ const isFooterColumn = el.hasAttribute("data-ohw-footer-col") || Boolean(el.closest("footer") && isInferredFooterGroup(el));
10110
9634
  selectedElRef.current = el;
10111
9635
  selectedHrefKeyRef.current = null;
10112
9636
  selectedFooterColAttrRef.current = isFooterColumn ? el.getAttribute("data-ohw-footer-col") ?? String(listFooterColumns().indexOf(el)) : null;
@@ -10148,8 +9672,6 @@ function OhhwellsBridge() {
10148
9672
  setSiblingHintRect(null);
10149
9673
  setSiblingHintRects([]);
10150
9674
  setIsItemDragging(false);
10151
- const preActivationSelection = window.getSelection();
10152
- const preservedRange = preActivationSelection && preActivationSelection.rangeCount > 0 && !preActivationSelection.isCollapsed && el.contains(preActivationSelection.getRangeAt(0).commonAncestorContainer) ? preActivationSelection.getRangeAt(0).cloneRange() : null;
10153
9675
  el.setAttribute("contenteditable", "true");
10154
9676
  el.setAttribute("data-ohw-editing", "");
10155
9677
  el.removeAttribute("data-ohw-hovered");
@@ -10157,11 +9679,7 @@ function OhhwellsBridge() {
10157
9679
  activeElRef.current = el;
10158
9680
  originalContentRef.current = el.innerHTML;
10159
9681
  el.focus({ preventScroll: true });
10160
- if (preservedRange) {
10161
- const selection = window.getSelection();
10162
- selection?.removeAllRanges();
10163
- selection?.addRange(preservedRange);
10164
- } else if (options?.caretX !== void 0 && options?.caretY !== void 0) {
9682
+ if (options?.caretX !== void 0 && options?.caretY !== void 0) {
10165
9683
  const { caretX, caretY } = options;
10166
9684
  placeCaretAtPoint(el, caretX, caretY);
10167
9685
  requestAnimationFrame(() => {
@@ -10617,9 +10135,7 @@ function OhhwellsBridge() {
10617
10135
  if (inActive || inActiveNav) {
10618
10136
  e.preventDefault();
10619
10137
  e.stopPropagation();
10620
- const selection = window.getSelection();
10621
- const hasRangeSelection = Boolean(selection && !selection.isCollapsed);
10622
- if (e.detail < 2 && !hasRangeSelection) {
10138
+ if (e.detail < 2) {
10623
10139
  placeCaretAtPoint(active, e.clientX, e.clientY);
10624
10140
  refreshActiveCommandsRef.current();
10625
10141
  }
@@ -10662,7 +10178,7 @@ function OhhwellsBridge() {
10662
10178
  }
10663
10179
  e.preventDefault();
10664
10180
  e.stopPropagation();
10665
- activateRef.current(editable, { caretX: e.clientX, caretY: e.clientY });
10181
+ activateRef.current(editable);
10666
10182
  return;
10667
10183
  }
10668
10184
  const hrefAnchor = getNavigationItemAnchor(target);
@@ -10689,18 +10205,6 @@ function OhhwellsBridge() {
10689
10205
  selectFrameRef.current(footerColClick);
10690
10206
  return;
10691
10207
  }
10692
- const footerLinksToSelect = resolveFooterLinksContainerSelectionTarget(
10693
- target,
10694
- e.clientX,
10695
- e.clientY,
10696
- isPointOverNavItem
10697
- );
10698
- if (footerLinksToSelect) {
10699
- e.preventDefault();
10700
- e.stopPropagation();
10701
- selectFrameRef.current(footerLinksToSelect);
10702
- return;
10703
- }
10704
10208
  const navContainerToSelect = resolveNavContainerSelectionTarget(target, e.clientX, e.clientY);
10705
10209
  if (navContainerToSelect) {
10706
10210
  e.preventDefault();
@@ -10759,8 +10263,8 @@ function OhhwellsBridge() {
10759
10263
  return;
10760
10264
  }
10761
10265
  const navLabel = getNavigationLabelEditable(target);
10762
- const editable = navLabel?.editable ?? target.closest('[data-ohw-editable="text"], [data-ohw-editable="plain"]');
10763
- if (!editable || isMediaEditable(editable) || editable.dataset.ohwEditable === "link") return;
10266
+ if (!navLabel) return;
10267
+ const { editable } = navLabel;
10764
10268
  e.preventDefault();
10765
10269
  e.stopPropagation();
10766
10270
  if (activeElRef.current !== editable) {
@@ -10781,38 +10285,16 @@ function OhhwellsBridge() {
10781
10285
  setHoveredNavContainerRect(null);
10782
10286
  return;
10783
10287
  }
10784
- {
10785
- const selected2 = selectedElRef.current;
10786
- const selectedIsFooterColumn = Boolean(selected2) && !isFooterLinksContainer(selected2) && (selected2.hasAttribute("data-ohw-footer-col") || selected2.hasAttribute("data-ohw-footer-column") || Boolean(selected2.closest("footer") && isInferredFooterGroup(selected2)));
10787
- const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
10788
- const allowFooterLinksHover = toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn;
10789
- if (allowNavContainerHover) {
10790
- const navContainer = target.closest("[data-ohw-nav-container]");
10791
- if (navContainer && !getNavigationItemAnchor(target)) {
10792
- hoveredNavContainerRef.current = navContainer;
10793
- setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10794
- hoveredItemElRef.current = null;
10795
- setHoveredItemRect(null);
10796
- return;
10797
- }
10288
+ if (toolbarVariantRef.current !== "select-frame") {
10289
+ const navContainer = target.closest("[data-ohw-nav-container]");
10290
+ if (navContainer && !getNavigationItemAnchor(target)) {
10291
+ hoveredNavContainerRef.current = navContainer;
10292
+ setHoveredNavContainerRect(navContainer.getBoundingClientRect());
10293
+ hoveredItemElRef.current = null;
10294
+ setHoveredItemRect(null);
10295
+ return;
10798
10296
  }
10799
- if (allowFooterLinksHover) {
10800
- const navContainer = target.closest("[data-ohw-nav-container]");
10801
- if (!navContainer) {
10802
- const footerLinks = target.closest("[data-ohw-footer-links], .rb-footer-links") ?? null;
10803
- if (footerLinks && selected2 !== footerLinks && !getNavigationItemAnchor(target) && !target.closest("[data-ohw-footer-col], [data-ohw-footer-column]")) {
10804
- hoveredNavContainerRef.current = footerLinks;
10805
- setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
10806
- hoveredItemElRef.current = null;
10807
- setHoveredItemRect(null);
10808
- return;
10809
- }
10810
- if (!footerLinks) {
10811
- hoveredNavContainerRef.current = null;
10812
- setHoveredNavContainerRect(null);
10813
- }
10814
- }
10815
- } else if (toolbarVariantRef.current === "select-frame") {
10297
+ if (!target.closest("[data-ohw-nav-container]")) {
10816
10298
  hoveredNavContainerRef.current = null;
10817
10299
  setHoveredNavContainerRect(null);
10818
10300
  }
@@ -10854,9 +10336,9 @@ function OhhwellsBridge() {
10854
10336
  };
10855
10337
  const handleMouseOut = (e) => {
10856
10338
  const target = e.target;
10857
- if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links")) {
10339
+ if (target.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column]")) {
10858
10340
  const related2 = e.relatedTarget instanceof Element ? e.relatedTarget : null;
10859
- if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-footer-links], .rb-footer-links, [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button], [data-ohw-footer-container-chrome], [data-ohw-footer-add-button]")) {
10341
+ if (related2?.closest("[data-ohw-nav-container], [data-ohw-footer-col], [data-ohw-footer-column], [data-ohw-navbar-container-chrome], [data-ohw-navbar-add-button]")) {
10860
10342
  return;
10861
10343
  }
10862
10344
  hoveredNavContainerRef.current = null;
@@ -10951,15 +10433,6 @@ function OhhwellsBridge() {
10951
10433
  if (track) track.setAttribute("data-ohw-hover-paused", "");
10952
10434
  };
10953
10435
  const clearImageHover = () => setMediaHover(null);
10954
- const dismissImageHover = () => {
10955
- if (hoveredImageRef.current) {
10956
- hoveredImageRef.current = null;
10957
- hoveredImageHasTextOverlapRef.current = false;
10958
- resumeAnimTracks();
10959
- postToParentRef.current({ type: "ow:image-unhover" });
10960
- }
10961
- clearImageHover();
10962
- };
10963
10436
  const findImageAtPoint = (clientX, clientY, fromParentViewport) => {
10964
10437
  const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
10965
10438
  const images = Array.from(document.querySelectorAll(MEDIA_SELECTOR));
@@ -11003,13 +10476,16 @@ function OhhwellsBridge() {
11003
10476
  }
11004
10477
  return smallest;
11005
10478
  };
10479
+ const dismissImageHover = () => {
10480
+ if (hoveredImageRef.current) {
10481
+ hoveredImageRef.current = null;
10482
+ hoveredImageHasTextOverlapRef.current = false;
10483
+ resumeAnimTracks();
10484
+ postToParentRef.current({ type: "ow:image-unhover" });
10485
+ }
10486
+ };
11006
10487
  const probeNavigationHoverAt = (x, y) => {
11007
- const selected = selectedElRef.current;
11008
- const selectedIsFooterColumn = Boolean(selected) && !isFooterLinksContainer(selected) && (selected.hasAttribute("data-ohw-footer-col") || selected.hasAttribute("data-ohw-footer-column") || Boolean(selected.closest("footer") && isInferredFooterGroup(selected)));
11009
- const selectedIsFooterLinks = Boolean(selected && isFooterLinksContainer(selected));
11010
- const allowNavContainerHover = toolbarVariantRef.current !== "select-frame";
11011
- const allowFooterLinksHover = (toolbarVariantRef.current !== "select-frame" || selectedIsFooterColumn) && !selectedIsFooterLinks;
11012
- if (toolbarVariantRef.current === "select-frame" && !allowFooterLinksHover) {
10488
+ if (toolbarVariantRef.current === "select-frame") {
11013
10489
  hoveredNavContainerRef.current = null;
11014
10490
  setHoveredNavContainerRect(null);
11015
10491
  }
@@ -11031,6 +10507,7 @@ function OhhwellsBridge() {
11031
10507
  if (navItemHit) {
11032
10508
  hoveredNavContainerRef.current = null;
11033
10509
  setHoveredNavContainerRect(null);
10510
+ const selected = selectedElRef.current;
11034
10511
  if (selected !== navItemHit) {
11035
10512
  clearHrefKeyHover(navItemHit);
11036
10513
  hoveredItemElRef.current = navItemHit;
@@ -11042,7 +10519,7 @@ function OhhwellsBridge() {
11042
10519
  return;
11043
10520
  }
11044
10521
  }
11045
- if (allowNavContainerHover) {
10522
+ if (toolbarVariantRef.current !== "select-frame") {
11046
10523
  for (const container of navContainers) {
11047
10524
  const containerRect = container.getBoundingClientRect();
11048
10525
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -11054,23 +10531,12 @@ function OhhwellsBridge() {
11054
10531
  setHoveredItemRect(null);
11055
10532
  return;
11056
10533
  }
10534
+ hoveredNavContainerRef.current = null;
10535
+ setHoveredNavContainerRect(null);
10536
+ } else {
10537
+ hoveredNavContainerRef.current = null;
10538
+ setHoveredNavContainerRect(null);
11057
10539
  }
11058
- if (allowFooterLinksHover) {
11059
- const footerLinks = getFooterLinksContainer();
11060
- if (footerLinks) {
11061
- const containerRect = footerLinks.getBoundingClientRect();
11062
- const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
11063
- if (overContainer && !isPointOverNavItem(footerLinks, x, y) && !isPointOverFooterColumn(x, y)) {
11064
- hoveredNavContainerRef.current = footerLinks;
11065
- setHoveredNavContainerRect(footerLinks.getBoundingClientRect());
11066
- hoveredItemElRef.current = null;
11067
- setHoveredItemRect(null);
11068
- return;
11069
- }
11070
- }
11071
- }
11072
- hoveredNavContainerRef.current = null;
11073
- setHoveredNavContainerRect(null);
11074
10540
  for (const column of footerColumns) {
11075
10541
  const containerRect = column.getBoundingClientRect();
11076
10542
  const overContainer = x >= containerRect.left && x <= containerRect.right && y >= containerRect.top && y <= containerRect.bottom;
@@ -11577,7 +11043,6 @@ function OhhwellsBridge() {
11577
11043
  }
11578
11044
  editContentRef.current = { ...editContentRef.current, ...content };
11579
11045
  reconcileNavbarItemsFromContent(editContentRef.current);
11580
- reconcileFooterOrderFromContent(editContentRef.current);
11581
11046
  syncNavigationDragCursorAttrs();
11582
11047
  enforceLinkHrefs();
11583
11048
  postToParentRef.current({ type: "ow:hydrate-done" });
@@ -11632,11 +11097,6 @@ function OhhwellsBridge() {
11632
11097
  }
11633
11098
  if (selectedElRef.current) {
11634
11099
  if (toolbarVariantRef.current === "select-frame") {
11635
- const parent2 = getNavigationSelectionParent(selectedElRef.current);
11636
- if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
11637
- selectFrameRef.current(parent2);
11638
- return;
11639
- }
11640
11100
  deselectRef.current();
11641
11101
  return;
11642
11102
  }
@@ -11652,10 +11112,13 @@ function OhhwellsBridge() {
11652
11112
  const handleKeyDown = (e) => {
11653
11113
  if (e.key === "Escape" && document.querySelector("[data-ohw-section-picker]")) return;
11654
11114
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "a" && activeElRef.current) {
11655
- e.preventDefault();
11656
- selectAllTextInEditable(activeElRef.current);
11657
- refreshActiveCommandsRef.current();
11658
- return;
11115
+ const navAnchor = getNavigationItemAnchor(activeElRef.current);
11116
+ if (navAnchor) {
11117
+ e.preventDefault();
11118
+ selectAllTextInEditable(activeElRef.current);
11119
+ refreshActiveCommandsRef.current();
11120
+ return;
11121
+ }
11659
11122
  }
11660
11123
  if (e.key === "Escape" && linkPopoverOpenRef.current) {
11661
11124
  setLinkPopoverRef.current(null);
@@ -11663,12 +11126,6 @@ function OhhwellsBridge() {
11663
11126
  }
11664
11127
  if (e.key === "Escape" && selectedElRef.current && !activeElRef.current) {
11665
11128
  if (toolbarVariantRef.current === "select-frame") {
11666
- const parent2 = getNavigationSelectionParent(selectedElRef.current);
11667
- if (parent2 && isNavigationContainer(parent2) && isFooterLinksContainer(parent2) && !isFooterLinksContainer(selectedElRef.current)) {
11668
- e.preventDefault();
11669
- selectFrameRef.current(parent2);
11670
- return;
11671
- }
11672
11129
  deselectRef.current();
11673
11130
  return;
11674
11131
  }
@@ -11831,30 +11288,30 @@ function OhhwellsBridge() {
11831
11288
  const h = document.documentElement.scrollHeight;
11832
11289
  if (h > 50) postToParentRef.current({ type: "ow:height", height: h });
11833
11290
  };
11834
- let selectionChangeRaf = null;
11835
- const runSelectionChange = () => {
11836
- selectionChangeRaf = null;
11837
- const activeRoot = activeElRef.current;
11838
- if (!activeRoot) return;
11839
- const startEl = resolveSelectionStartElement(window.getSelection());
11840
- const next = startEl ? detectActiveFormats(startEl, activeRoot) : /* @__PURE__ */ new Set();
11841
- setActiveCommands((prev) => setsEqual(prev, next) ? prev : next);
11842
- };
11843
11291
  const handleSelectionChange = () => {
11844
- if (pointerHeldRef.current) return;
11845
- if (selectionChangeRaf !== null) return;
11846
- selectionChangeRaf = requestAnimationFrame(runSelectionChange);
11847
- };
11848
- const markPointerHeld = (e) => {
11849
- if (e.button !== 0) return;
11850
- pointerHeldRef.current = true;
11851
- };
11852
- const markPointerReleased = () => {
11853
- if (!pointerHeldRef.current) return;
11854
- pointerHeldRef.current = false;
11855
- handleSelectionChange();
11292
+ if (!activeElRef.current) return;
11293
+ const next = /* @__PURE__ */ new Set();
11294
+ for (const cmd of ["bold", "italic", "underline", "strikeThrough", "insertUnorderedList", "insertOrderedList"]) {
11295
+ try {
11296
+ if (document.queryCommandState(cmd)) next.add(cmd);
11297
+ } catch {
11298
+ }
11299
+ }
11300
+ const sel = window.getSelection();
11301
+ const anchor = sel?.anchorNode;
11302
+ if (anchor) {
11303
+ const el = anchor.nodeType === Node.TEXT_NODE ? anchor.parentElement : anchor;
11304
+ const block = el?.closest("div, p, h1, h2, h3, h4, h5, h6, li, td, th") ?? el;
11305
+ if (block) {
11306
+ const align = getComputedStyle(block).textAlign;
11307
+ if (align === "center") next.add("justifyCenter");
11308
+ else if (align === "right" || align === "end") next.add("justifyRight");
11309
+ else next.add("justifyLeft");
11310
+ }
11311
+ }
11312
+ setActiveCommands(next);
11856
11313
  };
11857
- refreshActiveCommandsRef.current = runSelectionChange;
11314
+ refreshActiveCommandsRef.current = handleSelectionChange;
11858
11315
  const handleDocMouseLeave = () => {
11859
11316
  hoveredImageRef.current = null;
11860
11317
  setMediaHover(null);
@@ -12094,6 +11551,7 @@ function OhhwellsBridge() {
12094
11551
  const anchor = getNavigationItemAnchor(target);
12095
11552
  const hrefKey = anchor?.getAttribute("data-ohw-href-key") ?? null;
12096
11553
  if (anchor && isFooterHrefKey(hrefKey)) {
11554
+ armFooterPressDrag();
12097
11555
  footerPointerDragRef.current = {
12098
11556
  el: anchor,
12099
11557
  kind: "link",
@@ -12107,6 +11565,7 @@ function OhhwellsBridge() {
12107
11565
  }
12108
11566
  const col = target.closest("[data-ohw-footer-col]");
12109
11567
  if (col && !getNavigationItemAnchor(target)) {
11568
+ armFooterPressDrag();
12110
11569
  footerPointerDragRef.current = {
12111
11570
  el: col,
12112
11571
  kind: "column",
@@ -12135,7 +11594,6 @@ function OhhwellsBridge() {
12135
11594
  if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
12136
11595
  e.preventDefault();
12137
11596
  pending.started = true;
12138
- armFooterPressDrag();
12139
11597
  clearTextSelection();
12140
11598
  try {
12141
11599
  document.body.setPointerCapture(pending.pointerId);
@@ -12189,8 +11647,7 @@ function OhhwellsBridge() {
12189
11647
  }
12190
11648
  } catch {
12191
11649
  }
12192
- if (!pending) return;
12193
- if (!pending.started) {
11650
+ if (!pending?.started) {
12194
11651
  unlockFooterDragInteraction();
12195
11652
  return;
12196
11653
  }
@@ -12283,39 +11740,9 @@ function OhhwellsBridge() {
12283
11740
  return () => window.removeEventListener("hashchange", onHashChange);
12284
11741
  }, [pathname]);
12285
11742
  const handleCommand = (0, import_react9.useCallback)((cmd) => {
12286
- const el = activeElRef.current;
12287
- const selBefore = window.getSelection();
12288
- let savedOffsets = null;
12289
- if (el && selBefore && selBefore.rangeCount > 0 && !selBefore.isCollapsed) {
12290
- const r2 = selBefore.getRangeAt(0);
12291
- if (el.contains(r2.commonAncestorContainer)) {
12292
- savedOffsets = {
12293
- start: textOffsetInRoot(el, r2.startContainer, r2.startOffset),
12294
- end: textOffsetInRoot(el, r2.endContainer, r2.endOffset)
12295
- };
12296
- }
12297
- }
12298
- document.execCommand("styleWithCSS", false, true);
12299
11743
  document.execCommand(cmd, false);
12300
- if (el && document.activeElement !== el) {
12301
- el.focus();
12302
- }
12303
- const selAfter = window.getSelection();
12304
- if (el && savedOffsets && selAfter?.isCollapsed) {
12305
- const start = pointAtTextOffset(el, savedOffsets.start);
12306
- const end = pointAtTextOffset(el, savedOffsets.end);
12307
- if (start && end) {
12308
- try {
12309
- const range = document.createRange();
12310
- range.setStart(start.node, start.offset);
12311
- range.setEnd(end.node, end.offset);
12312
- selAfter.removeAllRanges();
12313
- selAfter.addRange(range);
12314
- } catch {
12315
- }
12316
- }
12317
- }
12318
- if (el) setToolbarRect(getEditMeasureEl(el).getBoundingClientRect());
11744
+ activeElRef.current?.focus();
11745
+ if (activeElRef.current) setToolbarRect(getEditMeasureEl(activeElRef.current).getBoundingClientRect());
12319
11746
  refreshActiveCommandsRef.current();
12320
11747
  }, []);
12321
11748
  const handleStateChange = (0, import_react9.useCallback)((state) => {
@@ -12455,9 +11882,9 @@ function OhhwellsBridge() {
12455
11882
  [postToParent2]
12456
11883
  );
12457
11884
  return bridgeRoot ? (0, import_react_dom3.createPortal)(
12458
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
12459
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
12460
- Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11885
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
11886
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
11887
+ Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12461
11888
  MediaOverlay,
12462
11889
  {
12463
11890
  hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
@@ -12468,7 +11895,7 @@ function OhhwellsBridge() {
12468
11895
  },
12469
11896
  `uploading-${key}`
12470
11897
  )),
12471
- mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11898
+ mediaHover && !(mediaHover.key in uploadingRects) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12472
11899
  MediaOverlay,
12473
11900
  {
12474
11901
  hover: mediaHover,
@@ -12477,10 +11904,10 @@ function OhhwellsBridge() {
12477
11904
  onVideoSettingsChange: handleVideoSettingsChange
12478
11905
  }
12479
11906
  ),
12480
- siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
12481
- siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
12482
- isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
12483
- isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11907
+ siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
11908
+ siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
11909
+ isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
11910
+ isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12484
11911
  "div",
12485
11912
  {
12486
11913
  className: "pointer-events-none fixed z-2147483646",
@@ -12490,7 +11917,7 @@ function OhhwellsBridge() {
12490
11917
  width: slot.width,
12491
11918
  height: slot.height
12492
11919
  },
12493
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11920
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12494
11921
  DropIndicator,
12495
11922
  {
12496
11923
  direction: slot.direction,
@@ -12501,7 +11928,7 @@ function OhhwellsBridge() {
12501
11928
  },
12502
11929
  `footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
12503
11930
  )),
12504
- isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11931
+ isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12505
11932
  "div",
12506
11933
  {
12507
11934
  className: "pointer-events-none fixed z-2147483646",
@@ -12511,7 +11938,7 @@ function OhhwellsBridge() {
12511
11938
  width: slot.width,
12512
11939
  height: slot.height
12513
11940
  },
12514
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11941
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12515
11942
  DropIndicator,
12516
11943
  {
12517
11944
  direction: slot.direction,
@@ -12522,11 +11949,10 @@ function OhhwellsBridge() {
12522
11949
  },
12523
11950
  `nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
12524
11951
  )),
12525
- hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
12526
- hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
12527
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
12528
- toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(FooterContainerChrome, { rect: toolbarRect, onAdd: handleAddFooterColumn }),
12529
- toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11952
+ hoveredNavContainerRect && toolbarVariant !== "select-frame" && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
11953
+ hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
11954
+ toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
11955
+ toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame") && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12530
11956
  ItemInteractionLayer,
12531
11957
  {
12532
11958
  rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
@@ -12540,7 +11966,7 @@ function OhhwellsBridge() {
12540
11966
  onItemPointerDown: handleItemChromePointerDown,
12541
11967
  onItemClick: handleItemChromeClick,
12542
11968
  itemDragSurface: !isFooterFrameSelection,
12543
- toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11969
+ toolbar: toolbarVariant === "link-action" && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12544
11970
  ItemActionToolbar,
12545
11971
  {
12546
11972
  onEditLink: openLinkPopoverForSelected,
@@ -12553,8 +11979,8 @@ function OhhwellsBridge() {
12553
11979
  ) : void 0
12554
11980
  }
12555
11981
  ),
12556
- toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
12557
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11982
+ toolbarRect && toolbarVariant === "rich-text" && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
11983
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12558
11984
  EditGlowChrome,
12559
11985
  {
12560
11986
  rect: toolbarRect,
@@ -12564,7 +11990,7 @@ function OhhwellsBridge() {
12564
11990
  hideHandle: isItemDragging
12565
11991
  }
12566
11992
  ),
12567
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
11993
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12568
11994
  FloatingToolbar,
12569
11995
  {
12570
11996
  rect: toolbarRect,
@@ -12577,7 +12003,7 @@ function OhhwellsBridge() {
12577
12003
  }
12578
12004
  )
12579
12005
  ] }),
12580
- maxBadge && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
12006
+ maxBadge && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
12581
12007
  "div",
12582
12008
  {
12583
12009
  "data-ohw-max-badge": "",
@@ -12603,7 +12029,7 @@ function OhhwellsBridge() {
12603
12029
  ]
12604
12030
  }
12605
12031
  ),
12606
- toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
12032
+ toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12607
12033
  StateToggle,
12608
12034
  {
12609
12035
  rect: toggleState.rect,
@@ -12612,15 +12038,15 @@ function OhhwellsBridge() {
12612
12038
  onStateChange: handleStateChange
12613
12039
  }
12614
12040
  ),
12615
- sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
12041
+ sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
12616
12042
  "div",
12617
12043
  {
12618
12044
  "data-ohw-section-insert-line": "",
12619
12045
  className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
12620
12046
  style: { top: sectionGap.y, transform: "translateY(-50%)" },
12621
12047
  children: [
12622
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12623
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
12048
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } }),
12049
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12624
12050
  Badge,
12625
12051
  {
12626
12052
  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",
@@ -12637,11 +12063,11 @@ function OhhwellsBridge() {
12637
12063
  children: "Add Section"
12638
12064
  }
12639
12065
  ),
12640
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12066
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex-1 bg-primary", style: { height: 3 } })
12641
12067
  ]
12642
12068
  }
12643
12069
  ),
12644
- linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
12070
+ linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
12645
12071
  LinkPopover,
12646
12072
  {
12647
12073
  panelRef: linkPopoverPanelRef,