@ohhwells/bridge 0.1.55-next.158 → 0.1.55-next.160

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
@@ -347,6 +347,17 @@ var FEATURE_LINE_CSS = [
347
347
  function textAttrs(ctx, path) {
348
348
  return ctx.keyFor ? { "data-ohw-key": ctx.keyFor(path), "data-ohw-editable": "text" } : {};
349
349
  }
350
+ var AI_RESPONSIVE_CSS = [
351
+ "@media (max-width: 960px) {",
352
+ " [data-ai-responsive] [data-ai-grid] { grid-template-columns: repeat(2, 1fr) !important; }",
353
+ ' [data-ai-responsive] [data-ai-grid="1"] { grid-template-columns: 1fr !important; }',
354
+ "}",
355
+ "@media (max-width: 640px) {",
356
+ " [data-ai-responsive] [data-ai-grid] { grid-template-columns: 1fr !important; }",
357
+ " [data-ai-responsive] [data-ai-columns] > * { grid-column: 1 / -1 !important; }",
358
+ " [data-ai-responsive] [data-ai-section-inner] { padding-left: 20px !important; padding-right: 20px !important; }",
359
+ "}"
360
+ ].join("\n");
350
361
  var TRANSPARENT_PX = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
351
362
  function MediaBox({
352
363
  refValue,
@@ -1089,6 +1100,7 @@ function Carousel({ items, itemsPerRow, ctx }) {
1089
1100
  children: pageGroups.map((group, p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1090
1101
  "div",
1091
1102
  {
1103
+ "data-ai-grid": String(itemsPerRow),
1092
1104
  style: {
1093
1105
  flex: "0 0 100%",
1094
1106
  display: "grid",
@@ -1192,6 +1204,7 @@ function CollectionBlock({ node, ctx, path }) {
1192
1204
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1193
1205
  "div",
1194
1206
  {
1207
+ "data-ai-grid": String(itemsPerRow),
1195
1208
  style: {
1196
1209
  display: "grid",
1197
1210
  gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`,
@@ -1355,6 +1368,7 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1355
1368
  {
1356
1369
  "data-ai-section": tree.tag ?? "",
1357
1370
  ...bgAttrs,
1371
+ "data-ai-responsive": "",
1358
1372
  style: {
1359
1373
  position: "relative",
1360
1374
  padding: `${pad}px 0`,
@@ -1364,10 +1378,12 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1364
1378
  backgroundPosition: "center"
1365
1379
  },
1366
1380
  children: [
1381
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: AI_RESPONSIVE_CSS }),
1367
1382
  isOverlay && backgroundUrl && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { position: "absolute", inset: 0, background: `rgba(255,255,255,${overlayAlpha})` } }),
1368
1383
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1369
1384
  "div",
1370
1385
  {
1386
+ "data-ai-section-inner": "",
1371
1387
  style: {
1372
1388
  position: "relative",
1373
1389
  maxWidth: AI_TREE_TOKENS.sectionMaxWidth,
@@ -1378,6 +1394,7 @@ function AiTreeRenderer({ tree, brand, resolveMedia, editKeyPrefix }) {
1378
1394
  children: tree.rows.map((row, r2) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1379
1395
  "div",
1380
1396
  {
1397
+ "data-ai-columns": "",
1381
1398
  style: {
1382
1399
  display: "grid",
1383
1400
  gridTemplateColumns: "repeat(12, 1fr)",
@@ -6304,6 +6321,7 @@ var FOCUS_RING = `0 0 0 4px color-mix(in srgb, ${PRIMARY} 12%, transparent)`;
6304
6321
  var DRAG_SHADOW = "0px 4px 6px -1px rgba(0, 0, 0, 0.1), 0px 2px 4px -2px rgba(0, 0, 0, 0.1)";
6305
6322
  var TOOLBAR_EDGE_MARGIN = 4;
6306
6323
  var SELECTION_CHROME_GAP = 4;
6324
+ var HOVER_CHROME_GAP = 2;
6307
6325
  var TOOLBAR_STROKE_GAP = 4;
6308
6326
  function getChromeZIndex(state) {
6309
6327
  switch (state) {
@@ -6459,10 +6477,11 @@ function ItemInteractionLayer({
6459
6477
  onItemPointerDown,
6460
6478
  onItemClick,
6461
6479
  itemDragSurface = true,
6462
- chromeGap = SELECTION_CHROME_GAP,
6480
+ chromeGap,
6463
6481
  className
6464
6482
  }) {
6465
6483
  if (state === "default") return null;
6484
+ const gap = chromeGap ?? (state === "hover" ? HOVER_CHROME_GAP : SELECTION_CHROME_GAP);
6466
6485
  const isActive = state === "active-top" || state === "active-bottom";
6467
6486
  const isDragging = state === "dragging";
6468
6487
  const showToolbar = isActive && toolbar;
@@ -6478,10 +6497,10 @@ function ItemInteractionLayer({
6478
6497
  className: cn("pointer-events-none", className),
6479
6498
  style: {
6480
6499
  position: "fixed",
6481
- top: rect.top - chromeGap,
6482
- left: rect.left - chromeGap,
6483
- width: rect.width + chromeGap * 2,
6484
- height: rect.height + chromeGap * 2,
6500
+ top: rect.top - gap,
6501
+ left: rect.left - gap,
6502
+ width: rect.width + gap * 2,
6503
+ height: rect.height + gap * 2,
6485
6504
  zIndex: getChromeZIndex(state)
6486
6505
  },
6487
6506
  children: [
@@ -10139,6 +10158,7 @@ function ensureIconSlot(item) {
10139
10158
  // src/lib/footer-items.ts
10140
10159
  var FOOTER_ORDER_KEY = "__ohw_footer_order";
10141
10160
  var MAX_FOOTER_COLUMNS = 18;
10161
+ var MAX_FOOTER_ITEMS_PER_COLUMN = 7;
10142
10162
  var FOOTER_HREF_RE = /^footer-(\d+)-(\d+)-href$/;
10143
10163
  function parseFooterHrefKey(key) {
10144
10164
  if (!key) return null;
@@ -10356,6 +10376,13 @@ function getNextFooterColumnIndex() {
10356
10376
  function canAddFooterColumn() {
10357
10377
  return listFooterColumns().length < MAX_FOOTER_COLUMNS;
10358
10378
  }
10379
+ function canAddFooterItem(column) {
10380
+ return listFooterLinksInColumn(column).length < MAX_FOOTER_ITEMS_PER_COLUMN;
10381
+ }
10382
+ function resolveFooterColumnForAdd(selected) {
10383
+ if (selected.hasAttribute("data-ohw-footer-col")) return selected;
10384
+ return selected.closest("[data-ohw-footer-col]") ?? (listFooterColumns().includes(selected) ? selected : null);
10385
+ }
10359
10386
  function buildFooterHeading(colIndex, text) {
10360
10387
  const heading = document.createElement("p");
10361
10388
  heading.setAttribute("data-ohw-editable", "text");
@@ -11408,6 +11435,7 @@ function FloatingPanel({
11408
11435
  e.stopPropagation();
11409
11436
  const el = e.currentTarget;
11410
11437
  el.setPointerCapture(e.pointerId);
11438
+ document.documentElement.setAttribute("data-ohw-panel-dragging", "");
11411
11439
  dragRef.current = {
11412
11440
  pointerId: e.pointerId,
11413
11441
  startX: e.clientX,
@@ -11440,11 +11468,17 @@ function FloatingPanel({
11440
11468
  const drag = dragRef.current;
11441
11469
  if (!drag || drag.pointerId !== e.pointerId) return;
11442
11470
  dragRef.current = null;
11471
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
11443
11472
  try {
11444
11473
  e.currentTarget.releasePointerCapture(e.pointerId);
11445
11474
  } catch {
11446
11475
  }
11447
11476
  }, []);
11477
+ (0, import_react13.useEffect)(() => {
11478
+ if (open) return;
11479
+ document.documentElement.removeAttribute("data-ohw-panel-dragging");
11480
+ }, [open]);
11481
+ (0, import_react13.useEffect)(() => () => document.documentElement.removeAttribute("data-ohw-panel-dragging"), []);
11448
11482
  if (!open) return null;
11449
11483
  return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
11450
11484
  "div",
@@ -13351,6 +13385,11 @@ function isNavbarLinksContainer2(el) {
13351
13385
  function getFooterColumn(el) {
13352
13386
  return el.closest("[data-ohw-footer-col], [data-ohw-footer-column]");
13353
13387
  }
13388
+ function isFooterAddItemDisabled(selected) {
13389
+ if (!selected) return false;
13390
+ const column = resolveFooterColumnForAdd(selected);
13391
+ return column ? !canAddFooterItem(column) : false;
13392
+ }
13354
13393
  function resolveFooterColumnSelectionTarget(target, clientX, clientY) {
13355
13394
  if (getNavigationItemAnchor(target)) return null;
13356
13395
  const column = getFooterColumn(target);
@@ -13664,6 +13703,9 @@ var ICONS = {
13664
13703
  var SELECTION_CHROME_GAP2 = 4;
13665
13704
  var TOOLBAR_STROKE_GAP2 = 4;
13666
13705
  var TOOLBAR_OFFSET_FROM_ELEMENT = SELECTION_CHROME_GAP2 + TOOLBAR_STROKE_GAP2;
13706
+ var HOVER_STROKE_WIDTH = 1.5;
13707
+ var TEXT_HOVER_SIDE_PAD = 4;
13708
+ var CHROME_PRIMARY = `var(--ohw-primary, ${PRIMARY3})`;
13667
13709
  var TOOLBAR_GROUPS = [
13668
13710
  [
13669
13711
  { cmd: "bold", title: "Bold" },
@@ -14171,6 +14213,28 @@ function OhhwellsBridge() {
14171
14213
  const [hoveredNavContainerRect, setHoveredNavContainerRect] = (0, import_react16.useState)(null);
14172
14214
  const hoveredItemElRef = (0, import_react16.useRef)(null);
14173
14215
  const [hoveredItemRect, setHoveredItemRect] = (0, import_react16.useState)(null);
14216
+ const [hoveredTextRect, setHoveredTextRect] = (0, import_react16.useState)(null);
14217
+ (0, import_react16.useEffect)(() => {
14218
+ const sync = () => {
14219
+ const el = document.querySelector(
14220
+ "[data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key])"
14221
+ );
14222
+ const target = el && !el.closest("[data-ohw-href-key]") ? el : null;
14223
+ if (!target) {
14224
+ setHoveredTextRect(null);
14225
+ return;
14226
+ }
14227
+ const r2 = target.getBoundingClientRect();
14228
+ setHoveredTextRect(new DOMRect(r2.x - TEXT_HOVER_SIDE_PAD, r2.y, r2.width + TEXT_HOVER_SIDE_PAD * 2, r2.height));
14229
+ };
14230
+ const observer = new MutationObserver(sync);
14231
+ observer.observe(document.documentElement, {
14232
+ attributes: true,
14233
+ attributeFilter: ["data-ohw-hovered"],
14234
+ subtree: true
14235
+ });
14236
+ return () => observer.disconnect();
14237
+ }, []);
14174
14238
  const siblingHintElRef = (0, import_react16.useRef)(null);
14175
14239
  const [siblingHintRect, setSiblingHintRect] = (0, import_react16.useState)(null);
14176
14240
  const [siblingHintRects, setSiblingHintRects] = (0, import_react16.useState)([]);
@@ -14663,10 +14727,16 @@ function OhhwellsBridge() {
14663
14727
  return;
14664
14728
  }
14665
14729
  if (toolbarVariantRef.current === "select-frame" && isFooterFrameSelection) {
14666
- if (!selected.hasAttribute("data-ohw-footer-col") && !selected.closest("[data-ohw-footer-col]")) {
14667
- }
14668
- const column = (selected.hasAttribute("data-ohw-footer-col") ? selected : null) ?? selected.closest("[data-ohw-footer-col]") ?? (listFooterColumns().includes(selected) ? selected : null);
14730
+ const column = resolveFooterColumnForAdd(selected);
14669
14731
  if (!column) return;
14732
+ if (!canAddFooterItem(column)) {
14733
+ postToParent2({
14734
+ type: "ow:toast",
14735
+ title: `Maximum ${MAX_FOOTER_ITEMS_PER_COLUMN} items per column`,
14736
+ toastType: "error"
14737
+ });
14738
+ return;
14739
+ }
14670
14740
  const result2 = insertFooterItem(column, "/", "New link", null);
14671
14741
  applyLinkByKey(result2.hrefKey, result2.href);
14672
14742
  document.querySelectorAll(`[data-ohw-key="${result2.labelKey}"]`).forEach((el) => {
@@ -15645,7 +15715,7 @@ function OhhwellsBridge() {
15645
15715
  reconcileSocialsFromContent(content);
15646
15716
  applySocialsDisplayFromContent(content);
15647
15717
  document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
15648
- if (isFooterHrefKey(el.getAttribute("data-ohw-href-key"))) {
15718
+ if (isFooterHrefKey(el.getAttribute("data-ohw-href-key")) || getSocialItem(el)) {
15649
15719
  disableNativeHrefDrag(el);
15650
15720
  }
15651
15721
  });
@@ -15773,9 +15843,12 @@ function OhhwellsBridge() {
15773
15843
  [data-ohw-editable="video"], [data-ohw-editable="video"] *,
15774
15844
  [data-ohw-editable="bg-image"], [data-ohw-editable="bg-image"] * { cursor: pointer !important; }
15775
15845
  [data-ohw-editable="link"], [data-ohw-editable="link"] * { cursor: pointer !important; }
15846
+ /* Text hover chrome is drawn by the overlay (see hoveredTextRect) \u2014 the CSS outline
15847
+ that used to draw it dashes denser than the overlay border, so identical specs
15848
+ still read as two different frames (OHH-695). The attribute stays: hover paths
15849
+ and suppression rules key off it. */
15776
15850
  [data-ohw-hovered]:not([contenteditable]):not([data-ohw-href-key]) {
15777
- outline: 2px dashed ${PRIMARY3} !important;
15778
- outline-offset: 4px;
15851
+ outline: none !important;
15779
15852
  }
15780
15853
  [data-ohw-href-key] [data-ohw-hovered],
15781
15854
  [data-ohw-href-key][data-ohw-hovered],
@@ -15828,8 +15901,11 @@ function OhhwellsBridge() {
15828
15901
  stateViews.textContent = `
15829
15902
  [data-ohw-state-view]:not([data-ohw-state-view="default"]) { display: none; }
15830
15903
  [data-ohw-state-view="default"] [data-ohw-editable] { pointer-events: auto !important; }
15831
- [data-ohw-state-hovered] { outline: 2px dashed ${PRIMARY3} !important; outline-offset: 4px; }
15904
+ [data-ohw-state-hovered] { outline: ${HOVER_STROKE_WIDTH}px dashed ${CHROME_PRIMARY} !important; outline-offset: ${HOVER_CHROME_GAP}px; }
15832
15905
  [data-ohw-state-hovered]:has([data-ohw-hovered]) { outline: none !important; }
15906
+ /* :has() only sees descendants \u2014 when the card itself is the hovered text, the overlay
15907
+ already frames it, and the card outline doubled it (OHH-695). */
15908
+ [data-ohw-state-hovered][data-ohw-hovered] { outline: none !important; }
15833
15909
  `;
15834
15910
  document.head.appendChild(base);
15835
15911
  document.head.appendChild(forceHover);
@@ -16110,7 +16186,7 @@ function OhhwellsBridge() {
16110
16186
  setHoveredNavContainerRect(null);
16111
16187
  return;
16112
16188
  }
16113
- if (isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16189
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || isInsideFloatingPanel(target) || isPointOverFloatingPanel(e.clientX, e.clientY)) {
16114
16190
  hoveredItemElRef.current = null;
16115
16191
  setHoveredItemRect(null);
16116
16192
  hoveredNavContainerRef.current = null;
@@ -16206,7 +16282,6 @@ function OhhwellsBridge() {
16206
16282
  hoveredNavContainerRef.current = null;
16207
16283
  setHoveredNavContainerRect(null);
16208
16284
  hoveredItemElRef.current = editable;
16209
- setHoveredItemRect(editable.getBoundingClientRect());
16210
16285
  }
16211
16286
  }
16212
16287
  }
@@ -16825,7 +16900,7 @@ function OhhwellsBridge() {
16825
16900
  };
16826
16901
  const handleMouseMove = (e) => {
16827
16902
  const { clientX, clientY } = e;
16828
- if (floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16903
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16829
16904
  hoveredItemElRef.current = null;
16830
16905
  setHoveredItemRect(null);
16831
16906
  hoveredNavContainerRef.current = null;
@@ -16846,7 +16921,7 @@ function OhhwellsBridge() {
16846
16921
  if (e.data?.type !== "ow:pointer-sync") return;
16847
16922
  const { clientX, clientY } = e.data;
16848
16923
  if (typeof clientX !== "number" || typeof clientY !== "number") return;
16849
- if (floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16924
+ if (document.documentElement.hasAttribute("data-ohw-panel-dragging") || floatingPanelOpenRef.current && isPointOverFloatingPanel(clientX, clientY)) {
16850
16925
  dismissImageHover();
16851
16926
  clearImageHover();
16852
16927
  return;
@@ -17949,7 +18024,7 @@ function OhhwellsBridge() {
17949
18024
  if (footerDragRef.current) return;
17950
18025
  const target = e.target;
17951
18026
  if (!target) return;
17952
- 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]')) {
18027
+ 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]')) {
17953
18028
  return;
17954
18029
  }
17955
18030
  if (target.closest("[data-ohw-item-drag-surface]")) return;
@@ -18593,6 +18668,7 @@ function OhhwellsBridge() {
18593
18668
  )),
18594
18669
  hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
18595
18670
  hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
18671
+ hoveredTextRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
18596
18672
  toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
18597
18673
  toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
18598
18674
  FooterContainerChrome,
@@ -18633,7 +18709,7 @@ function OhhwellsBridge() {
18633
18709
  onSelectParent: handleSelectParent,
18634
18710
  onDuplicate: handleDuplicateSelected,
18635
18711
  onDelete: handleDeleteSelected,
18636
- addItemDisabled: false,
18712
+ addItemDisabled: isFooterFrameSelection && isFooterAddItemDisabled(selectedElRef.current),
18637
18713
  editLinkDisabled: false,
18638
18714
  moreDisabled: false,
18639
18715
  duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow,