@ohhwells/bridge 0.1.120 → 0.1.122
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 +2457 -400
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +2456 -399
- package/dist/index.js.map +1 -1
- package/dist/styles.css +79 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -501,6 +501,40 @@ function applyBrandToDom(kit) {
|
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
// src/lib/custom-code.ts
|
|
505
|
+
var ALLOWED_HEAD_TAGS = /* @__PURE__ */ new Set(["style", "meta", "link", "script", "noscript", "base"]);
|
|
506
|
+
var CUSTOM_CODE_AFTER_HEAD_KEY = "__ohw_custom_code_after_head";
|
|
507
|
+
var CUSTOM_CODE_BEFORE_HEAD_KEY = "__ohw_custom_code_before_head";
|
|
508
|
+
function clearExisting(slot) {
|
|
509
|
+
document.querySelectorAll(`[data-ohw-custom-code="${slot}"]`).forEach((el) => el.remove());
|
|
510
|
+
}
|
|
511
|
+
function buildNodes(raw, slot) {
|
|
512
|
+
if (!raw || !raw.trim()) return [];
|
|
513
|
+
const parsed = new DOMParser().parseFromString(raw, "text/html");
|
|
514
|
+
const source = [...parsed.head.childNodes, ...parsed.body.childNodes];
|
|
515
|
+
const nodes = [];
|
|
516
|
+
for (const node of source) {
|
|
517
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
518
|
+
const el = node;
|
|
519
|
+
const tag = el.tagName.toLowerCase();
|
|
520
|
+
if (!ALLOWED_HEAD_TAGS.has(tag)) continue;
|
|
521
|
+
const built = document.createElement(tag);
|
|
522
|
+
for (const attr of Array.from(el.attributes)) built.setAttribute(attr.name, attr.value);
|
|
523
|
+
if (tag === "script" || tag === "style" || tag === "noscript") built.textContent = el.textContent;
|
|
524
|
+
built.dataset.ohwCustomCode = slot;
|
|
525
|
+
nodes.push(built);
|
|
526
|
+
}
|
|
527
|
+
return nodes;
|
|
528
|
+
}
|
|
529
|
+
function applyCustomCodeToHead(content) {
|
|
530
|
+
clearExisting("after");
|
|
531
|
+
clearExisting("before");
|
|
532
|
+
const afterNodes = buildNodes(content[CUSTOM_CODE_AFTER_HEAD_KEY], "after");
|
|
533
|
+
if (afterNodes.length > 0) document.head.prepend(...afterNodes);
|
|
534
|
+
const beforeNodes = buildNodes(content[CUSTOM_CODE_BEFORE_HEAD_KEY], "before");
|
|
535
|
+
if (beforeNodes.length > 0) document.head.append(...beforeNodes);
|
|
536
|
+
}
|
|
537
|
+
|
|
504
538
|
// src/lib/section-styles.ts
|
|
505
539
|
var STYLE_STORE_KEY = "__ohw_styles";
|
|
506
540
|
var STYLE_SHEET_ID = "ohw-section-styles";
|
|
@@ -564,9 +598,9 @@ function styleSheetCss() {
|
|
|
564
598
|
);
|
|
565
599
|
}
|
|
566
600
|
const pad = { tight: 40, balanced: 64, airy: 96 };
|
|
567
|
-
for (const [spacing,
|
|
601
|
+
for (const [spacing, px2] of Object.entries(pad)) {
|
|
568
602
|
rules.push(
|
|
569
|
-
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${
|
|
603
|
+
`[data-ohw-style-spacing="${spacing}"] { padding-top: ${px2}px !important; padding-bottom: ${px2}px !important; }`
|
|
570
604
|
);
|
|
571
605
|
}
|
|
572
606
|
rules.push(
|
|
@@ -3133,12 +3167,12 @@ function deriveTemplateButtonStyle() {
|
|
|
3133
3167
|
cs.borderBottomLeftRadius
|
|
3134
3168
|
].map((v) => v || "0px");
|
|
3135
3169
|
const radius = corners.every((v) => v === corners[0]) ? corners[0] : corners.join(" ");
|
|
3136
|
-
const
|
|
3137
|
-
const lineHeight =
|
|
3138
|
-
const contentH = btn.getBoundingClientRect().height -
|
|
3170
|
+
const px2 = (v) => parseFloat(v) || 0;
|
|
3171
|
+
const lineHeight = px2(cs.lineHeight) || px2(cs.fontSize) * 1.2;
|
|
3172
|
+
const contentH = btn.getBoundingClientRect().height - px2(cs.borderTopWidth) - px2(cs.borderBottomWidth);
|
|
3139
3173
|
const impliedY = Math.round(Math.max(0, (contentH - lineHeight) / 2));
|
|
3140
|
-
const padY = Math.max(
|
|
3141
|
-
const padX = Math.max(
|
|
3174
|
+
const padY = Math.max(px2(cs.paddingTop), px2(cs.paddingBottom), impliedY);
|
|
3175
|
+
const padX = Math.max(px2(cs.paddingLeft), px2(cs.paddingRight));
|
|
3142
3176
|
return {
|
|
3143
3177
|
radius: radius || "10px",
|
|
3144
3178
|
padding: `${padY}px ${padX}px`,
|
|
@@ -8055,6 +8089,14 @@ function ItemActionToolbar({
|
|
|
8055
8089
|
e.preventDefault();
|
|
8056
8090
|
e.stopPropagation();
|
|
8057
8091
|
onStyle?.();
|
|
8092
|
+
},
|
|
8093
|
+
// Same as Edit link: mousedown opens the panel and remounts this toolbar
|
|
8094
|
+
// (styleActive flips). Without stopping click, the gesture lands on whatever
|
|
8095
|
+
// is now under the cursor — navbar CTAs park the toolbar below the button, so
|
|
8096
|
+
// that miss deselects and the panel closes as soon as it opens.
|
|
8097
|
+
onClick: (e) => {
|
|
8098
|
+
e.preventDefault();
|
|
8099
|
+
e.stopPropagation();
|
|
8058
8100
|
}
|
|
8059
8101
|
},
|
|
8060
8102
|
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react3.Brush, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
@@ -8377,20 +8419,32 @@ function ItemInteractionLayer({
|
|
|
8377
8419
|
itemDragSurface = true,
|
|
8378
8420
|
chromeGap,
|
|
8379
8421
|
toolbarAlign = "center",
|
|
8422
|
+
hidden = false,
|
|
8380
8423
|
className
|
|
8381
8424
|
}) {
|
|
8425
|
+
const localRef = (0, import_react7.useRef)(null);
|
|
8426
|
+
(0, import_react7.useLayoutEffect)(() => {
|
|
8427
|
+
const node = localRef.current;
|
|
8428
|
+
if (!node) return;
|
|
8429
|
+
node.style.display = hidden ? "none" : "block";
|
|
8430
|
+
}, [hidden, rect.top, rect.left, rect.width, rect.height, state]);
|
|
8382
8431
|
if (state === "default") return null;
|
|
8383
8432
|
const gap = chromeGap ?? (state === "hover" ? HOVER_CHROME_GAP : SELECTION_CHROME_GAP);
|
|
8384
8433
|
const isActive = state === "active-top" || state === "active-bottom";
|
|
8385
8434
|
const isDragging = state === "dragging";
|
|
8386
8435
|
const showToolbar = isActive && toolbar;
|
|
8387
8436
|
const showDragHandle = (isActive || isDragging) && showHandle;
|
|
8388
|
-
const itemDragEnabled = itemDragSurface && isActive &&
|
|
8437
|
+
const itemDragEnabled = itemDragSurface && isActive && !isDragging && !dragDisabled && Boolean(showHandle || onItemPointerDown);
|
|
8389
8438
|
const useDetachedBelowToolbar = Boolean(showToolbar && state === "active-bottom" && toolbarBelowRect);
|
|
8439
|
+
const setRootRef = (node) => {
|
|
8440
|
+
localRef.current = node;
|
|
8441
|
+
if (typeof elRef === "function") elRef(node);
|
|
8442
|
+
else if (elRef) elRef.current = node;
|
|
8443
|
+
};
|
|
8390
8444
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
8391
8445
|
"div",
|
|
8392
8446
|
{
|
|
8393
|
-
ref:
|
|
8447
|
+
ref: setRootRef,
|
|
8394
8448
|
"data-ohw-item-interaction": "",
|
|
8395
8449
|
"data-ohw-item-interaction-state": state,
|
|
8396
8450
|
className: cn("pointer-events-none", className),
|
|
@@ -8400,7 +8454,8 @@ function ItemInteractionLayer({
|
|
|
8400
8454
|
left: rect.left - gap,
|
|
8401
8455
|
width: rect.width + gap * 2,
|
|
8402
8456
|
height: rect.height + gap * 2,
|
|
8403
|
-
zIndex: getChromeZIndex(state)
|
|
8457
|
+
zIndex: getChromeZIndex(state),
|
|
8458
|
+
display: hidden ? "none" : "block"
|
|
8404
8459
|
},
|
|
8405
8460
|
children: [
|
|
8406
8461
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
@@ -11221,6 +11276,13 @@ function findButtonAtPoint(x, y, media) {
|
|
|
11221
11276
|
if (hits.length === 0) return null;
|
|
11222
11277
|
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
11223
11278
|
}
|
|
11279
|
+
function findNavbarCtaAtPoint(x, y) {
|
|
11280
|
+
const hits = Array.from(
|
|
11281
|
+
document.querySelectorAll('[data-ohw-role="navbar-button"]')
|
|
11282
|
+
).filter((el) => containsPoint(el, x, y) && !el.closest("[data-ohw-bridge]"));
|
|
11283
|
+
if (hits.length === 0) return null;
|
|
11284
|
+
return hits.reduce((best, el) => best.contains(el) ? el : best);
|
|
11285
|
+
}
|
|
11224
11286
|
|
|
11225
11287
|
// src/lib/session-search.ts
|
|
11226
11288
|
var STORAGE_KEY = "ohw-preserved-search";
|
|
@@ -11956,6 +12018,26 @@ var import_react12 = require("react");
|
|
|
11956
12018
|
var import_react_dom3 = require("react-dom");
|
|
11957
12019
|
var import_lucide_react15 = require("lucide-react");
|
|
11958
12020
|
var import_navigation2 = require("next/navigation");
|
|
12021
|
+
|
|
12022
|
+
// src/lib/parent-scroll.ts
|
|
12023
|
+
function visibleBand(parentScroll) {
|
|
12024
|
+
const { iframeOffsetTop, headerH: visibleCanvasTop, canvasH } = parentScroll;
|
|
12025
|
+
const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
12026
|
+
const bottom = Math.min(window.innerHeight, visibleCanvasTop + canvasH - iframeOffsetTop);
|
|
12027
|
+
return { top, bottom: Math.max(top, bottom) };
|
|
12028
|
+
}
|
|
12029
|
+
function getIframeVisibleClip(parentScroll) {
|
|
12030
|
+
if (!parentScroll) return null;
|
|
12031
|
+
return visibleBand(parentScroll);
|
|
12032
|
+
}
|
|
12033
|
+
function getIframeChromeClip(parentScroll) {
|
|
12034
|
+
if (!parentScroll) return null;
|
|
12035
|
+
const band = visibleBand(parentScroll);
|
|
12036
|
+
const promptBarH = Math.max(0, parentScroll.promptBarH ?? 0);
|
|
12037
|
+
return { top: band.top, bottom: Math.max(band.top, band.bottom - promptBarH) };
|
|
12038
|
+
}
|
|
12039
|
+
|
|
12040
|
+
// src/ui/link-modal/SectionPickerOverlay.tsx
|
|
11959
12041
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
11960
12042
|
var DIM_OVERLAY = "rgba(0, 0, 0, 0.45)";
|
|
11961
12043
|
function rectsEqual(a, b) {
|
|
@@ -12093,20 +12175,22 @@ function SectionPickerOverlay({
|
|
|
12093
12175
|
[]
|
|
12094
12176
|
);
|
|
12095
12177
|
(0, import_react12.useEffect)(() => {
|
|
12096
|
-
const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH) => {
|
|
12097
|
-
const
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12178
|
+
const applyClip = (iframeOffsetTop, visibleCanvasTop, canvasH, promptBarH = 0) => {
|
|
12179
|
+
const next = getIframeVisibleClip({
|
|
12180
|
+
iframeOffsetTop,
|
|
12181
|
+
headerH: visibleCanvasTop,
|
|
12182
|
+
canvasH,
|
|
12183
|
+
promptBarH
|
|
12184
|
+
});
|
|
12185
|
+
if (!next) return;
|
|
12102
12186
|
setChromeClip(
|
|
12103
|
-
(prev) => prev.top === top && prev.bottom === bottom ? prev :
|
|
12187
|
+
(prev) => prev.top === next.top && prev.bottom === next.bottom ? prev : next
|
|
12104
12188
|
);
|
|
12105
12189
|
};
|
|
12106
12190
|
const onParentScroll = (e) => {
|
|
12107
12191
|
if (e.data?.type !== "ow:parent-scroll") return;
|
|
12108
|
-
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
12109
|
-
applyClip(iframeOffsetTop, headerH, canvasH);
|
|
12192
|
+
const { iframeOffsetTop, headerH, canvasH, promptBarH = 0 } = e.data;
|
|
12193
|
+
applyClip(iframeOffsetTop, headerH, canvasH, promptBarH);
|
|
12110
12194
|
iframeOffsetTopRef.current = iframeOffsetTop;
|
|
12111
12195
|
if (!pointerScreenRef.current && pointerRef.current) {
|
|
12112
12196
|
pointerScreenRef.current = {
|
|
@@ -15770,36 +15854,50 @@ var import_lucide_react16 = require("lucide-react");
|
|
|
15770
15854
|
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
15771
15855
|
var PANEL_WIDTH = 256;
|
|
15772
15856
|
var EDGE_MARGIN = 16;
|
|
15857
|
+
var HEADER_MIN = 56;
|
|
15773
15858
|
function getVisibleClip(parentScroll) {
|
|
15774
15859
|
const left = 0;
|
|
15775
15860
|
const right = window.innerWidth;
|
|
15776
|
-
|
|
15861
|
+
const band = getIframeChromeClip(parentScroll);
|
|
15862
|
+
if (!band) {
|
|
15777
15863
|
return { top: 0, bottom: window.innerHeight, left, right };
|
|
15778
15864
|
}
|
|
15779
|
-
|
|
15780
|
-
const top = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
15781
|
-
const bottom = Math.min(window.innerHeight, visibleCanvasTop + canvasH - iframeOffsetTop);
|
|
15782
|
-
return { top, bottom: Math.max(top, bottom), left, right };
|
|
15865
|
+
return { ...band, left, right };
|
|
15783
15866
|
}
|
|
15784
|
-
function defaultFloatingPanelPosition(parentScroll,
|
|
15867
|
+
function defaultFloatingPanelPosition(parentScroll, _panelHeight = 280) {
|
|
15785
15868
|
const clip = getVisibleClip(parentScroll);
|
|
15786
15869
|
return {
|
|
15787
15870
|
x: Math.max(EDGE_MARGIN, clip.right - PANEL_WIDTH - EDGE_MARGIN),
|
|
15788
|
-
y:
|
|
15789
|
-
Math.max(clip.top + EDGE_MARGIN, EDGE_MARGIN),
|
|
15790
|
-
Math.max(clip.top + EDGE_MARGIN, clip.bottom - panelHeight - EDGE_MARGIN)
|
|
15791
|
-
)
|
|
15871
|
+
y: clip.top + EDGE_MARGIN
|
|
15792
15872
|
};
|
|
15793
15873
|
}
|
|
15794
|
-
function
|
|
15874
|
+
function clampX(x, panelW) {
|
|
15875
|
+
const left = EDGE_MARGIN;
|
|
15876
|
+
const maxX = Math.max(left, window.innerWidth - panelW - EDGE_MARGIN);
|
|
15877
|
+
return Math.min(Math.max(x, left), maxX);
|
|
15878
|
+
}
|
|
15879
|
+
function clampDragPosition(pos, parentScroll, panelW) {
|
|
15795
15880
|
const clip = getVisibleClip(parentScroll);
|
|
15796
|
-
const
|
|
15797
|
-
const maxY = Math.max(
|
|
15881
|
+
const minY = clip.top + EDGE_MARGIN;
|
|
15882
|
+
const maxY = Math.max(minY, clip.bottom - EDGE_MARGIN - HEADER_MIN);
|
|
15798
15883
|
return {
|
|
15799
|
-
x:
|
|
15800
|
-
y: Math.min(Math.max(pos.y,
|
|
15884
|
+
x: clampX(pos.x, panelW),
|
|
15885
|
+
y: Math.min(Math.max(pos.y, minY), maxY)
|
|
15801
15886
|
};
|
|
15802
15887
|
}
|
|
15888
|
+
function fitPanelInClip(homeY, parentScroll, preferredHeight) {
|
|
15889
|
+
const clip = getVisibleClip(parentScroll);
|
|
15890
|
+
const minY = clip.top + EDGE_MARGIN;
|
|
15891
|
+
const maxBottom = clip.bottom - EDGE_MARGIN;
|
|
15892
|
+
const band = Math.max(HEADER_MIN, maxBottom - minY);
|
|
15893
|
+
let y = Math.max(homeY, minY);
|
|
15894
|
+
const want = Math.min(Math.max(preferredHeight, HEADER_MIN), band);
|
|
15895
|
+
if (y + want > maxBottom) {
|
|
15896
|
+
y = Math.max(minY, maxBottom - want);
|
|
15897
|
+
}
|
|
15898
|
+
const maxHeight = Math.max(HEADER_MIN, Math.floor(maxBottom - y));
|
|
15899
|
+
return { y, maxHeight };
|
|
15900
|
+
}
|
|
15803
15901
|
function FloatingPanel({
|
|
15804
15902
|
open,
|
|
15805
15903
|
title,
|
|
@@ -15816,19 +15914,54 @@ function FloatingPanel({
|
|
|
15816
15914
|
const panelRef = (0, import_react15.useRef)(null);
|
|
15817
15915
|
const [measured, setMeasured] = (0, import_react15.useState)({ w: PANEL_WIDTH, h: 280 });
|
|
15818
15916
|
const dragRef = (0, import_react15.useRef)(null);
|
|
15819
|
-
const
|
|
15820
|
-
|
|
15917
|
+
const homeRef = (0, import_react15.useRef)(null);
|
|
15918
|
+
if (!open) {
|
|
15919
|
+
homeRef.current = null;
|
|
15920
|
+
} else if (position) {
|
|
15921
|
+
homeRef.current = position;
|
|
15922
|
+
} else if (homeRef.current == null) {
|
|
15923
|
+
homeRef.current = defaultFloatingPanelPosition(parentScroll);
|
|
15924
|
+
}
|
|
15925
|
+
const [liveScroll, setLiveScroll] = (0, import_react15.useState)(parentScroll);
|
|
15926
|
+
const home = position ?? homeRef.current ?? defaultFloatingPanelPosition(parentScroll);
|
|
15927
|
+
const { y: fittedY, maxHeight } = fitPanelInClip(home.y, liveScroll, measured.h);
|
|
15928
|
+
const clamped = {
|
|
15929
|
+
x: clampX(home.x, measured.w),
|
|
15930
|
+
y: fittedY
|
|
15931
|
+
};
|
|
15932
|
+
(0, import_react15.useEffect)(() => {
|
|
15933
|
+
setLiveScroll(parentScroll);
|
|
15934
|
+
}, [parentScroll]);
|
|
15935
|
+
(0, import_react15.useEffect)(() => {
|
|
15936
|
+
if (!open) return;
|
|
15937
|
+
const onParentScroll = (e) => {
|
|
15938
|
+
if (e.data?.type !== "ow:parent-scroll") return;
|
|
15939
|
+
const { iframeOffsetTop, headerH, canvasH, promptBarH = 0 } = e.data;
|
|
15940
|
+
setLiveScroll({ iframeOffsetTop, headerH, canvasH, promptBarH });
|
|
15941
|
+
};
|
|
15942
|
+
window.addEventListener("message", onParentScroll);
|
|
15943
|
+
return () => window.removeEventListener("message", onParentScroll);
|
|
15944
|
+
}, [open]);
|
|
15945
|
+
const positionRef = (0, import_react15.useRef)(position);
|
|
15946
|
+
(0, import_react15.useLayoutEffect)(() => {
|
|
15947
|
+
if (!open) {
|
|
15948
|
+
positionRef.current = position;
|
|
15949
|
+
return;
|
|
15950
|
+
}
|
|
15951
|
+
if (position == null && positionRef.current != null) {
|
|
15952
|
+
homeRef.current = defaultFloatingPanelPosition(liveScroll ?? parentScroll);
|
|
15953
|
+
}
|
|
15954
|
+
positionRef.current = position;
|
|
15955
|
+
}, [open, position, liveScroll, parentScroll]);
|
|
15821
15956
|
(0, import_react15.useLayoutEffect)(() => {
|
|
15822
15957
|
if (!open || !panelRef.current) return;
|
|
15823
15958
|
const el = panelRef.current;
|
|
15824
|
-
const
|
|
15959
|
+
const header = el.querySelector("[data-ohw-floating-panel-header]");
|
|
15960
|
+
const body = el.querySelector("[data-ohw-floating-panel-body]");
|
|
15961
|
+
const contentH = (header?.offsetHeight ?? 0) + (body?.scrollHeight ?? 0) || el.scrollHeight || 280;
|
|
15962
|
+
const next = { w: el.offsetWidth || PANEL_WIDTH, h: contentH };
|
|
15825
15963
|
setMeasured((prev) => prev.w === next.w && prev.h === next.h ? prev : next);
|
|
15826
15964
|
}, [open, children, title, context]);
|
|
15827
|
-
(0, import_react15.useEffect)(() => {
|
|
15828
|
-
if (!open || !position || !onPositionChange) return;
|
|
15829
|
-
const next = clampPosition(position, parentScroll, measured.w, measured.h);
|
|
15830
|
-
if (next.x !== position.x || next.y !== position.y) onPositionChange(next);
|
|
15831
|
-
}, [open, parentScroll, measured.w, measured.h, position, onPositionChange]);
|
|
15832
15965
|
const onHeaderPointerDown = (0, import_react15.useCallback)(
|
|
15833
15966
|
(e) => {
|
|
15834
15967
|
if (e.button !== 0) return;
|
|
@@ -15862,18 +15995,17 @@ function FloatingPanel({
|
|
|
15862
15995
|
return;
|
|
15863
15996
|
}
|
|
15864
15997
|
e.preventDefault();
|
|
15865
|
-
const next =
|
|
15998
|
+
const next = clampDragPosition(
|
|
15866
15999
|
{
|
|
15867
16000
|
x: drag.originX + (e.clientX - drag.startX),
|
|
15868
16001
|
y: drag.originY + (e.clientY - drag.startY)
|
|
15869
16002
|
},
|
|
15870
|
-
|
|
15871
|
-
measured.w
|
|
15872
|
-
measured.h
|
|
16003
|
+
liveScroll,
|
|
16004
|
+
measured.w
|
|
15873
16005
|
);
|
|
15874
16006
|
onPositionChange?.(next);
|
|
15875
16007
|
},
|
|
15876
|
-
[measured.
|
|
16008
|
+
[measured.w, onPositionChange, liveScroll]
|
|
15877
16009
|
);
|
|
15878
16010
|
const endDrag = (0, import_react15.useCallback)((e) => {
|
|
15879
16011
|
const drag = dragRef.current;
|
|
@@ -15903,7 +16035,7 @@ function FloatingPanel({
|
|
|
15903
16035
|
"fixed z-[2147483647] flex w-64 flex-col overflow-hidden rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
|
|
15904
16036
|
className
|
|
15905
16037
|
),
|
|
15906
|
-
style: { left: clamped.x, top: clamped.y },
|
|
16038
|
+
style: { left: clamped.x, top: clamped.y, maxHeight },
|
|
15907
16039
|
onMouseDown: (e) => e.stopPropagation(),
|
|
15908
16040
|
onPointerDown: (e) => e.stopPropagation(),
|
|
15909
16041
|
onClick: (e) => e.stopPropagation(),
|
|
@@ -15912,7 +16044,7 @@ function FloatingPanel({
|
|
|
15912
16044
|
"div",
|
|
15913
16045
|
{
|
|
15914
16046
|
"data-ohw-floating-panel-header": "",
|
|
15915
|
-
className: "relative flex cursor-grab items-start gap-2 border-b border-border py-
|
|
16047
|
+
className: "relative flex shrink-0 cursor-grab items-start gap-2 border-b border-border py-4! pl-5! pr-11! active:cursor-grabbing",
|
|
15916
16048
|
onPointerDown: onHeaderPointerDown,
|
|
15917
16049
|
onPointerMove: onHeaderPointerMove,
|
|
15918
16050
|
onPointerUp: endDrag,
|
|
@@ -15947,7 +16079,11 @@ function FloatingPanel({
|
|
|
15947
16079
|
"div",
|
|
15948
16080
|
{
|
|
15949
16081
|
"data-ohw-floating-panel-body": "",
|
|
15950
|
-
className: cn(
|
|
16082
|
+
className: cn(
|
|
16083
|
+
"flex min-h-0 w-full flex-1 flex-col gap-4 overflow-y-auto overscroll-contain p-4",
|
|
16084
|
+
bodyClassName
|
|
16085
|
+
),
|
|
16086
|
+
style: { WebkitOverflowScrolling: "touch" },
|
|
15951
16087
|
children
|
|
15952
16088
|
}
|
|
15953
16089
|
)
|
|
@@ -16025,198 +16161,1632 @@ function SocialsDisplayPanel({ display, onChange, className }) {
|
|
|
16025
16161
|
] });
|
|
16026
16162
|
}
|
|
16027
16163
|
|
|
16028
|
-
// src/
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16164
|
+
// src/ui/button-style-panel.tsx
|
|
16165
|
+
var import_lucide_react17 = require("lucide-react");
|
|
16166
|
+
|
|
16167
|
+
// src/lib/button-styles.ts
|
|
16168
|
+
var BUTTON_VARIANTS_KEY = "__ohw_button_variants";
|
|
16169
|
+
var BUTTON_SIZES_KEY = "__ohw_button_sizes";
|
|
16170
|
+
var BUTTON_ASSIGNMENTS_KEY = "__ohw_button_assignments";
|
|
16171
|
+
var BUTTON_VARIANT_IDS = ["primary", "secondary", "ghost"];
|
|
16172
|
+
var BUTTON_SIZE_IDS = ["s", "m", "l"];
|
|
16173
|
+
var TRANSPARENT = "rgba(0, 0, 0, 0)";
|
|
16174
|
+
var REFERENCE_SIZES = {
|
|
16175
|
+
s: { height: 40, paddingTop: 8, paddingRight: 16, paddingBottom: 8, paddingLeft: 16, fontSize: 15, borderRadius: 8, gap: 8 },
|
|
16176
|
+
m: { height: 48, paddingTop: 12, paddingRight: 24, paddingBottom: 12, paddingLeft: 24, fontSize: 15, borderRadius: 8, gap: 8 },
|
|
16177
|
+
l: { height: 56, paddingTop: 16, paddingRight: 32, paddingBottom: 16, paddingLeft: 32, fontSize: 15, borderRadius: 8, gap: 8 }
|
|
16178
|
+
};
|
|
16179
|
+
function buttonStyleContext(_el) {
|
|
16180
|
+
return "Button";
|
|
16181
|
+
}
|
|
16182
|
+
function previewSlotBackground(el) {
|
|
16183
|
+
let node = el.parentElement;
|
|
16184
|
+
while (node && node !== el.ownerDocument.documentElement) {
|
|
16185
|
+
if (node.closest("[data-ohw-bridge], [data-ohw-bridge-root]")) {
|
|
16186
|
+
node = node.parentElement;
|
|
16187
|
+
continue;
|
|
16188
|
+
}
|
|
16189
|
+
const bg = getComputedStyle(node).backgroundColor;
|
|
16190
|
+
const parsed = parseColor(bg);
|
|
16191
|
+
if (parsed && !isTransparent(parsed)) return bg;
|
|
16192
|
+
node = node.parentElement;
|
|
16193
|
+
}
|
|
16194
|
+
const root = el.ownerDocument.documentElement;
|
|
16195
|
+
const style = getComputedStyle(root);
|
|
16196
|
+
for (const name of ["--brand-surface", "--brand-background", "--ohw-brand-light", "--color-light"]) {
|
|
16197
|
+
const value = style.getPropertyValue(name).trim();
|
|
16198
|
+
if (value) return value;
|
|
16033
16199
|
}
|
|
16200
|
+
return "var(--brand-background, var(--ohw-brand-light, var(--color-light, #ffffff)))";
|
|
16034
16201
|
}
|
|
16035
|
-
function
|
|
16036
|
-
|
|
16037
|
-
|
|
16202
|
+
function buttonId(el) {
|
|
16203
|
+
if (!el) return null;
|
|
16204
|
+
const button = el.matches(CTA_BUTTON_SELECTOR) ? el : el.closest(CTA_BUTTON_SELECTOR);
|
|
16205
|
+
const id = button?.getAttribute("data-ohw-href-key")?.trim();
|
|
16206
|
+
return id || null;
|
|
16038
16207
|
}
|
|
16039
|
-
function
|
|
16040
|
-
|
|
16208
|
+
function isButtonVariantId(value) {
|
|
16209
|
+
return BUTTON_VARIANT_IDS.includes(value);
|
|
16041
16210
|
}
|
|
16042
|
-
function
|
|
16043
|
-
|
|
16044
|
-
document.documentElement.setAttribute("data-ohw-item-dragging", "");
|
|
16045
|
-
clearTextSelection();
|
|
16211
|
+
function isButtonSizeId(value) {
|
|
16212
|
+
return BUTTON_SIZE_IDS.includes(value);
|
|
16046
16213
|
}
|
|
16047
|
-
function
|
|
16048
|
-
const
|
|
16049
|
-
|
|
16050
|
-
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
16051
|
-
if (wasDragging) clearTextSelection();
|
|
16214
|
+
function px(value) {
|
|
16215
|
+
const rounded = Math.round(value * 100) / 100;
|
|
16216
|
+
return `${rounded}px`;
|
|
16052
16217
|
}
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
return listActiveNavbarItems(draggedEl).filter((el) => {
|
|
16060
|
-
const key = el.getAttribute("data-ohw-href-key");
|
|
16061
|
-
return isNavbarHrefKey(key) && !isNestedNavChild(el);
|
|
16062
|
-
});
|
|
16218
|
+
function parsePx(value, rootFont = 16) {
|
|
16219
|
+
if (!value) return 0;
|
|
16220
|
+
const n = parseFloat(value);
|
|
16221
|
+
if (!Number.isFinite(n)) return 0;
|
|
16222
|
+
if (value.trim().endsWith("rem") || value.trim().endsWith("em")) return n * rootFont;
|
|
16223
|
+
return n;
|
|
16063
16224
|
}
|
|
16064
|
-
function
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
const trigger = group.querySelector(":scope > [data-ohw-href-key]") ?? Array.from(group.querySelectorAll("[data-ohw-href-key]")).find(
|
|
16069
|
-
(el) => !el.closest("[data-ohw-nav-children]")
|
|
16070
|
-
) ?? null;
|
|
16071
|
-
const key = trigger?.getAttribute("data-ohw-href-key");
|
|
16072
|
-
return key && isNavbarHrefKey(key) ? key : null;
|
|
16225
|
+
function classifyHeight(height) {
|
|
16226
|
+
if (height < 44) return "s";
|
|
16227
|
+
if (height < 52) return "m";
|
|
16228
|
+
return "l";
|
|
16073
16229
|
}
|
|
16074
|
-
function
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
(
|
|
16083
|
-
|
|
16230
|
+
function scaleGeometry(geometry, scale = 0.75) {
|
|
16231
|
+
return {
|
|
16232
|
+
paddingTop: px(parsePx(geometry.paddingTop) * scale),
|
|
16233
|
+
paddingRight: px(parsePx(geometry.paddingRight) * scale),
|
|
16234
|
+
paddingBottom: px(parsePx(geometry.paddingBottom) * scale),
|
|
16235
|
+
paddingLeft: px(parsePx(geometry.paddingLeft) * scale),
|
|
16236
|
+
fontSize: px(parsePx(geometry.fontSize) * scale),
|
|
16237
|
+
borderRadius: px(parsePx(geometry.borderRadius) * scale),
|
|
16238
|
+
gap: px(parsePx(geometry.gap) * scale),
|
|
16239
|
+
height: Math.round(geometry.height * scale)
|
|
16240
|
+
};
|
|
16084
16241
|
}
|
|
16085
|
-
function
|
|
16086
|
-
const
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
const horizontalGap = b.left - a.right;
|
|
16092
|
-
return verticalGap > horizontalGap;
|
|
16093
|
-
}
|
|
16094
|
-
const container = getActiveNavbarListContainer(draggedEl);
|
|
16095
|
-
if (!container) return false;
|
|
16096
|
-
const style = window.getComputedStyle(container);
|
|
16097
|
-
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
16242
|
+
function relativeLuminance(color) {
|
|
16243
|
+
const channel = (value) => {
|
|
16244
|
+
const s = value / 255;
|
|
16245
|
+
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
16246
|
+
};
|
|
16247
|
+
return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);
|
|
16098
16248
|
}
|
|
16099
|
-
function
|
|
16100
|
-
const
|
|
16101
|
-
const
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
|
|
16110
|
-
|
|
16111
|
-
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
const
|
|
16118
|
-
|
|
16119
|
-
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
16130
|
-
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
}
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16249
|
+
function contrastRatio(a, b) {
|
|
16250
|
+
const lighter = Math.max(relativeLuminance(a), relativeLuminance(b));
|
|
16251
|
+
const darker = Math.min(relativeLuminance(a), relativeLuminance(b));
|
|
16252
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
16253
|
+
}
|
|
16254
|
+
function compositeOver(fg, bg) {
|
|
16255
|
+
const a = fg.a + bg.a * (1 - fg.a);
|
|
16256
|
+
if (a < 1e-3) return { ...bg, a: 0 };
|
|
16257
|
+
return {
|
|
16258
|
+
r: (fg.r * fg.a + bg.r * bg.a * (1 - fg.a)) / a,
|
|
16259
|
+
g: (fg.g * fg.a + bg.g * bg.a * (1 - fg.a)) / a,
|
|
16260
|
+
b: (fg.b * fg.a + bg.b * bg.a * (1 - fg.a)) / a,
|
|
16261
|
+
a
|
|
16262
|
+
};
|
|
16263
|
+
}
|
|
16264
|
+
function previewSlotForChrome(chrome, slotBackground) {
|
|
16265
|
+
const text = parseColor(chrome.color);
|
|
16266
|
+
if (!text || text.a < 0.2) return slotBackground;
|
|
16267
|
+
const slot = parseColor(slotBackground) ?? { r: 250, g: 250, b: 249, a: 1 };
|
|
16268
|
+
const fill = parseColor(chrome.background);
|
|
16269
|
+
const effective = fill && !isTransparent(fill) ? compositeOver(fill, slot) : slot;
|
|
16270
|
+
if (contrastRatio(text, effective) >= 3) return slotBackground;
|
|
16271
|
+
return relativeLuminance(text) > 0.55 ? "#2c2c2c" : "#f4f4f5";
|
|
16272
|
+
}
|
|
16273
|
+
function parseColor(input) {
|
|
16274
|
+
if (!input) return null;
|
|
16275
|
+
const value = input.trim().toLowerCase();
|
|
16276
|
+
if (value === "transparent") return { r: 0, g: 0, b: 0, a: 0 };
|
|
16277
|
+
const hex = value.match(/^#([0-9a-f]{3,8})$/);
|
|
16278
|
+
if (hex) {
|
|
16279
|
+
const raw = hex[1];
|
|
16280
|
+
const expand = (pair) => parseInt(pair.length === 1 ? pair + pair : pair, 16);
|
|
16281
|
+
if (raw.length === 3 || raw.length === 4) {
|
|
16282
|
+
return {
|
|
16283
|
+
r: expand(raw[0]),
|
|
16284
|
+
g: expand(raw[1]),
|
|
16285
|
+
b: expand(raw[2]),
|
|
16286
|
+
a: raw.length === 4 ? expand(raw[3]) / 255 : 1
|
|
16287
|
+
};
|
|
16288
|
+
}
|
|
16289
|
+
if (raw.length === 6 || raw.length === 8) {
|
|
16290
|
+
return {
|
|
16291
|
+
r: expand(raw.slice(0, 2)),
|
|
16292
|
+
g: expand(raw.slice(2, 4)),
|
|
16293
|
+
b: expand(raw.slice(4, 6)),
|
|
16294
|
+
a: raw.length === 8 ? expand(raw.slice(6, 8)) / 255 : 1
|
|
16295
|
+
};
|
|
16144
16296
|
}
|
|
16145
|
-
slots.push({
|
|
16146
|
-
insertIndex: i,
|
|
16147
|
-
parentId: null,
|
|
16148
|
-
left,
|
|
16149
|
-
top,
|
|
16150
|
-
width: Math.max(width, 40),
|
|
16151
|
-
height: barThickness,
|
|
16152
|
-
direction: "horizontal"
|
|
16153
|
-
});
|
|
16154
16297
|
}
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
|
|
16160
|
-
|
|
16161
|
-
|
|
16162
|
-
if (!container) return slots;
|
|
16163
|
-
const rect = container.getBoundingClientRect();
|
|
16164
|
-
slots.push({
|
|
16165
|
-
insertIndex: 0,
|
|
16166
|
-
parentId: null,
|
|
16167
|
-
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
16168
|
-
top: rect.top,
|
|
16169
|
-
width: barThickness,
|
|
16170
|
-
height: Math.max(rect.height, 24),
|
|
16171
|
-
direction: "vertical"
|
|
16172
|
-
});
|
|
16173
|
-
return slots;
|
|
16298
|
+
const rgb = value.match(
|
|
16299
|
+
/^rgba?\(\s*([\d.]+)[%\s,]+([\d.]+)[%\s,]+([\d.]+)(?:%?\s*[,/]\s*([\d.]+%?))?\s*\)$/
|
|
16300
|
+
);
|
|
16301
|
+
if (rgb) {
|
|
16302
|
+
const alphaRaw = rgb[4];
|
|
16303
|
+
const alpha = alphaRaw == null ? 1 : alphaRaw.endsWith("%") ? parseFloat(alphaRaw) / 100 : parseFloat(alphaRaw);
|
|
16304
|
+
return { r: Number(rgb[1]), g: Number(rgb[2]), b: Number(rgb[3]), a: alpha };
|
|
16174
16305
|
}
|
|
16175
|
-
const
|
|
16176
|
-
|
|
16177
|
-
|
|
16178
|
-
|
|
16179
|
-
|
|
16180
|
-
|
|
16181
|
-
|
|
16182
|
-
|
|
16183
|
-
|
|
16184
|
-
|
|
16185
|
-
if (i === 0) {
|
|
16186
|
-
const first = items[0].getBoundingClientRect();
|
|
16187
|
-
left = first.left - edgeGap / 2 - barThickness / 2;
|
|
16188
|
-
top = first.top;
|
|
16189
|
-
height = first.height;
|
|
16190
|
-
} else if (i === items.length) {
|
|
16191
|
-
const last = items[items.length - 1].getBoundingClientRect();
|
|
16192
|
-
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
16193
|
-
left = last.right + lastGap / 2 - barThickness / 2;
|
|
16194
|
-
top = last.top;
|
|
16195
|
-
height = last.height;
|
|
16196
|
-
} else {
|
|
16197
|
-
const prev = items[i - 1].getBoundingClientRect();
|
|
16198
|
-
const next = items[i].getBoundingClientRect();
|
|
16199
|
-
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
16200
|
-
top = Math.min(prev.top, next.top);
|
|
16201
|
-
height = Math.max(prev.bottom, next.bottom) - top;
|
|
16202
|
-
}
|
|
16203
|
-
slots.push({
|
|
16204
|
-
insertIndex: i,
|
|
16205
|
-
parentId: null,
|
|
16206
|
-
left,
|
|
16207
|
-
top,
|
|
16208
|
-
width: barThickness,
|
|
16209
|
-
height: Math.max(height, 24),
|
|
16210
|
-
direction: "vertical"
|
|
16211
|
-
});
|
|
16306
|
+
const oklch = value.match(
|
|
16307
|
+
/^oklch\(\s*([\d.]+%?)\s+([\d.]+)\s+([\d.]+)(?:deg)?(?:\s*\/\s*([\d.]+%?))?\s*\)$/
|
|
16308
|
+
);
|
|
16309
|
+
if (oklch) {
|
|
16310
|
+
const Lraw = oklch[1];
|
|
16311
|
+
const L = Lraw.endsWith("%") ? parseFloat(Lraw) / 100 : parseFloat(Lraw);
|
|
16312
|
+
const gray = Math.max(0, Math.min(1, L)) * 255;
|
|
16313
|
+
const alphaRaw = oklch[4];
|
|
16314
|
+
const alpha = alphaRaw == null ? 1 : alphaRaw.endsWith("%") ? parseFloat(alphaRaw) / 100 : parseFloat(alphaRaw);
|
|
16315
|
+
return { r: gray, g: gray, b: gray, a: alpha };
|
|
16212
16316
|
}
|
|
16213
|
-
return
|
|
16317
|
+
return null;
|
|
16214
16318
|
}
|
|
16215
|
-
function
|
|
16216
|
-
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16319
|
+
function isTransparent(color) {
|
|
16320
|
+
return !color || color.a < 0.05;
|
|
16321
|
+
}
|
|
16322
|
+
function hasOpaqueBackground(background) {
|
|
16323
|
+
if (!background) return false;
|
|
16324
|
+
const value = background.trim().toLowerCase();
|
|
16325
|
+
if (!value || value === "transparent" || value === "rgba(0, 0, 0, 0)" || value === "rgb(0, 0, 0, 0)") {
|
|
16326
|
+
return false;
|
|
16327
|
+
}
|
|
16328
|
+
const parsed = parseColor(background);
|
|
16329
|
+
if (parsed) return !isTransparent(parsed);
|
|
16330
|
+
return true;
|
|
16331
|
+
}
|
|
16332
|
+
function toCss(color) {
|
|
16333
|
+
const r2 = Math.round(color.r);
|
|
16334
|
+
const g = Math.round(color.g);
|
|
16335
|
+
const b = Math.round(color.b);
|
|
16336
|
+
if (color.a >= 0.995) return `rgb(${r2}, ${g}, ${b})`;
|
|
16337
|
+
return `rgba(${r2}, ${g}, ${b}, ${Math.round(color.a * 100) / 100})`;
|
|
16338
|
+
}
|
|
16339
|
+
function colorKey(input) {
|
|
16340
|
+
const parsed = parseColor(input);
|
|
16341
|
+
if (!parsed || isTransparent(parsed)) return "transparent";
|
|
16342
|
+
return `${Math.round(parsed.r / 8)}-${Math.round(parsed.g / 8)}-${Math.round(parsed.b / 8)}-${Math.round(parsed.a * 4)}`;
|
|
16343
|
+
}
|
|
16344
|
+
function declaredVariant(className) {
|
|
16345
|
+
const match = className.match(/\bbtn--(primary|secondary|ghost)\b/);
|
|
16346
|
+
return match && isButtonVariantId(match[1]) ? match[1] : null;
|
|
16347
|
+
}
|
|
16348
|
+
function fillSlot(sample) {
|
|
16349
|
+
const width = parseFloat(sample.borderWidth);
|
|
16350
|
+
const border = parseColor(sample.borderColor);
|
|
16351
|
+
if (width > 0 && !isTransparent(border)) return "secondary";
|
|
16352
|
+
if (hasOpaqueBackground(sample.background)) return "primary";
|
|
16353
|
+
return "ghost";
|
|
16354
|
+
}
|
|
16355
|
+
function sampleSlot(sample) {
|
|
16356
|
+
return declaredVariant(sample.className) ?? fillSlot(sample);
|
|
16357
|
+
}
|
|
16358
|
+
function fingerprint(sample) {
|
|
16359
|
+
const width = parseFloat(sample.borderWidth);
|
|
16360
|
+
const border = width > 0 ? colorKey(sample.borderColor) : "none";
|
|
16361
|
+
return `${colorKey(sample.background)}|${border}|${colorKey(sample.color)}|${sampleSlot(sample)}`;
|
|
16362
|
+
}
|
|
16363
|
+
function paintColor(chrome) {
|
|
16364
|
+
if (hasOpaqueBackground(chrome.background)) {
|
|
16365
|
+
const parsed = parseColor(chrome.background);
|
|
16366
|
+
return parsed ? toCss({ ...parsed, a: 1 }) : chrome.background;
|
|
16367
|
+
}
|
|
16368
|
+
const width = parseFloat(chrome.borderWidth);
|
|
16369
|
+
if (width > 0 && hasOpaqueBackground(chrome.borderColor)) {
|
|
16370
|
+
const parsed = parseColor(chrome.borderColor);
|
|
16371
|
+
return parsed ? toCss({ ...parsed, a: 1 }) : chrome.borderColor;
|
|
16372
|
+
}
|
|
16373
|
+
const text = parseColor(chrome.color);
|
|
16374
|
+
return text ? toCss({ ...text, a: 1 }) : chrome.color;
|
|
16375
|
+
}
|
|
16376
|
+
function accentColor(chrome) {
|
|
16377
|
+
const bg = parseColor(chrome.background);
|
|
16378
|
+
if (bg && !isTransparent(bg) && relativeLuminance(bg) < 0.55) {
|
|
16379
|
+
return toCss({ ...bg, a: 1 });
|
|
16380
|
+
}
|
|
16381
|
+
const text = parseColor(chrome.color);
|
|
16382
|
+
if (text && !isTransparent(text)) return toCss({ ...text, a: 1 });
|
|
16383
|
+
return paintColor(chrome);
|
|
16384
|
+
}
|
|
16385
|
+
function chromeFrom(sample) {
|
|
16386
|
+
return {
|
|
16387
|
+
background: sample.background || TRANSPARENT,
|
|
16388
|
+
color: sample.color || "currentColor",
|
|
16389
|
+
borderColor: sample.borderColor || TRANSPARENT,
|
|
16390
|
+
borderWidth: sample.borderWidth || "0px"
|
|
16391
|
+
};
|
|
16392
|
+
}
|
|
16393
|
+
function filledPrimary(seed) {
|
|
16394
|
+
const paint = parseColor(paintColor(seed)) ?? { r: 15, g: 15, b: 15, a: 1 };
|
|
16395
|
+
const luminance = relativeLuminance(paint);
|
|
16396
|
+
return {
|
|
16397
|
+
background: toCss({ ...paint, a: 1 }),
|
|
16398
|
+
color: luminance > 0.55 ? "rgb(15, 15, 15)" : "rgb(255, 255, 255)",
|
|
16399
|
+
borderColor: TRANSPARENT,
|
|
16400
|
+
borderWidth: "0px"
|
|
16401
|
+
};
|
|
16402
|
+
}
|
|
16403
|
+
function generatedSecondary(primary) {
|
|
16404
|
+
const paint = accentColor(primary);
|
|
16405
|
+
return {
|
|
16406
|
+
background: TRANSPARENT,
|
|
16407
|
+
color: paint,
|
|
16408
|
+
borderColor: paint,
|
|
16409
|
+
borderWidth: "1px"
|
|
16410
|
+
};
|
|
16411
|
+
}
|
|
16412
|
+
function generatedGhost(primary) {
|
|
16413
|
+
return {
|
|
16414
|
+
background: TRANSPARENT,
|
|
16415
|
+
color: accentColor(primary),
|
|
16416
|
+
borderColor: TRANSPARENT,
|
|
16417
|
+
borderWidth: "0px"
|
|
16418
|
+
};
|
|
16419
|
+
}
|
|
16420
|
+
function normalizeOutlineChrome(outline, primary) {
|
|
16421
|
+
const paint = accentColor(primary);
|
|
16422
|
+
const text = parseColor(outline.color);
|
|
16423
|
+
const paintRgb = parseColor(paint);
|
|
16424
|
+
const primaryLabel = parseColor(primary.color);
|
|
16425
|
+
const matchesOnPrimary = Boolean(text && primaryLabel) && colorKey(outline.color) === colorKey(primary.color);
|
|
16426
|
+
const textTooLight = text ? relativeLuminance(text) > 0.7 : false;
|
|
16427
|
+
const paintIsDarker = paintRgb ? relativeLuminance(paintRgb) < 0.65 : hasOpaqueBackground(primary.background);
|
|
16428
|
+
if (!(matchesOnPrimary || textTooLight) || !paintIsDarker) return outline;
|
|
16429
|
+
const hasBorder = parseFloat(outline.borderWidth) > 0;
|
|
16430
|
+
return {
|
|
16431
|
+
...outline,
|
|
16432
|
+
color: paint,
|
|
16433
|
+
borderColor: hasBorder ? paint : outline.borderColor
|
|
16434
|
+
};
|
|
16435
|
+
}
|
|
16436
|
+
function generateButtonVariants(samples) {
|
|
16437
|
+
if (samples.length === 0) return { status: "unresolved" };
|
|
16438
|
+
const groups = /* @__PURE__ */ new Map();
|
|
16439
|
+
for (const sample of samples) {
|
|
16440
|
+
const key = fingerprint(sample);
|
|
16441
|
+
const list = groups.get(key) ?? [];
|
|
16442
|
+
list.push(sample);
|
|
16443
|
+
groups.set(key, list);
|
|
16444
|
+
}
|
|
16445
|
+
if (groups.size > 3) return { status: "unresolved" };
|
|
16446
|
+
const bySlot = /* @__PURE__ */ new Map();
|
|
16447
|
+
for (const group of groups.values()) {
|
|
16448
|
+
const sample = group[0];
|
|
16449
|
+
const slot = sampleSlot(sample);
|
|
16450
|
+
if (bySlot.has(slot)) return { status: "unresolved" };
|
|
16451
|
+
bySlot.set(slot, sample);
|
|
16452
|
+
}
|
|
16453
|
+
const primarySample = bySlot.get("primary");
|
|
16454
|
+
const seed = chromeFrom(primarySample ?? samples[0]);
|
|
16455
|
+
const primary = primarySample ? seed : filledPrimary(seed);
|
|
16456
|
+
const secondary = normalizeOutlineChrome(
|
|
16457
|
+
bySlot.has("secondary") ? chromeFrom(bySlot.get("secondary")) : generatedSecondary(primary),
|
|
16458
|
+
primary
|
|
16459
|
+
);
|
|
16460
|
+
const ghost = normalizeOutlineChrome(
|
|
16461
|
+
bySlot.has("ghost") ? chromeFrom(bySlot.get("ghost")) : generatedGhost(primary),
|
|
16462
|
+
primary
|
|
16463
|
+
);
|
|
16464
|
+
return {
|
|
16465
|
+
status: "ready",
|
|
16466
|
+
tokens: { primary, secondary, ghost }
|
|
16467
|
+
};
|
|
16468
|
+
}
|
|
16469
|
+
function geometryFromSample(sample) {
|
|
16470
|
+
return {
|
|
16471
|
+
paddingTop: px(sample.paddingTop),
|
|
16472
|
+
paddingRight: px(sample.paddingRight),
|
|
16473
|
+
paddingBottom: px(sample.paddingBottom),
|
|
16474
|
+
paddingLeft: px(sample.paddingLeft),
|
|
16475
|
+
fontSize: px(sample.fontSize),
|
|
16476
|
+
borderRadius: px(sample.borderRadius),
|
|
16477
|
+
gap: px(sample.gap),
|
|
16478
|
+
height: Math.round(sample.height)
|
|
16479
|
+
};
|
|
16480
|
+
}
|
|
16481
|
+
function shiftSample(base, steps) {
|
|
16482
|
+
return {
|
|
16483
|
+
height: Math.max(24, base.height + steps * 8),
|
|
16484
|
+
paddingTop: Math.max(0, base.paddingTop + steps * 4),
|
|
16485
|
+
paddingBottom: Math.max(0, base.paddingBottom + steps * 4),
|
|
16486
|
+
paddingLeft: Math.max(0, base.paddingLeft + steps * 8),
|
|
16487
|
+
paddingRight: Math.max(0, base.paddingRight + steps * 8),
|
|
16488
|
+
fontSize: base.fontSize,
|
|
16489
|
+
borderRadius: base.borderRadius,
|
|
16490
|
+
gap: base.gap
|
|
16491
|
+
};
|
|
16492
|
+
}
|
|
16493
|
+
function clusterSizes(samples) {
|
|
16494
|
+
const sorted = [...samples].sort((a, b) => a.height - b.height);
|
|
16495
|
+
const clusters = [];
|
|
16496
|
+
for (const sample of sorted) {
|
|
16497
|
+
const current = clusters[clusters.length - 1];
|
|
16498
|
+
const head = current?.[0];
|
|
16499
|
+
if (!current || !head || Math.abs(sample.height - head.height) > 2) clusters.push([sample]);
|
|
16500
|
+
else current.push(sample);
|
|
16501
|
+
}
|
|
16502
|
+
return clusters.map((group) => {
|
|
16503
|
+
const pick = (key) => group.reduce((sum, item) => sum + item[key], 0) / group.length;
|
|
16504
|
+
return {
|
|
16505
|
+
height: pick("height"),
|
|
16506
|
+
paddingTop: pick("paddingTop"),
|
|
16507
|
+
paddingRight: pick("paddingRight"),
|
|
16508
|
+
paddingBottom: pick("paddingBottom"),
|
|
16509
|
+
paddingLeft: pick("paddingLeft"),
|
|
16510
|
+
fontSize: pick("fontSize"),
|
|
16511
|
+
borderRadius: pick("borderRadius"),
|
|
16512
|
+
gap: pick("gap")
|
|
16513
|
+
};
|
|
16514
|
+
});
|
|
16515
|
+
}
|
|
16516
|
+
function tokensFromSamples(bySlot, radius, gap) {
|
|
16517
|
+
const fill = (id) => {
|
|
16518
|
+
const sample = bySlot[id] ?? REFERENCE_SIZES[id];
|
|
16519
|
+
return geometryFromSample({ ...sample, borderRadius: radius, gap });
|
|
16520
|
+
};
|
|
16521
|
+
return { s: fill("s"), m: fill("m"), l: fill("l") };
|
|
16522
|
+
}
|
|
16523
|
+
function interpolateSizes(known) {
|
|
16524
|
+
const order = BUTTON_SIZE_IDS;
|
|
16525
|
+
const indexOf = (id) => order.indexOf(id);
|
|
16526
|
+
const sorted = [...known].sort((a, b) => indexOf(a.id) - indexOf(b.id));
|
|
16527
|
+
const left = sorted[0];
|
|
16528
|
+
const right = sorted[1];
|
|
16529
|
+
const span = indexOf(right.id) - indexOf(left.id);
|
|
16530
|
+
const step = (key) => (right.sample[key] - left.sample[key]) / span;
|
|
16531
|
+
const at = (index) => {
|
|
16532
|
+
const steps = index - indexOf(left.id);
|
|
16533
|
+
return {
|
|
16534
|
+
height: left.sample.height + step("height") * steps,
|
|
16535
|
+
paddingTop: Math.max(0, left.sample.paddingTop + step("paddingTop") * steps),
|
|
16536
|
+
paddingBottom: Math.max(0, left.sample.paddingBottom + step("paddingBottom") * steps),
|
|
16537
|
+
paddingLeft: Math.max(0, left.sample.paddingLeft + step("paddingLeft") * steps),
|
|
16538
|
+
paddingRight: Math.max(0, left.sample.paddingRight + step("paddingRight") * steps),
|
|
16539
|
+
fontSize: Math.max(10, left.sample.fontSize + step("fontSize") * steps),
|
|
16540
|
+
borderRadius: left.sample.borderRadius,
|
|
16541
|
+
gap: left.sample.gap
|
|
16542
|
+
};
|
|
16543
|
+
};
|
|
16544
|
+
const bySlot = {
|
|
16545
|
+
[left.id]: left.sample,
|
|
16546
|
+
[right.id]: { ...right.sample, borderRadius: left.sample.borderRadius, gap: left.sample.gap }
|
|
16547
|
+
};
|
|
16548
|
+
for (const id of order) {
|
|
16549
|
+
if (!bySlot[id]) bySlot[id] = at(indexOf(id));
|
|
16550
|
+
}
|
|
16551
|
+
return tokensFromSamples(bySlot, left.sample.borderRadius, left.sample.gap);
|
|
16552
|
+
}
|
|
16553
|
+
function generateButtonSizes(samples) {
|
|
16554
|
+
const clusters = clusterSizes(samples.filter((sample) => sample.height > 0));
|
|
16555
|
+
if (clusters.length === 0) {
|
|
16556
|
+
return { status: "ready", tokens: tokensFromSamples(REFERENCE_SIZES, 8, 8) };
|
|
16557
|
+
}
|
|
16558
|
+
if (clusters.length > 3) return { status: "unresolved" };
|
|
16559
|
+
if (clusters.length === 3) {
|
|
16560
|
+
const sorted = [...clusters].sort((a, b) => a.height - b.height);
|
|
16561
|
+
const radius = sorted[1].borderRadius;
|
|
16562
|
+
const gap = sorted[1].gap;
|
|
16563
|
+
return {
|
|
16564
|
+
status: "ready",
|
|
16565
|
+
tokens: {
|
|
16566
|
+
s: geometryFromSample({ ...sorted[0], borderRadius: radius, gap }),
|
|
16567
|
+
m: geometryFromSample({ ...sorted[1], borderRadius: radius, gap }),
|
|
16568
|
+
l: geometryFromSample({ ...sorted[2], borderRadius: radius, gap })
|
|
16569
|
+
}
|
|
16570
|
+
};
|
|
16571
|
+
}
|
|
16572
|
+
if (clusters.length === 1) {
|
|
16573
|
+
const known = clusters[0];
|
|
16574
|
+
const slot = classifyHeight(known.height);
|
|
16575
|
+
const offset = BUTTON_SIZE_IDS.indexOf(slot);
|
|
16576
|
+
const bySlot = Object.fromEntries(
|
|
16577
|
+
BUTTON_SIZE_IDS.map((id, index) => [id, shiftSample(known, index - offset)])
|
|
16578
|
+
);
|
|
16579
|
+
bySlot[slot] = known;
|
|
16580
|
+
return { status: "ready", tokens: tokensFromSamples(bySlot, known.borderRadius, known.gap) };
|
|
16581
|
+
}
|
|
16582
|
+
const mapped = clusters.map((sample) => ({ id: classifyHeight(sample.height), sample }));
|
|
16583
|
+
if (mapped[0].id === mapped[1].id) {
|
|
16584
|
+
const larger = clusters.slice().sort((a, b) => b.height - a.height)[0];
|
|
16585
|
+
return generateButtonSizes([larger]);
|
|
16586
|
+
}
|
|
16587
|
+
return { status: "ready", tokens: interpolateSizes(mapped) };
|
|
16588
|
+
}
|
|
16589
|
+
function parseJson(raw) {
|
|
16590
|
+
if (!raw) return null;
|
|
16591
|
+
try {
|
|
16592
|
+
return JSON.parse(raw);
|
|
16593
|
+
} catch {
|
|
16594
|
+
return null;
|
|
16595
|
+
}
|
|
16596
|
+
}
|
|
16597
|
+
function isChrome(value) {
|
|
16598
|
+
if (!value || typeof value !== "object") return false;
|
|
16599
|
+
const chrome = value;
|
|
16600
|
+
return typeof chrome.background === "string" && typeof chrome.color === "string";
|
|
16601
|
+
}
|
|
16602
|
+
function isGeometry(value) {
|
|
16603
|
+
if (!value || typeof value !== "object") return false;
|
|
16604
|
+
const geometry = value;
|
|
16605
|
+
return typeof geometry.paddingTop === "string" && typeof geometry.height === "number";
|
|
16606
|
+
}
|
|
16607
|
+
function readVariantTokens(content) {
|
|
16608
|
+
const parsed = parseJson(content[BUTTON_VARIANTS_KEY]);
|
|
16609
|
+
if (!parsed) return null;
|
|
16610
|
+
if (!BUTTON_VARIANT_IDS.every((id) => isChrome(parsed[id]))) return null;
|
|
16611
|
+
return parsed;
|
|
16612
|
+
}
|
|
16613
|
+
function readSizeTokens(content) {
|
|
16614
|
+
const parsed = parseJson(content[BUTTON_SIZES_KEY]);
|
|
16615
|
+
if (!parsed) return null;
|
|
16616
|
+
if (!BUTTON_SIZE_IDS.every((id) => isGeometry(parsed[id]))) return null;
|
|
16617
|
+
return parsed;
|
|
16618
|
+
}
|
|
16619
|
+
function readAssignments(content) {
|
|
16620
|
+
const parsed = parseJson(content[BUTTON_ASSIGNMENTS_KEY]);
|
|
16621
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
16622
|
+
const next = {};
|
|
16623
|
+
for (const [id, value] of Object.entries(parsed)) {
|
|
16624
|
+
if (!value || !isButtonVariantId(value.variant) || !isButtonSizeId(value.size)) continue;
|
|
16625
|
+
next[id] = { variant: value.variant, size: value.size };
|
|
16626
|
+
}
|
|
16627
|
+
return next;
|
|
16628
|
+
}
|
|
16629
|
+
function cssLength(style, prop) {
|
|
16630
|
+
return style.getPropertyValue(prop) || "0px";
|
|
16631
|
+
}
|
|
16632
|
+
function readVariantSample(el) {
|
|
16633
|
+
const style = getComputedStyle(el);
|
|
16634
|
+
return {
|
|
16635
|
+
background: style.backgroundColor,
|
|
16636
|
+
color: style.color,
|
|
16637
|
+
borderColor: style.borderTopColor,
|
|
16638
|
+
borderWidth: style.borderTopWidth,
|
|
16639
|
+
className: el.className || ""
|
|
16640
|
+
};
|
|
16641
|
+
}
|
|
16642
|
+
function readSizeSample(el) {
|
|
16643
|
+
const style = getComputedStyle(el);
|
|
16644
|
+
const rootFont = parsePx(getComputedStyle(el.ownerDocument.documentElement).fontSize) || 16;
|
|
16645
|
+
const rect = el.getBoundingClientRect();
|
|
16646
|
+
return {
|
|
16647
|
+
height: rect.height,
|
|
16648
|
+
paddingTop: parsePx(cssLength(style, "padding-top"), rootFont),
|
|
16649
|
+
paddingRight: parsePx(cssLength(style, "padding-right"), rootFont),
|
|
16650
|
+
paddingBottom: parsePx(cssLength(style, "padding-bottom"), rootFont),
|
|
16651
|
+
paddingLeft: parsePx(cssLength(style, "padding-left"), rootFont),
|
|
16652
|
+
fontSize: parsePx(style.fontSize, rootFont),
|
|
16653
|
+
borderRadius: parsePx(style.borderTopLeftRadius, rootFont),
|
|
16654
|
+
gap: parsePx(style.columnGap || style.gap, rootFont)
|
|
16655
|
+
};
|
|
16656
|
+
}
|
|
16657
|
+
function readTypography(el) {
|
|
16658
|
+
const style = getComputedStyle(el);
|
|
16659
|
+
return {
|
|
16660
|
+
fontFamily: style.fontFamily,
|
|
16661
|
+
fontWeight: style.fontWeight,
|
|
16662
|
+
letterSpacing: style.letterSpacing,
|
|
16663
|
+
textTransform: style.textTransform,
|
|
16664
|
+
textDecoration: style.textDecorationLine || style.textDecoration || "none"
|
|
16665
|
+
};
|
|
16666
|
+
}
|
|
16667
|
+
var buttonOriginByEl = /* @__PURE__ */ new WeakMap();
|
|
16668
|
+
var ORIGIN_ATTR = "data-ohw-btn-origin";
|
|
16669
|
+
function parseOriginAttr(raw) {
|
|
16670
|
+
if (!raw) return null;
|
|
16671
|
+
try {
|
|
16672
|
+
const value = JSON.parse(raw);
|
|
16673
|
+
if (!value?.variant || !value.size || !value.typography) return null;
|
|
16674
|
+
return value;
|
|
16675
|
+
} catch {
|
|
16676
|
+
return null;
|
|
16677
|
+
}
|
|
16678
|
+
}
|
|
16679
|
+
function measureLiveOrigin(el) {
|
|
16680
|
+
return {
|
|
16681
|
+
variant: readVariantSample(el),
|
|
16682
|
+
size: readSizeSample(el),
|
|
16683
|
+
typography: readTypography(el)
|
|
16684
|
+
};
|
|
16685
|
+
}
|
|
16686
|
+
function captureButtonOrigin(el) {
|
|
16687
|
+
const cached = buttonOriginByEl.get(el);
|
|
16688
|
+
if (cached) return cached;
|
|
16689
|
+
const fromAttr = parseOriginAttr(el.getAttribute(ORIGIN_ATTR));
|
|
16690
|
+
if (fromAttr) {
|
|
16691
|
+
buttonOriginByEl.set(el, fromAttr);
|
|
16692
|
+
return fromAttr;
|
|
16693
|
+
}
|
|
16694
|
+
const origin = measureLiveOrigin(el);
|
|
16695
|
+
buttonOriginByEl.set(el, origin);
|
|
16696
|
+
try {
|
|
16697
|
+
el.setAttribute(ORIGIN_ATTR, JSON.stringify(origin));
|
|
16698
|
+
} catch {
|
|
16699
|
+
}
|
|
16700
|
+
return origin;
|
|
16701
|
+
}
|
|
16702
|
+
function listStyleButtons(doc) {
|
|
16703
|
+
return Array.from(doc.querySelectorAll(CTA_BUTTON_SELECTOR)).filter((el) => {
|
|
16704
|
+
if (el.closest("[data-ohw-bridge], [data-ohw-bridge-root]")) return false;
|
|
16705
|
+
const rect = el.getBoundingClientRect();
|
|
16706
|
+
return rect.width > 0 && rect.height > 0;
|
|
16707
|
+
});
|
|
16708
|
+
}
|
|
16709
|
+
function generateTokensFromButtons(buttons) {
|
|
16710
|
+
const variants = generateButtonVariants(buttons.map(readVariantSample));
|
|
16711
|
+
const sizes = generateButtonSizes(buttons.map(readSizeSample));
|
|
16712
|
+
if (variants.status !== "ready" || sizes.status !== "ready") return { status: "unresolved" };
|
|
16713
|
+
return { status: "ready", tokens: { variants: variants.tokens, sizes: sizes.tokens } };
|
|
16714
|
+
}
|
|
16715
|
+
function tokensFromButton(el) {
|
|
16716
|
+
const origin = captureButtonOrigin(el);
|
|
16717
|
+
const sample = origin.variant;
|
|
16718
|
+
const variants = generateButtonVariants([sample]);
|
|
16719
|
+
const sizes = generateButtonSizes([origin.size]);
|
|
16720
|
+
const primary = chromeFrom(sample);
|
|
16721
|
+
return {
|
|
16722
|
+
variants: variants.status === "ready" ? variants.tokens : { primary, secondary: generatedSecondary(primary), ghost: generatedGhost(primary) },
|
|
16723
|
+
sizes: sizes.status === "ready" ? sizes.tokens : tokensFromSamples(REFERENCE_SIZES, 8, 8)
|
|
16724
|
+
};
|
|
16725
|
+
}
|
|
16726
|
+
function readStoredStyleTokens(content) {
|
|
16727
|
+
const variants = readVariantTokens(content);
|
|
16728
|
+
const sizes = readSizeTokens(content);
|
|
16729
|
+
if (!variants || !sizes) return null;
|
|
16730
|
+
return { variants, sizes };
|
|
16731
|
+
}
|
|
16732
|
+
function styleTokenNodes(tokens) {
|
|
16733
|
+
return [
|
|
16734
|
+
{ key: BUTTON_VARIANTS_KEY, text: JSON.stringify(tokens.variants) },
|
|
16735
|
+
{ key: BUTTON_SIZES_KEY, text: JSON.stringify(tokens.sizes) }
|
|
16736
|
+
];
|
|
16737
|
+
}
|
|
16738
|
+
function ensureButtonStyleTokens(doc, content) {
|
|
16739
|
+
const stored = readStoredStyleTokens(content);
|
|
16740
|
+
if (stored) return { tokens: stored, nodes: [] };
|
|
16741
|
+
const generated = generateTokensFromButtons(listStyleButtons(doc));
|
|
16742
|
+
if (generated.status !== "ready") return { tokens: null, nodes: [] };
|
|
16743
|
+
return { tokens: generated.tokens, nodes: styleTokenNodes(generated.tokens) };
|
|
16744
|
+
}
|
|
16745
|
+
function detectVariant(el, tokens) {
|
|
16746
|
+
const declared = declaredVariant(el.className || "");
|
|
16747
|
+
if (declared) return declared;
|
|
16748
|
+
const stamped = el.getAttribute("data-ohw-btn-variant");
|
|
16749
|
+
if (stamped && isButtonVariantId(stamped)) return stamped;
|
|
16750
|
+
const sample = readVariantSample(el);
|
|
16751
|
+
if (!tokens) return sampleSlot(sample);
|
|
16752
|
+
const key = fingerprint(sample);
|
|
16753
|
+
for (const id of BUTTON_VARIANT_IDS) {
|
|
16754
|
+
const chrome = tokens[id];
|
|
16755
|
+
const tokenKey = fingerprint({
|
|
16756
|
+
background: chrome.background,
|
|
16757
|
+
color: chrome.color,
|
|
16758
|
+
borderColor: chrome.borderColor,
|
|
16759
|
+
borderWidth: chrome.borderWidth,
|
|
16760
|
+
className: `btn btn--${id}`
|
|
16761
|
+
});
|
|
16762
|
+
if (tokenKey === key) return id;
|
|
16763
|
+
}
|
|
16764
|
+
return sampleSlot(sample);
|
|
16765
|
+
}
|
|
16766
|
+
function detectSize(el, tokens) {
|
|
16767
|
+
const stamped = el.getAttribute("data-ohw-btn-size");
|
|
16768
|
+
if (stamped && isButtonSizeId(stamped)) return stamped;
|
|
16769
|
+
const height = el.getBoundingClientRect().height;
|
|
16770
|
+
if (!tokens) return classifyHeight(height);
|
|
16771
|
+
let best = "m";
|
|
16772
|
+
let bestDelta = Number.POSITIVE_INFINITY;
|
|
16773
|
+
for (const id of BUTTON_SIZE_IDS) {
|
|
16774
|
+
const delta = Math.abs(tokens[id].height - height);
|
|
16775
|
+
if (delta < bestDelta) {
|
|
16776
|
+
best = id;
|
|
16777
|
+
bestDelta = delta;
|
|
16778
|
+
}
|
|
16779
|
+
}
|
|
16780
|
+
return best;
|
|
16781
|
+
}
|
|
16782
|
+
function assignmentFor(el, content, tokens) {
|
|
16783
|
+
const id = buttonId(el);
|
|
16784
|
+
const stored = id ? readAssignments(content)[id] : void 0;
|
|
16785
|
+
if (stored) return stored;
|
|
16786
|
+
return {
|
|
16787
|
+
variant: detectVariant(el, tokens?.variants ?? null),
|
|
16788
|
+
size: detectSize(el, tokens?.sizes ?? null)
|
|
16789
|
+
};
|
|
16790
|
+
}
|
|
16791
|
+
function labelElement(el) {
|
|
16792
|
+
return el.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') ?? (el.matches('[data-ohw-editable="text"], [data-ohw-editable="plain"]') ? el : null);
|
|
16793
|
+
}
|
|
16794
|
+
var paintLockByEl = /* @__PURE__ */ new WeakMap();
|
|
16795
|
+
var paintObserverByEl = /* @__PURE__ */ new WeakMap();
|
|
16796
|
+
var paintingButton = false;
|
|
16797
|
+
function paintButtonChrome(el, assignment, tokens) {
|
|
16798
|
+
const origin = captureButtonOrigin(el);
|
|
16799
|
+
const chrome = tokens.variants[assignment.variant];
|
|
16800
|
+
const originSlot = classifyHeight(origin.size.height);
|
|
16801
|
+
const geometry = assignment.size === originSlot ? geometryFromSample({ ...origin.size, borderRadius: origin.size.borderRadius, gap: origin.size.gap }) : tokens.sizes[assignment.size];
|
|
16802
|
+
const { typography } = origin;
|
|
16803
|
+
el.setAttribute("data-ohw-btn-variant", assignment.variant);
|
|
16804
|
+
el.setAttribute("data-ohw-btn-size", assignment.size);
|
|
16805
|
+
el.style.transition = "none";
|
|
16806
|
+
el.style.boxSizing = "border-box";
|
|
16807
|
+
el.style.display = "inline-flex";
|
|
16808
|
+
el.style.alignItems = "center";
|
|
16809
|
+
el.style.justifyContent = "center";
|
|
16810
|
+
el.style.background = chrome.background;
|
|
16811
|
+
el.style.color = chrome.color;
|
|
16812
|
+
el.style.borderStyle = parseFloat(chrome.borderWidth) > 0 ? "solid" : "none";
|
|
16813
|
+
el.style.borderColor = chrome.borderColor;
|
|
16814
|
+
el.style.borderWidth = chrome.borderWidth;
|
|
16815
|
+
el.style.padding = `${geometry.paddingTop} ${geometry.paddingRight} ${geometry.paddingBottom} ${geometry.paddingLeft}`;
|
|
16816
|
+
el.style.fontSize = geometry.fontSize;
|
|
16817
|
+
el.style.borderRadius = px(origin.size.borderRadius);
|
|
16818
|
+
el.style.gap = geometry.gap;
|
|
16819
|
+
el.style.height = px(geometry.height);
|
|
16820
|
+
el.style.fontFamily = typography.fontFamily;
|
|
16821
|
+
el.style.fontWeight = typography.fontWeight;
|
|
16822
|
+
el.style.letterSpacing = typography.letterSpacing;
|
|
16823
|
+
el.style.textTransform = typography.textTransform;
|
|
16824
|
+
if (typography.textDecoration && typography.textDecoration !== "none") {
|
|
16825
|
+
el.style.textDecoration = typography.textDecoration;
|
|
16826
|
+
} else {
|
|
16827
|
+
el.style.textDecoration = "none";
|
|
16828
|
+
}
|
|
16829
|
+
const label = labelElement(el);
|
|
16830
|
+
if (label && label !== el) label.style.color = chrome.color;
|
|
16831
|
+
}
|
|
16832
|
+
function guardTemplateHover(el) {
|
|
16833
|
+
if (paintObserverByEl.has(el)) return;
|
|
16834
|
+
const observer = new MutationObserver(() => {
|
|
16835
|
+
if (paintingButton) return;
|
|
16836
|
+
const lock = paintLockByEl.get(el);
|
|
16837
|
+
if (!lock) return;
|
|
16838
|
+
paintingButton = true;
|
|
16839
|
+
paintButtonChrome(el, lock.assignment, lock.tokens);
|
|
16840
|
+
paintingButton = false;
|
|
16841
|
+
});
|
|
16842
|
+
observer.observe(el, { attributes: true, attributeFilter: ["style", "class"] });
|
|
16843
|
+
paintObserverByEl.set(el, observer);
|
|
16844
|
+
}
|
|
16845
|
+
function applyButtonStyle(el, assignment, tokens) {
|
|
16846
|
+
paintLockByEl.set(el, { assignment, tokens });
|
|
16847
|
+
paintingButton = true;
|
|
16848
|
+
paintButtonChrome(el, assignment, tokens);
|
|
16849
|
+
paintingButton = false;
|
|
16850
|
+
guardTemplateHover(el);
|
|
16851
|
+
}
|
|
16852
|
+
function applyButtonStylesFromContent(doc, content) {
|
|
16853
|
+
const assignments = readAssignments(content);
|
|
16854
|
+
for (const [id, assignment] of Object.entries(assignments)) {
|
|
16855
|
+
const el = doc.querySelector(`[data-ohw-href-key="${CSS.escape(id)}"]`);
|
|
16856
|
+
if (!el) continue;
|
|
16857
|
+
applyButtonStyle(el, assignment, tokensFromButton(el));
|
|
16858
|
+
}
|
|
16859
|
+
}
|
|
16860
|
+
function withAssignment(content, id, assignment) {
|
|
16861
|
+
return { ...readAssignments(content), [id]: assignment };
|
|
16862
|
+
}
|
|
16863
|
+
|
|
16864
|
+
// src/ui/button-style-panel.tsx
|
|
16865
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
16866
|
+
var SIZE_LABEL = { s: "S", m: "M", l: "L" };
|
|
16867
|
+
function ButtonStylePanel({
|
|
16868
|
+
variants,
|
|
16869
|
+
sizes,
|
|
16870
|
+
variant,
|
|
16871
|
+
size,
|
|
16872
|
+
onVariant,
|
|
16873
|
+
onSize,
|
|
16874
|
+
previewLabel = "Book Now",
|
|
16875
|
+
slotBackground = "var(--brand-background, var(--ohw-brand-light, var(--color-light, #ffffff)))"
|
|
16876
|
+
}) {
|
|
16877
|
+
const preview = scaleGeometry(sizes.m, 0.75);
|
|
16878
|
+
const label = previewLabel.trim() || "Book Now";
|
|
16879
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex w-full flex-col gap-5", children: [
|
|
16880
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "flex w-full flex-col gap-2.5", children: [
|
|
16881
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-semibold uppercase leading-4 tracking-[0.6px] text-stone-500 font-sans", children: "Variants" }),
|
|
16882
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "flex w-full flex-col gap-2.5", children: BUTTON_VARIANT_IDS.map((id) => {
|
|
16883
|
+
const chrome = variants[id];
|
|
16884
|
+
const selected = id === variant;
|
|
16885
|
+
const hasBorder = parseFloat(chrome.borderWidth) > 0;
|
|
16886
|
+
const cardSlot = previewSlotForChrome(chrome, slotBackground);
|
|
16887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
16888
|
+
"button",
|
|
16889
|
+
{
|
|
16890
|
+
type: "button",
|
|
16891
|
+
"aria-pressed": selected,
|
|
16892
|
+
"aria-label": id,
|
|
16893
|
+
onMouseDown: (e) => {
|
|
16894
|
+
e.preventDefault();
|
|
16895
|
+
e.stopPropagation();
|
|
16896
|
+
},
|
|
16897
|
+
onClick: () => onVariant(id),
|
|
16898
|
+
className: cn(
|
|
16899
|
+
"relative w-full overflow-hidden rounded-xl border-solid text-left",
|
|
16900
|
+
selected ? "border-2 border-primary" : "border border-border"
|
|
16901
|
+
),
|
|
16902
|
+
children: [
|
|
16903
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
16904
|
+
"div",
|
|
16905
|
+
{
|
|
16906
|
+
className: "flex w-full items-center justify-center py-4",
|
|
16907
|
+
style: { background: cardSlot },
|
|
16908
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
16909
|
+
"span",
|
|
16910
|
+
{
|
|
16911
|
+
className: "inline-flex items-center justify-center whitespace-nowrap font-semibold uppercase leading-none",
|
|
16912
|
+
style: {
|
|
16913
|
+
background: chrome.background,
|
|
16914
|
+
color: chrome.color,
|
|
16915
|
+
borderColor: chrome.borderColor,
|
|
16916
|
+
borderWidth: hasBorder ? chrome.borderWidth : "0px",
|
|
16917
|
+
borderStyle: hasBorder ? "solid" : "none",
|
|
16918
|
+
padding: `${preview.paddingTop} ${preview.paddingRight} ${preview.paddingBottom} ${preview.paddingLeft}`,
|
|
16919
|
+
fontSize: preview.fontSize,
|
|
16920
|
+
borderRadius: preview.borderRadius,
|
|
16921
|
+
height: preview.height,
|
|
16922
|
+
boxSizing: "border-box",
|
|
16923
|
+
letterSpacing: "0.12em"
|
|
16924
|
+
},
|
|
16925
|
+
children: label
|
|
16926
|
+
}
|
|
16927
|
+
)
|
|
16928
|
+
}
|
|
16929
|
+
),
|
|
16930
|
+
selected ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
16931
|
+
"span",
|
|
16932
|
+
{
|
|
16933
|
+
className: "absolute right-0.5 top-0.5 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground",
|
|
16934
|
+
"aria-hidden": true,
|
|
16935
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lucide_react17.Check, { className: "size-3", strokeWidth: 3 })
|
|
16936
|
+
}
|
|
16937
|
+
) : null
|
|
16938
|
+
]
|
|
16939
|
+
},
|
|
16940
|
+
id
|
|
16941
|
+
);
|
|
16942
|
+
}) })
|
|
16943
|
+
] }),
|
|
16944
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("section", { className: "flex w-full flex-col gap-2.5", children: [
|
|
16945
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("h3", { className: "text-xs font-semibold uppercase leading-4 tracking-[0.6px] text-stone-500 font-sans", children: "Size" }),
|
|
16946
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
16947
|
+
"div",
|
|
16948
|
+
{
|
|
16949
|
+
className: "flex w-full items-start rounded-lg bg-stone-100 p-1",
|
|
16950
|
+
role: "radiogroup",
|
|
16951
|
+
"aria-label": "Size",
|
|
16952
|
+
children: BUTTON_SIZE_IDS.map((id) => {
|
|
16953
|
+
const selected = id === size;
|
|
16954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
16955
|
+
"button",
|
|
16956
|
+
{
|
|
16957
|
+
type: "button",
|
|
16958
|
+
role: "radio",
|
|
16959
|
+
"aria-checked": selected,
|
|
16960
|
+
onMouseDown: (e) => {
|
|
16961
|
+
e.preventDefault();
|
|
16962
|
+
e.stopPropagation();
|
|
16963
|
+
},
|
|
16964
|
+
onClick: () => onSize(id),
|
|
16965
|
+
className: cn(
|
|
16966
|
+
"flex min-w-14 flex-1 items-center justify-center rounded-md px-3 py-1.5 text-sm font-medium leading-5",
|
|
16967
|
+
selected ? "bg-white text-stone-950 shadow-sm" : "bg-transparent text-stone-500"
|
|
16968
|
+
),
|
|
16969
|
+
children: SIZE_LABEL[id]
|
|
16970
|
+
},
|
|
16971
|
+
id
|
|
16972
|
+
);
|
|
16973
|
+
})
|
|
16974
|
+
}
|
|
16975
|
+
)
|
|
16976
|
+
] })
|
|
16977
|
+
] });
|
|
16978
|
+
}
|
|
16979
|
+
|
|
16980
|
+
// src/lib/button-collections.ts
|
|
16981
|
+
var BUTTON_COLLECTIONS_KEY = "__ohw_button_collections";
|
|
16982
|
+
var BUTTON_SNAPSHOTS_KEY = "__ohw_button_snapshots";
|
|
16983
|
+
var BUTTON_HIDDEN_KEY = "__ohw_button_hidden";
|
|
16984
|
+
var COLLECTION_ATTR = "data-ohw-button-collection";
|
|
16985
|
+
function parseJson2(raw) {
|
|
16986
|
+
if (!raw) return null;
|
|
16987
|
+
try {
|
|
16988
|
+
return JSON.parse(raw);
|
|
16989
|
+
} catch {
|
|
16990
|
+
return null;
|
|
16991
|
+
}
|
|
16992
|
+
}
|
|
16993
|
+
function readCollections(content) {
|
|
16994
|
+
const parsed = parseJson2(content[BUTTON_COLLECTIONS_KEY]);
|
|
16995
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
16996
|
+
const next = {};
|
|
16997
|
+
for (const [id, value] of Object.entries(parsed)) {
|
|
16998
|
+
if (!value || !Array.isArray(value.members)) continue;
|
|
16999
|
+
next[id] = {
|
|
17000
|
+
id,
|
|
17001
|
+
members: value.members.filter((member) => typeof member === "string" && member),
|
|
17002
|
+
gap: typeof value.gap === "string" ? value.gap : "12px"
|
|
17003
|
+
};
|
|
17004
|
+
}
|
|
17005
|
+
return next;
|
|
17006
|
+
}
|
|
17007
|
+
function readSnapshots(content) {
|
|
17008
|
+
const parsed = parseJson2(content[BUTTON_SNAPSHOTS_KEY]);
|
|
17009
|
+
if (!parsed || typeof parsed !== "object") return {};
|
|
17010
|
+
const next = {};
|
|
17011
|
+
for (const [id, value] of Object.entries(parsed)) {
|
|
17012
|
+
if (!value || typeof value.html !== "string") continue;
|
|
17013
|
+
next[id] = value;
|
|
17014
|
+
}
|
|
17015
|
+
return next;
|
|
17016
|
+
}
|
|
17017
|
+
function readHiddenButtons(content) {
|
|
17018
|
+
const parsed = parseJson2(content[BUTTON_HIDDEN_KEY]);
|
|
17019
|
+
if (!Array.isArray(parsed)) return [];
|
|
17020
|
+
return parsed.filter((id) => typeof id === "string" && id);
|
|
17021
|
+
}
|
|
17022
|
+
function buttonCollectionOf(el) {
|
|
17023
|
+
return el?.closest(`[${COLLECTION_ATTR}]`) ?? null;
|
|
17024
|
+
}
|
|
17025
|
+
function isNavbarCta(el) {
|
|
17026
|
+
return el.getAttribute("data-ohw-role") === "navbar-button" || Boolean(el.closest('[data-ohw-role="navbar-button"]'));
|
|
17027
|
+
}
|
|
17028
|
+
function navbarScope(el) {
|
|
17029
|
+
return el.closest("nav, [data-ohw-nav-container], [data-ohw-nav-drawer]") ?? el.ownerDocument;
|
|
17030
|
+
}
|
|
17031
|
+
function isLastNavbarButton(el) {
|
|
17032
|
+
if (!isNavbarCta(el)) return false;
|
|
17033
|
+
const buttons = Array.from(navbarScope(el).querySelectorAll(CTA_BUTTON_SELECTOR)).filter(
|
|
17034
|
+
(button) => isNavbarCta(button) && buttonId(button)
|
|
17035
|
+
);
|
|
17036
|
+
return buttons.length <= 1;
|
|
17037
|
+
}
|
|
17038
|
+
function canDeleteButton(el) {
|
|
17039
|
+
return !isLastNavbarButton(el);
|
|
17040
|
+
}
|
|
17041
|
+
function canDuplicateButton(el) {
|
|
17042
|
+
return isNavbarCta(el);
|
|
17043
|
+
}
|
|
17044
|
+
function labelElement2(el) {
|
|
17045
|
+
return el.querySelector('[data-ohw-editable="text"], [data-ohw-editable="plain"]') ?? el.querySelector("[data-ohw-key]");
|
|
17046
|
+
}
|
|
17047
|
+
function buttonLabel(el) {
|
|
17048
|
+
return (labelElement2(el)?.textContent ?? el.textContent ?? "").trim();
|
|
17049
|
+
}
|
|
17050
|
+
function buttonHref(el) {
|
|
17051
|
+
return el.getAttribute("href") ?? "";
|
|
17052
|
+
}
|
|
17053
|
+
function hrefKeyBase(hrefKey) {
|
|
17054
|
+
return hrefKey.replace(/-href$/, "").replace(/-copy-\d+$/, "");
|
|
17055
|
+
}
|
|
17056
|
+
function labelKeyForHrefKey(hrefKey) {
|
|
17057
|
+
return `${hrefKey.replace(/-href$/, "")}-label`;
|
|
17058
|
+
}
|
|
17059
|
+
function cleanClone(el) {
|
|
17060
|
+
const copy = el.cloneNode(true);
|
|
17061
|
+
copy.querySelectorAll("[data-ohw-selected], [data-ohw-hovered], [data-ohw-editing]").forEach((node) => {
|
|
17062
|
+
node.removeAttribute("data-ohw-selected");
|
|
17063
|
+
node.removeAttribute("data-ohw-hovered");
|
|
17064
|
+
node.removeAttribute("data-ohw-editing");
|
|
17065
|
+
node.removeAttribute("contenteditable");
|
|
17066
|
+
});
|
|
17067
|
+
copy.removeAttribute("data-ohw-selected");
|
|
17068
|
+
copy.removeAttribute("data-ohw-hovered");
|
|
17069
|
+
copy.removeAttribute("data-ohw-editing");
|
|
17070
|
+
copy.removeAttribute("contenteditable");
|
|
17071
|
+
copy.removeAttribute("data-ohw-drag-disabled");
|
|
17072
|
+
return copy;
|
|
17073
|
+
}
|
|
17074
|
+
function nextCopyId(sourceId, content, doc) {
|
|
17075
|
+
const used = /* @__PURE__ */ new Set([
|
|
17076
|
+
...Object.keys(readSnapshots(content)),
|
|
17077
|
+
...Object.keys(readAssignments(content)),
|
|
17078
|
+
...Array.from(doc.querySelectorAll("[data-ohw-href-key]")).map(
|
|
17079
|
+
(el) => el.getAttribute("data-ohw-href-key") ?? ""
|
|
17080
|
+
)
|
|
17081
|
+
]);
|
|
17082
|
+
const base = hrefKeyBase(sourceId);
|
|
17083
|
+
let n = 2;
|
|
17084
|
+
while (used.has(`${base}-copy-${n}-href`)) n += 1;
|
|
17085
|
+
return `${base}-copy-${n}-href`;
|
|
17086
|
+
}
|
|
17087
|
+
function nextCollectionId(content, doc) {
|
|
17088
|
+
const used = /* @__PURE__ */ new Set([
|
|
17089
|
+
...Object.keys(readCollections(content)),
|
|
17090
|
+
...Array.from(doc.querySelectorAll(`[${COLLECTION_ATTR}]`)).map(
|
|
17091
|
+
(el) => el.getAttribute(COLLECTION_ATTR) ?? ""
|
|
17092
|
+
)
|
|
17093
|
+
]);
|
|
17094
|
+
let n = 1;
|
|
17095
|
+
while (used.has(`bc-${n}`)) n += 1;
|
|
17096
|
+
return `bc-${n}`;
|
|
17097
|
+
}
|
|
17098
|
+
var COLLECTION_GAP_MAX_PX = 12;
|
|
17099
|
+
var COLLECTION_GAP_DEFAULT = "12px";
|
|
17100
|
+
function usableGap(value) {
|
|
17101
|
+
if (!value || value === "normal") return null;
|
|
17102
|
+
const n = parseFloat(value);
|
|
17103
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
17104
|
+
if (n > COLLECTION_GAP_MAX_PX) return COLLECTION_GAP_DEFAULT;
|
|
17105
|
+
return `${Math.round(n * 100) / 100}px`;
|
|
17106
|
+
}
|
|
17107
|
+
function collectionGap(el, tokens) {
|
|
17108
|
+
const fromCollection = usableGap(buttonCollectionOf(el)?.style.gap);
|
|
17109
|
+
if (fromCollection) return fromCollection;
|
|
17110
|
+
const parent = el.parentElement;
|
|
17111
|
+
if (parent) {
|
|
17112
|
+
const style = getComputedStyle(parent);
|
|
17113
|
+
const fromParent = usableGap(style.columnGap) ?? usableGap(style.gap);
|
|
17114
|
+
if (fromParent) return fromParent;
|
|
17115
|
+
}
|
|
17116
|
+
const fromTokens = usableGap(tokens?.sizes.m.gap);
|
|
17117
|
+
if (fromTokens) return fromTokens;
|
|
17118
|
+
return COLLECTION_GAP_DEFAULT;
|
|
17119
|
+
}
|
|
17120
|
+
function styleCollection(collection, gap) {
|
|
17121
|
+
collection.style.display = "inline-flex";
|
|
17122
|
+
collection.style.alignItems = "center";
|
|
17123
|
+
collection.style.flexWrap = "wrap";
|
|
17124
|
+
collection.style.gap = gap;
|
|
17125
|
+
collection.style.maxWidth = "100%";
|
|
17126
|
+
}
|
|
17127
|
+
function createCollection(doc, id, gap) {
|
|
17128
|
+
const collection = doc.createElement("div");
|
|
17129
|
+
collection.setAttribute(COLLECTION_ATTR, id);
|
|
17130
|
+
styleCollection(collection, gap);
|
|
17131
|
+
return collection;
|
|
17132
|
+
}
|
|
17133
|
+
function setButtonDragAttr(el) {
|
|
17134
|
+
if (isNavbarCta(el) && buttonCollectionOf(el)) el.removeAttribute("data-ohw-drag-disabled");
|
|
17135
|
+
else el.setAttribute("data-ohw-drag-disabled", "true");
|
|
17136
|
+
}
|
|
17137
|
+
function rekeyCopy(copy, id) {
|
|
17138
|
+
copy.setAttribute("data-ohw-href-key", id);
|
|
17139
|
+
const label = labelElement2(copy);
|
|
17140
|
+
const labelKey = labelKeyForHrefKey(id);
|
|
17141
|
+
if (label) label.setAttribute("data-ohw-key", labelKey);
|
|
17142
|
+
setButtonDragAttr(copy);
|
|
17143
|
+
return { labelKey };
|
|
17144
|
+
}
|
|
17145
|
+
function stampVariantClass(el, variant) {
|
|
17146
|
+
const raw = typeof el.className === "string" ? el.className : el.getAttribute("class") || "";
|
|
17147
|
+
const without = raw.replace(/\bbtn--(?:primary|secondary|ghost)\b/g, "").replace(/\s+/g, " ").trim();
|
|
17148
|
+
el.className = without ? `${without} btn--${variant}` : `btn btn--${variant}`;
|
|
17149
|
+
}
|
|
17150
|
+
function snapshotOf(el) {
|
|
17151
|
+
const id = buttonId(el) ?? "";
|
|
17152
|
+
const label = labelElement2(el);
|
|
17153
|
+
return {
|
|
17154
|
+
id,
|
|
17155
|
+
href: buttonHref(el),
|
|
17156
|
+
label: buttonLabel(el),
|
|
17157
|
+
labelKey: label?.getAttribute("data-ohw-key") ?? labelKeyForHrefKey(id),
|
|
17158
|
+
html: cleanClone(el).outerHTML
|
|
17159
|
+
};
|
|
17160
|
+
}
|
|
17161
|
+
function htmlToElement(doc, html) {
|
|
17162
|
+
const wrap = doc.createElement("div");
|
|
17163
|
+
wrap.innerHTML = html;
|
|
17164
|
+
const el = wrap.firstElementChild;
|
|
17165
|
+
return el instanceof HTMLElement ? el : null;
|
|
17166
|
+
}
|
|
17167
|
+
function findButton(doc, id) {
|
|
17168
|
+
return doc.querySelector(`[data-ohw-href-key="${CSS.escape(id)}"]`);
|
|
17169
|
+
}
|
|
17170
|
+
function duplicateButton(source, content) {
|
|
17171
|
+
if (!canDuplicateButton(source)) return null;
|
|
17172
|
+
const sourceId = buttonId(source);
|
|
17173
|
+
if (!sourceId) return null;
|
|
17174
|
+
const doc = source.ownerDocument;
|
|
17175
|
+
const tokens = tokensFromButton(source);
|
|
17176
|
+
const copyId = nextCopyId(sourceId, content, doc);
|
|
17177
|
+
const copy = cleanClone(source);
|
|
17178
|
+
const { labelKey } = rekeyCopy(copy, copyId);
|
|
17179
|
+
const href = buttonHref(source);
|
|
17180
|
+
const label = buttonLabel(source);
|
|
17181
|
+
if (href) copy.setAttribute("href", href);
|
|
17182
|
+
const sourceAssignment = readAssignments(content)[sourceId] ?? assignmentFor(source, content, tokens);
|
|
17183
|
+
const copyAssignment = {
|
|
17184
|
+
variant: "secondary",
|
|
17185
|
+
size: sourceAssignment.size
|
|
17186
|
+
};
|
|
17187
|
+
stampVariantClass(copy, "secondary");
|
|
17188
|
+
applyButtonStyle(copy, copyAssignment, tokens);
|
|
17189
|
+
const copyLabelEl = labelElement2(copy);
|
|
17190
|
+
if (copyLabelEl) copyLabelEl.textContent = label;
|
|
17191
|
+
let collection = buttonCollectionOf(source);
|
|
17192
|
+
const collections = readCollections(content);
|
|
17193
|
+
let collectionId = collection?.getAttribute(COLLECTION_ATTR) ?? "";
|
|
17194
|
+
let members = collectionId && collections[collectionId] ? [...collections[collectionId].members] : [];
|
|
17195
|
+
const gap = collectionGap(source, tokens);
|
|
17196
|
+
if (!collection) {
|
|
17197
|
+
collectionId = nextCollectionId(content, doc);
|
|
17198
|
+
collection = createCollection(doc, collectionId, gap);
|
|
17199
|
+
source.parentElement?.insertBefore(collection, source);
|
|
17200
|
+
collection.append(source, copy);
|
|
17201
|
+
setButtonDragAttr(source);
|
|
17202
|
+
setButtonDragAttr(copy);
|
|
17203
|
+
members = [sourceId, copyId];
|
|
17204
|
+
} else {
|
|
17205
|
+
styleCollection(collection, gap);
|
|
17206
|
+
source.after(copy);
|
|
17207
|
+
setButtonDragAttr(copy);
|
|
17208
|
+
if (!members.includes(sourceId)) members = listCollectionMembers(collection);
|
|
17209
|
+
const at = members.indexOf(sourceId);
|
|
17210
|
+
members.splice(at >= 0 ? at + 1 : members.length, 0, copyId);
|
|
17211
|
+
}
|
|
17212
|
+
const sourceLabelKey = labelElement2(source)?.getAttribute("data-ohw-key");
|
|
17213
|
+
const snapshots = {
|
|
17214
|
+
...readSnapshots(content),
|
|
17215
|
+
[sourceId]: snapshotOf(source),
|
|
17216
|
+
[copyId]: snapshotOf(copy)
|
|
17217
|
+
};
|
|
17218
|
+
const nextCollections = {
|
|
17219
|
+
...collections,
|
|
17220
|
+
[collectionId]: { id: collectionId, members, gap }
|
|
17221
|
+
};
|
|
17222
|
+
const assignments = withAssignment(content, copyId, copyAssignment);
|
|
17223
|
+
const nextContent = {
|
|
17224
|
+
...content,
|
|
17225
|
+
[copyId]: href,
|
|
17226
|
+
[labelKey]: label,
|
|
17227
|
+
[BUTTON_COLLECTIONS_KEY]: JSON.stringify(nextCollections),
|
|
17228
|
+
[BUTTON_SNAPSHOTS_KEY]: JSON.stringify(snapshots),
|
|
17229
|
+
[BUTTON_ASSIGNMENTS_KEY]: JSON.stringify(assignments)
|
|
17230
|
+
};
|
|
17231
|
+
if (sourceLabelKey && nextContent[sourceLabelKey] === void 0) {
|
|
17232
|
+
nextContent[sourceLabelKey] = label;
|
|
17233
|
+
}
|
|
17234
|
+
const nodeKeys = [
|
|
17235
|
+
copyId,
|
|
17236
|
+
labelKey,
|
|
17237
|
+
BUTTON_COLLECTIONS_KEY,
|
|
17238
|
+
BUTTON_SNAPSHOTS_KEY,
|
|
17239
|
+
BUTTON_ASSIGNMENTS_KEY
|
|
17240
|
+
];
|
|
17241
|
+
if (sourceLabelKey) nodeKeys.push(sourceLabelKey);
|
|
17242
|
+
return {
|
|
17243
|
+
copy,
|
|
17244
|
+
content: nextContent,
|
|
17245
|
+
nodes: contentNodes(nextContent, nodeKeys)
|
|
17246
|
+
};
|
|
17247
|
+
}
|
|
17248
|
+
function listCollectionMembers(collection) {
|
|
17249
|
+
return Array.from(collection.querySelectorAll(CTA_BUTTON_SELECTOR)).map((el) => buttonId(el)).filter((id) => Boolean(id));
|
|
17250
|
+
}
|
|
17251
|
+
function contentNodes(content, keys) {
|
|
17252
|
+
return keys.filter((key) => content[key] !== void 0).map((key) => ({ key, text: content[key] }));
|
|
17253
|
+
}
|
|
17254
|
+
function deleteButton(source, content) {
|
|
17255
|
+
if (!canDeleteButton(source)) return null;
|
|
17256
|
+
const id = buttonId(source);
|
|
17257
|
+
if (!id) return null;
|
|
17258
|
+
const parent = source.parentElement;
|
|
17259
|
+
const nextSibling = source.nextSibling;
|
|
17260
|
+
const removed = source;
|
|
17261
|
+
const collection = buttonCollectionOf(source);
|
|
17262
|
+
const collectionId = collection?.getAttribute(COLLECTION_ATTR) ?? "";
|
|
17263
|
+
const previousCollections = readCollections(content);
|
|
17264
|
+
const previousHidden = readHiddenButtons(content);
|
|
17265
|
+
const snapshots = { ...readSnapshots(content) };
|
|
17266
|
+
const assignments = { ...readAssignments(content) };
|
|
17267
|
+
delete assignments[id];
|
|
17268
|
+
const remainingBeforeUnwrap = collection ? listCollectionMembers(collection).filter((member) => member !== id) : [];
|
|
17269
|
+
removed.remove();
|
|
17270
|
+
let nextCollections = { ...previousCollections };
|
|
17271
|
+
let unwrapped = null;
|
|
17272
|
+
if (collection && collectionId) {
|
|
17273
|
+
const members = listCollectionMembers(collection);
|
|
17274
|
+
if (members.length <= 1) {
|
|
17275
|
+
unwrapped = collection;
|
|
17276
|
+
unwrapCollection(collection);
|
|
17277
|
+
delete nextCollections[collectionId];
|
|
17278
|
+
} else {
|
|
17279
|
+
nextCollections[collectionId] = {
|
|
17280
|
+
id: collectionId,
|
|
17281
|
+
members,
|
|
17282
|
+
gap: collection.style.gap || previousCollections[collectionId]?.gap || "12px"
|
|
17283
|
+
};
|
|
17284
|
+
}
|
|
17285
|
+
}
|
|
17286
|
+
const hidden = previousHidden.includes(id) ? previousHidden : [...previousHidden, id];
|
|
17287
|
+
const nextContent = {
|
|
17288
|
+
...content,
|
|
17289
|
+
[id]: "",
|
|
17290
|
+
[BUTTON_COLLECTIONS_KEY]: JSON.stringify(nextCollections),
|
|
17291
|
+
[BUTTON_HIDDEN_KEY]: JSON.stringify(hidden),
|
|
17292
|
+
[BUTTON_SNAPSHOTS_KEY]: JSON.stringify(snapshots),
|
|
17293
|
+
[BUTTON_ASSIGNMENTS_KEY]: JSON.stringify(assignments)
|
|
17294
|
+
};
|
|
17295
|
+
return {
|
|
17296
|
+
content: nextContent,
|
|
17297
|
+
nodes: contentNodes(nextContent, [id, BUTTON_COLLECTIONS_KEY, BUTTON_HIDDEN_KEY, BUTTON_SNAPSHOTS_KEY, BUTTON_ASSIGNMENTS_KEY]),
|
|
17298
|
+
undo: () => {
|
|
17299
|
+
if (unwrapped && remainingBeforeUnwrap.length === 1) {
|
|
17300
|
+
const remaining = findButton(removed.ownerDocument, remainingBeforeUnwrap[0]);
|
|
17301
|
+
const host = remaining?.parentElement;
|
|
17302
|
+
if (remaining && host) {
|
|
17303
|
+
const restoredCollection = createCollection(
|
|
17304
|
+
removed.ownerDocument,
|
|
17305
|
+
collectionId,
|
|
17306
|
+
previousCollections[collectionId]?.gap || "12px"
|
|
17307
|
+
);
|
|
17308
|
+
host.insertBefore(restoredCollection, remaining);
|
|
17309
|
+
restoredCollection.append(remaining, removed);
|
|
17310
|
+
return;
|
|
17311
|
+
}
|
|
17312
|
+
}
|
|
17313
|
+
if (nextSibling && nextSibling.parentNode === parent) parent?.insertBefore(removed, nextSibling);
|
|
17314
|
+
else parent?.appendChild(removed);
|
|
17315
|
+
}
|
|
17316
|
+
};
|
|
17317
|
+
}
|
|
17318
|
+
function unwrapCollection(collection) {
|
|
17319
|
+
const parent = collection.parentElement;
|
|
17320
|
+
if (!parent) return;
|
|
17321
|
+
while (collection.firstChild) parent.insertBefore(collection.firstChild, collection);
|
|
17322
|
+
collection.remove();
|
|
17323
|
+
}
|
|
17324
|
+
function reorderButtonInCollection(button, clientX) {
|
|
17325
|
+
const collection = buttonCollectionOf(button);
|
|
17326
|
+
const id = buttonId(button);
|
|
17327
|
+
if (!collection || !id) return null;
|
|
17328
|
+
const siblings = Array.from(collection.querySelectorAll(CTA_BUTTON_SELECTOR)).filter((el) => el !== button);
|
|
17329
|
+
let placed = false;
|
|
17330
|
+
for (const sibling of siblings) {
|
|
17331
|
+
const rect = sibling.getBoundingClientRect();
|
|
17332
|
+
if (clientX < rect.left + rect.width / 2) {
|
|
17333
|
+
sibling.before(button);
|
|
17334
|
+
placed = true;
|
|
17335
|
+
break;
|
|
17336
|
+
}
|
|
17337
|
+
}
|
|
17338
|
+
if (!placed) collection.append(button);
|
|
17339
|
+
return listCollectionMembers(collection);
|
|
17340
|
+
}
|
|
17341
|
+
function listVisibleCollectionButtons(collection) {
|
|
17342
|
+
return Array.from(collection.querySelectorAll(CTA_BUTTON_SELECTOR)).filter((el) => {
|
|
17343
|
+
if (!buttonId(el)) return false;
|
|
17344
|
+
return el.getClientRects().length > 0;
|
|
17345
|
+
});
|
|
17346
|
+
}
|
|
17347
|
+
function isVerticalButtonLayout(items, collection) {
|
|
17348
|
+
if (items.length >= 2) {
|
|
17349
|
+
const a = items[0].getBoundingClientRect();
|
|
17350
|
+
const b = items[1].getBoundingClientRect();
|
|
17351
|
+
return b.top - a.bottom > b.left - a.right;
|
|
17352
|
+
}
|
|
17353
|
+
const style = window.getComputedStyle(collection);
|
|
17354
|
+
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
17355
|
+
}
|
|
17356
|
+
function buildButtonCollectionDropSlots(collection) {
|
|
17357
|
+
const items = listVisibleCollectionButtons(collection);
|
|
17358
|
+
const barThickness = 3;
|
|
17359
|
+
const slots = [];
|
|
17360
|
+
if (items.length === 0) {
|
|
17361
|
+
const rect = collection.getBoundingClientRect();
|
|
17362
|
+
slots.push({
|
|
17363
|
+
insertIndex: 0,
|
|
17364
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
17365
|
+
top: rect.top,
|
|
17366
|
+
width: barThickness,
|
|
17367
|
+
height: Math.max(rect.height, 24),
|
|
17368
|
+
direction: "vertical"
|
|
17369
|
+
});
|
|
17370
|
+
return slots;
|
|
17371
|
+
}
|
|
17372
|
+
if (isVerticalButtonLayout(items, collection)) {
|
|
17373
|
+
const edgeGap2 = items.length >= 2 ? Math.max(0, items[1].getBoundingClientRect().top - items[0].getBoundingClientRect().bottom) : 16;
|
|
17374
|
+
for (let i = 0; i <= items.length; i++) {
|
|
17375
|
+
let top;
|
|
17376
|
+
let left;
|
|
17377
|
+
let width;
|
|
17378
|
+
if (i === 0) {
|
|
17379
|
+
const first = items[0].getBoundingClientRect();
|
|
17380
|
+
top = first.top - edgeGap2 / 2 - barThickness / 2;
|
|
17381
|
+
left = first.left;
|
|
17382
|
+
width = first.width;
|
|
17383
|
+
} else if (i === items.length) {
|
|
17384
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
17385
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap2;
|
|
17386
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
17387
|
+
left = last.left;
|
|
17388
|
+
width = last.width;
|
|
17389
|
+
} else {
|
|
17390
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
17391
|
+
const next = items[i].getBoundingClientRect();
|
|
17392
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
17393
|
+
left = Math.min(prev.left, next.left);
|
|
17394
|
+
width = Math.max(prev.right, next.right) - left;
|
|
17395
|
+
}
|
|
17396
|
+
slots.push({
|
|
17397
|
+
insertIndex: i,
|
|
17398
|
+
left,
|
|
17399
|
+
top,
|
|
17400
|
+
width: Math.max(width, 40),
|
|
17401
|
+
height: barThickness,
|
|
17402
|
+
direction: "horizontal"
|
|
17403
|
+
});
|
|
17404
|
+
}
|
|
17405
|
+
return slots;
|
|
17406
|
+
}
|
|
17407
|
+
const edgeGap = items.length >= 2 ? Math.max(0, items[1].getBoundingClientRect().left - items[0].getBoundingClientRect().right) : 12;
|
|
17408
|
+
for (let i = 0; i <= items.length; i++) {
|
|
17409
|
+
let left;
|
|
17410
|
+
let top;
|
|
17411
|
+
let height;
|
|
17412
|
+
if (i === 0) {
|
|
17413
|
+
const first = items[0].getBoundingClientRect();
|
|
17414
|
+
left = first.left - edgeGap / 2 - barThickness / 2;
|
|
17415
|
+
top = first.top;
|
|
17416
|
+
height = first.height;
|
|
17417
|
+
} else if (i === items.length) {
|
|
17418
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
17419
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
17420
|
+
left = last.right + lastGap / 2 - barThickness / 2;
|
|
17421
|
+
top = last.top;
|
|
17422
|
+
height = last.height;
|
|
17423
|
+
} else {
|
|
17424
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
17425
|
+
const next = items[i].getBoundingClientRect();
|
|
17426
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
17427
|
+
top = Math.min(prev.top, next.top);
|
|
17428
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
17429
|
+
}
|
|
17430
|
+
slots.push({
|
|
17431
|
+
insertIndex: i,
|
|
17432
|
+
left,
|
|
17433
|
+
top,
|
|
17434
|
+
width: barThickness,
|
|
17435
|
+
height: Math.max(height, 24),
|
|
17436
|
+
direction: "vertical"
|
|
17437
|
+
});
|
|
17438
|
+
}
|
|
17439
|
+
return slots;
|
|
17440
|
+
}
|
|
17441
|
+
function hitTestButtonCollectionDropSlot(collection, clientX, clientY) {
|
|
17442
|
+
const slots = buildButtonCollectionDropSlots(collection);
|
|
17443
|
+
let best = null;
|
|
17444
|
+
for (const slot of slots) {
|
|
17445
|
+
const cx2 = slot.left + slot.width / 2;
|
|
17446
|
+
const cy = slot.top + slot.height / 2;
|
|
17447
|
+
const dist = slot.direction === "vertical" ? Math.abs(clientX - cx2) + Math.abs(clientY - cy) * 0.25 : Math.abs(clientY - cy) + Math.abs(clientX - cx2) * 0.25;
|
|
17448
|
+
if (!best || dist < best.dist) best = { slot, dist };
|
|
17449
|
+
}
|
|
17450
|
+
return best?.slot ?? null;
|
|
17451
|
+
}
|
|
17452
|
+
function insertButtonAtCollectionIndex(button, insertIndex) {
|
|
17453
|
+
const collection = buttonCollectionOf(button);
|
|
17454
|
+
if (!collection) return null;
|
|
17455
|
+
const items = listVisibleCollectionButtons(collection);
|
|
17456
|
+
const from = items.indexOf(button);
|
|
17457
|
+
if (from < 0) return null;
|
|
17458
|
+
const others = items.filter((el) => el !== button);
|
|
17459
|
+
let index = insertIndex;
|
|
17460
|
+
if (from < insertIndex) index -= 1;
|
|
17461
|
+
if (index <= 0) {
|
|
17462
|
+
const first = others[0];
|
|
17463
|
+
if (first) first.before(button);
|
|
17464
|
+
else collection.append(button);
|
|
17465
|
+
} else if (index >= others.length) {
|
|
17466
|
+
collection.append(button);
|
|
17467
|
+
} else {
|
|
17468
|
+
others[index].before(button);
|
|
17469
|
+
}
|
|
17470
|
+
return listCollectionMembers(collection);
|
|
17471
|
+
}
|
|
17472
|
+
function persistCollectionOrder(collection, content) {
|
|
17473
|
+
const id = collection.getAttribute(COLLECTION_ATTR);
|
|
17474
|
+
if (!id) return null;
|
|
17475
|
+
const collections = readCollections(content);
|
|
17476
|
+
const current = collections[id];
|
|
17477
|
+
const members = listCollectionMembers(collection);
|
|
17478
|
+
const next = {
|
|
17479
|
+
...collections,
|
|
17480
|
+
[id]: { id, members, gap: collection.style.gap || current?.gap || "12px" }
|
|
17481
|
+
};
|
|
17482
|
+
const nextContent = { ...content, [BUTTON_COLLECTIONS_KEY]: JSON.stringify(next) };
|
|
17483
|
+
return { content: nextContent, nodes: [{ key: BUTTON_COLLECTIONS_KEY, text: nextContent[BUTTON_COLLECTIONS_KEY] }] };
|
|
17484
|
+
}
|
|
17485
|
+
function hideButton(el) {
|
|
17486
|
+
if (el.getAttribute("data-ohw-button-hidden") === "") return;
|
|
17487
|
+
el.setAttribute("data-ohw-button-hidden", "");
|
|
17488
|
+
el.style.display = "none";
|
|
17489
|
+
}
|
|
17490
|
+
function syncButtonsFromContent(doc, content) {
|
|
17491
|
+
reconcileButtonCollections(doc, content);
|
|
17492
|
+
applyButtonContentFromContent(doc, content);
|
|
17493
|
+
applyButtonStylesFromContent(doc, content);
|
|
17494
|
+
}
|
|
17495
|
+
function applyButtonContentFromContent(doc, content) {
|
|
17496
|
+
const snapshots = readSnapshots(content);
|
|
17497
|
+
for (const snapshot of Object.values(snapshots)) {
|
|
17498
|
+
const el = findButton(doc, snapshot.id);
|
|
17499
|
+
if (!el) continue;
|
|
17500
|
+
applySnapshotContent(el, snapshot, content);
|
|
17501
|
+
}
|
|
17502
|
+
}
|
|
17503
|
+
function applySnapshotContent(el, snapshot, content) {
|
|
17504
|
+
const href = content[snapshot.id] ?? snapshot.href;
|
|
17505
|
+
if (href) el.setAttribute("href", href);
|
|
17506
|
+
const labelKey = snapshot.labelKey || labelKeyForHrefKey(snapshot.id);
|
|
17507
|
+
if (labelKey && !el.querySelector(`[data-ohw-key="${CSS.escape(labelKey)}"]`)) {
|
|
17508
|
+
const label2 = labelElement2(el);
|
|
17509
|
+
if (label2) label2.setAttribute("data-ohw-key", labelKey);
|
|
17510
|
+
}
|
|
17511
|
+
const text = content[labelKey];
|
|
17512
|
+
if (text === void 0) return;
|
|
17513
|
+
const label = labelElement2(el);
|
|
17514
|
+
if (label) {
|
|
17515
|
+
if (label.getAttribute("data-ohw-key") !== labelKey) label.setAttribute("data-ohw-key", labelKey);
|
|
17516
|
+
if (label.textContent !== text) label.textContent = text;
|
|
17517
|
+
}
|
|
17518
|
+
}
|
|
17519
|
+
function reconcileButtonCollections(doc, content) {
|
|
17520
|
+
const hidden = new Set(readHiddenButtons(content));
|
|
17521
|
+
for (const id of hidden) {
|
|
17522
|
+
const el = findButton(doc, id);
|
|
17523
|
+
if (el) hideButton(el);
|
|
17524
|
+
}
|
|
17525
|
+
const snapshots = readSnapshots(content);
|
|
17526
|
+
const collections = readCollections(content);
|
|
17527
|
+
for (const collectionState of Object.values(collections)) {
|
|
17528
|
+
const live = collectionState.members.map((id) => findButton(doc, id) ?? restoreSnapshot(doc, snapshots[id], content)).filter((el) => Boolean(el && !hidden.has(buttonId(el) ?? "")));
|
|
17529
|
+
if (live.length === 0) continue;
|
|
17530
|
+
if (live.length === 1) {
|
|
17531
|
+
const existing = buttonCollectionOf(live[0]);
|
|
17532
|
+
if (existing) unwrapCollection(existing);
|
|
17533
|
+
continue;
|
|
17534
|
+
}
|
|
17535
|
+
const anchor = live.find((el) => el.isConnected) ?? live[0];
|
|
17536
|
+
let collection = live.map((el) => buttonCollectionOf(el)).find((el) => el?.getAttribute(COLLECTION_ATTR) === collectionState.id) ?? null;
|
|
17537
|
+
if (!collection) {
|
|
17538
|
+
if (!anchor.parentElement) continue;
|
|
17539
|
+
collection = createCollection(doc, collectionState.id, collectionState.gap);
|
|
17540
|
+
anchor.parentElement.insertBefore(collection, anchor);
|
|
17541
|
+
}
|
|
17542
|
+
styleCollection(collection, collectionState.gap);
|
|
17543
|
+
const current = listCollectionMembers(collection);
|
|
17544
|
+
const sameOrder = current.length === live.length && current.every((id, index) => id === buttonId(live[index]));
|
|
17545
|
+
if (!sameOrder) {
|
|
17546
|
+
for (const member of live) collection.append(member);
|
|
17547
|
+
}
|
|
17548
|
+
for (const member of live) setButtonDragAttr(member);
|
|
17549
|
+
}
|
|
17550
|
+
}
|
|
17551
|
+
function restoreSnapshot(doc, snapshot, content) {
|
|
17552
|
+
if (!snapshot) return null;
|
|
17553
|
+
const existing = findButton(doc, snapshot.id);
|
|
17554
|
+
if (existing) {
|
|
17555
|
+
applySnapshotContent(existing, snapshot, content);
|
|
17556
|
+
return existing;
|
|
17557
|
+
}
|
|
17558
|
+
const el = htmlToElement(doc, snapshot.html);
|
|
17559
|
+
if (!el) return null;
|
|
17560
|
+
el.setAttribute("data-ohw-href-key", snapshot.id);
|
|
17561
|
+
const label = labelElement2(el);
|
|
17562
|
+
const labelKey = snapshot.labelKey || labelKeyForHrefKey(snapshot.id);
|
|
17563
|
+
if (label) label.setAttribute("data-ohw-key", labelKey);
|
|
17564
|
+
applySnapshotContent(el, snapshot, content);
|
|
17565
|
+
setButtonDragAttr(el);
|
|
17566
|
+
return el;
|
|
17567
|
+
}
|
|
17568
|
+
function navbarCtasInScope(el) {
|
|
17569
|
+
const scope = el.closest("nav, [data-ohw-nav-root], [data-ohw-nav-drawer]") ?? el.parentElement;
|
|
17570
|
+
if (!scope) return [];
|
|
17571
|
+
return Array.from(scope.querySelectorAll(CTA_BUTTON_SELECTOR)).filter(
|
|
17572
|
+
(button) => isNavbarCta(button) && buttonId(button)
|
|
17573
|
+
);
|
|
17574
|
+
}
|
|
17575
|
+
function ensureNavbarButtonCollection(button, content) {
|
|
17576
|
+
const existing = buttonCollectionOf(button);
|
|
17577
|
+
if (existing) return existing;
|
|
17578
|
+
if (!isNavbarCta(button) || !buttonId(button)) return null;
|
|
17579
|
+
const parent = button.parentElement;
|
|
17580
|
+
if (!parent) return null;
|
|
17581
|
+
const siblings = navbarCtasInScope(button).filter((el) => el.parentElement === parent);
|
|
17582
|
+
if (siblings.length < 2) return null;
|
|
17583
|
+
const id = nextCollectionId(content, button.ownerDocument);
|
|
17584
|
+
const collection = createCollection(button.ownerDocument, id, collectionGap(button, tokensFromButton(button)));
|
|
17585
|
+
siblings[0].before(collection);
|
|
17586
|
+
for (const member of siblings) {
|
|
17587
|
+
collection.append(member);
|
|
17588
|
+
setButtonDragAttr(member);
|
|
17589
|
+
}
|
|
17590
|
+
return collection;
|
|
17591
|
+
}
|
|
17592
|
+
function collectionDragEnabled(el) {
|
|
17593
|
+
if (!isNavbarCta(el) || !buttonId(el)) return false;
|
|
17594
|
+
if (buttonCollectionOf(el)) return true;
|
|
17595
|
+
return navbarCtasInScope(el).length >= 2;
|
|
17596
|
+
}
|
|
17597
|
+
|
|
17598
|
+
// src/lib/item-drag-interaction.ts
|
|
17599
|
+
function disableNativeHrefDrag(el) {
|
|
17600
|
+
if (el.draggable) el.draggable = false;
|
|
17601
|
+
if (el.getAttribute("draggable") !== "false") {
|
|
17602
|
+
el.setAttribute("draggable", "false");
|
|
17603
|
+
}
|
|
17604
|
+
}
|
|
17605
|
+
function clearTextSelection() {
|
|
17606
|
+
const sel = window.getSelection();
|
|
17607
|
+
if (sel && !sel.isCollapsed) sel.removeAllRanges();
|
|
17608
|
+
}
|
|
17609
|
+
function armItemPressDrag() {
|
|
17610
|
+
document.documentElement.setAttribute("data-ohw-footer-press-drag", "");
|
|
17611
|
+
}
|
|
17612
|
+
function lockItemDuringDrag() {
|
|
17613
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
17614
|
+
document.documentElement.setAttribute("data-ohw-item-dragging", "");
|
|
17615
|
+
clearTextSelection();
|
|
17616
|
+
}
|
|
17617
|
+
function unlockItemDragInteraction() {
|
|
17618
|
+
const wasDragging = document.documentElement.hasAttribute("data-ohw-item-dragging");
|
|
17619
|
+
document.documentElement.removeAttribute("data-ohw-footer-press-drag");
|
|
17620
|
+
document.documentElement.removeAttribute("data-ohw-item-dragging");
|
|
17621
|
+
if (wasDragging) clearTextSelection();
|
|
17622
|
+
}
|
|
17623
|
+
var armFooterPressDrag = armItemPressDrag;
|
|
17624
|
+
var lockFooterDuringDrag = lockItemDuringDrag;
|
|
17625
|
+
var unlockFooterDragInteraction = unlockItemDragInteraction;
|
|
17626
|
+
|
|
17627
|
+
// src/lib/nav-dnd.ts
|
|
17628
|
+
function listReorderableNavItems(draggedEl) {
|
|
17629
|
+
return listActiveNavbarItems(draggedEl).filter((el) => {
|
|
17630
|
+
const key = el.getAttribute("data-ohw-href-key");
|
|
17631
|
+
return isNavbarHrefKey(key) && !isNestedNavChild(el);
|
|
17632
|
+
});
|
|
17633
|
+
}
|
|
17634
|
+
function resolveParentNavHrefKey(child) {
|
|
17635
|
+
const childrenRoot = child.closest("[data-ohw-nav-children]");
|
|
17636
|
+
const group = childrenRoot?.closest("[data-ohw-nav-group]");
|
|
17637
|
+
if (!group) return null;
|
|
17638
|
+
const trigger = group.querySelector(":scope > [data-ohw-href-key]") ?? Array.from(group.querySelectorAll("[data-ohw-href-key]")).find(
|
|
17639
|
+
(el) => !el.closest("[data-ohw-nav-children]")
|
|
17640
|
+
) ?? null;
|
|
17641
|
+
const key = trigger?.getAttribute("data-ohw-href-key");
|
|
17642
|
+
return key && isNavbarHrefKey(key) ? key : null;
|
|
17643
|
+
}
|
|
17644
|
+
function listNavChildren(parentHrefKey, draggedEl) {
|
|
17645
|
+
const items = listActiveNavbarItems(draggedEl);
|
|
17646
|
+
const parent = items.find((el) => el.getAttribute("data-ohw-href-key") === parentHrefKey);
|
|
17647
|
+
if (!parent) return [];
|
|
17648
|
+
const group = parent.closest("[data-ohw-nav-group]");
|
|
17649
|
+
const childrenRoot = group?.querySelector(":scope > [data-ohw-nav-children]");
|
|
17650
|
+
if (!childrenRoot) return [];
|
|
17651
|
+
return Array.from(childrenRoot.querySelectorAll(":scope > [data-ohw-href-key]")).filter(
|
|
17652
|
+
(el) => isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))
|
|
17653
|
+
);
|
|
17654
|
+
}
|
|
17655
|
+
function isVerticalNavLayout(items, draggedEl) {
|
|
17656
|
+
const visible = items.filter((el) => el.getClientRects().length > 0);
|
|
17657
|
+
if (visible.length >= 2) {
|
|
17658
|
+
const a = visible[0].getBoundingClientRect();
|
|
17659
|
+
const b = visible[1].getBoundingClientRect();
|
|
17660
|
+
const verticalGap = b.top - a.bottom;
|
|
17661
|
+
const horizontalGap = b.left - a.right;
|
|
17662
|
+
return verticalGap > horizontalGap;
|
|
17663
|
+
}
|
|
17664
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
17665
|
+
if (!container) return false;
|
|
17666
|
+
const style = window.getComputedStyle(container);
|
|
17667
|
+
return style.flexDirection === "column" || style.flexDirection === "column-reverse";
|
|
17668
|
+
}
|
|
17669
|
+
function buildVerticalRootNavDropSlots(items, draggedEl) {
|
|
17670
|
+
const slots = [];
|
|
17671
|
+
const barThickness = 3;
|
|
17672
|
+
if (items.length === 0) {
|
|
17673
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
17674
|
+
if (!container) return slots;
|
|
17675
|
+
const rect = container.getBoundingClientRect();
|
|
17676
|
+
slots.push({
|
|
17677
|
+
insertIndex: 0,
|
|
17678
|
+
parentId: null,
|
|
17679
|
+
left: rect.left,
|
|
17680
|
+
top: rect.top + rect.height / 2 - barThickness / 2,
|
|
17681
|
+
width: Math.max(rect.width, 40),
|
|
17682
|
+
height: barThickness,
|
|
17683
|
+
direction: "horizontal"
|
|
17684
|
+
});
|
|
17685
|
+
return slots;
|
|
17686
|
+
}
|
|
17687
|
+
const edgeGap = (() => {
|
|
17688
|
+
if (items.length < 2) return 16;
|
|
17689
|
+
const a = items[0].getBoundingClientRect();
|
|
17690
|
+
const b = items[1].getBoundingClientRect();
|
|
17691
|
+
return Math.max(0, b.top - a.bottom);
|
|
17692
|
+
})();
|
|
17693
|
+
for (let i = 0; i <= items.length; i++) {
|
|
17694
|
+
let top;
|
|
17695
|
+
let width;
|
|
17696
|
+
let left;
|
|
17697
|
+
if (i === 0) {
|
|
17698
|
+
const first = items[0].getBoundingClientRect();
|
|
17699
|
+
top = first.top - edgeGap / 2 - barThickness / 2;
|
|
17700
|
+
left = first.left;
|
|
17701
|
+
width = first.width;
|
|
17702
|
+
} else if (i === items.length) {
|
|
17703
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
17704
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.top - items[items.length - 2].getBoundingClientRect().bottom) : edgeGap;
|
|
17705
|
+
top = last.bottom + lastGap / 2 - barThickness / 2;
|
|
17706
|
+
left = last.left;
|
|
17707
|
+
width = last.width;
|
|
17708
|
+
} else {
|
|
17709
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
17710
|
+
const next = items[i].getBoundingClientRect();
|
|
17711
|
+
top = (prev.bottom + next.top) / 2 - barThickness / 2;
|
|
17712
|
+
left = Math.min(prev.left, next.left);
|
|
17713
|
+
width = Math.max(prev.right, next.right) - left;
|
|
17714
|
+
}
|
|
17715
|
+
slots.push({
|
|
17716
|
+
insertIndex: i,
|
|
17717
|
+
parentId: null,
|
|
17718
|
+
left,
|
|
17719
|
+
top,
|
|
17720
|
+
width: Math.max(width, 40),
|
|
17721
|
+
height: barThickness,
|
|
17722
|
+
direction: "horizontal"
|
|
17723
|
+
});
|
|
17724
|
+
}
|
|
17725
|
+
return slots;
|
|
17726
|
+
}
|
|
17727
|
+
function buildHorizontalRootNavDropSlots(items, draggedEl) {
|
|
17728
|
+
const slots = [];
|
|
17729
|
+
const barThickness = 3;
|
|
17730
|
+
if (items.length === 0) {
|
|
17731
|
+
const container = getActiveNavbarListContainer(draggedEl);
|
|
17732
|
+
if (!container) return slots;
|
|
17733
|
+
const rect = container.getBoundingClientRect();
|
|
17734
|
+
slots.push({
|
|
17735
|
+
insertIndex: 0,
|
|
17736
|
+
parentId: null,
|
|
17737
|
+
left: rect.left + rect.width / 2 - barThickness / 2,
|
|
17738
|
+
top: rect.top,
|
|
17739
|
+
width: barThickness,
|
|
17740
|
+
height: Math.max(rect.height, 24),
|
|
17741
|
+
direction: "vertical"
|
|
17742
|
+
});
|
|
17743
|
+
return slots;
|
|
17744
|
+
}
|
|
17745
|
+
const edgeGap = (() => {
|
|
17746
|
+
if (items.length < 2) return 32;
|
|
17747
|
+
const a = items[0].getBoundingClientRect();
|
|
17748
|
+
const b = items[1].getBoundingClientRect();
|
|
17749
|
+
return Math.max(0, b.left - a.right);
|
|
17750
|
+
})();
|
|
17751
|
+
for (let i = 0; i <= items.length; i++) {
|
|
17752
|
+
let left;
|
|
17753
|
+
let top;
|
|
17754
|
+
let height;
|
|
17755
|
+
if (i === 0) {
|
|
17756
|
+
const first = items[0].getBoundingClientRect();
|
|
17757
|
+
left = first.left - edgeGap / 2 - barThickness / 2;
|
|
17758
|
+
top = first.top;
|
|
17759
|
+
height = first.height;
|
|
17760
|
+
} else if (i === items.length) {
|
|
17761
|
+
const last = items[items.length - 1].getBoundingClientRect();
|
|
17762
|
+
const lastGap = items.length >= 2 ? Math.max(0, last.left - items[items.length - 2].getBoundingClientRect().right) : edgeGap;
|
|
17763
|
+
left = last.right + lastGap / 2 - barThickness / 2;
|
|
17764
|
+
top = last.top;
|
|
17765
|
+
height = last.height;
|
|
17766
|
+
} else {
|
|
17767
|
+
const prev = items[i - 1].getBoundingClientRect();
|
|
17768
|
+
const next = items[i].getBoundingClientRect();
|
|
17769
|
+
left = (prev.right + next.left) / 2 - barThickness / 2;
|
|
17770
|
+
top = Math.min(prev.top, next.top);
|
|
17771
|
+
height = Math.max(prev.bottom, next.bottom) - top;
|
|
17772
|
+
}
|
|
17773
|
+
slots.push({
|
|
17774
|
+
insertIndex: i,
|
|
17775
|
+
parentId: null,
|
|
17776
|
+
left,
|
|
17777
|
+
top,
|
|
17778
|
+
width: barThickness,
|
|
17779
|
+
height: Math.max(height, 24),
|
|
17780
|
+
direction: "vertical"
|
|
17781
|
+
});
|
|
17782
|
+
}
|
|
17783
|
+
return slots;
|
|
17784
|
+
}
|
|
17785
|
+
function buildRootNavDropSlots(draggedEl) {
|
|
17786
|
+
const items = listReorderableNavItems(draggedEl);
|
|
17787
|
+
if (isVerticalNavLayout(items, draggedEl)) {
|
|
17788
|
+
return buildVerticalRootNavDropSlots(items, draggedEl);
|
|
17789
|
+
}
|
|
16220
17790
|
return buildHorizontalRootNavDropSlots(items, draggedEl);
|
|
16221
17791
|
}
|
|
16222
17792
|
function buildChildNavDropSlots(parentHrefKey, draggedEl) {
|
|
@@ -16454,7 +18024,7 @@ function useNavItemDrag({
|
|
|
16454
18024
|
document.querySelectorAll(
|
|
16455
18025
|
"nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key]"
|
|
16456
18026
|
).forEach((el) => {
|
|
16457
|
-
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
18027
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key")) || isCtaButton(el)) {
|
|
16458
18028
|
disableNativeHrefDrag(el);
|
|
16459
18029
|
}
|
|
16460
18030
|
});
|
|
@@ -16763,12 +18333,6 @@ var SECTION_DRAG_EXCLUDED_SELECTOR = [
|
|
|
16763
18333
|
"[data-ohw-media-overlay]",
|
|
16764
18334
|
"[data-ohw-media-skeleton]"
|
|
16765
18335
|
].join(", ");
|
|
16766
|
-
function visibleClip(ps) {
|
|
16767
|
-
if (!ps) return null;
|
|
16768
|
-
const top = Math.max(0, ps.headerH - ps.iframeOffsetTop);
|
|
16769
|
-
const bottom = Math.min(window.innerHeight, ps.headerH + ps.canvasH - ps.iframeOffsetTop);
|
|
16770
|
-
return { top, bottom: Math.max(top, bottom) };
|
|
16771
|
-
}
|
|
16772
18336
|
function useSectionDrag({
|
|
16773
18337
|
isEditMode,
|
|
16774
18338
|
editContentRef,
|
|
@@ -16805,7 +18369,7 @@ function useSectionDrag({
|
|
|
16805
18369
|
}, [postToParentRef, stopAutoScroll]);
|
|
16806
18370
|
const updateAutoScroll = (0, import_react17.useCallback)(
|
|
16807
18371
|
(clientY) => {
|
|
16808
|
-
const clip =
|
|
18372
|
+
const clip = getIframeChromeClip(parentScrollRef.current);
|
|
16809
18373
|
let delta = 0;
|
|
16810
18374
|
if (clip) {
|
|
16811
18375
|
const distTop = clientY - clip.top;
|
|
@@ -17011,8 +18575,8 @@ function useSectionDrag({
|
|
|
17011
18575
|
}
|
|
17012
18576
|
|
|
17013
18577
|
// src/ui/footer-container-chrome.tsx
|
|
17014
|
-
var
|
|
17015
|
-
var
|
|
18578
|
+
var import_lucide_react18 = require("lucide-react");
|
|
18579
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
17016
18580
|
function FooterContainerChrome({
|
|
17017
18581
|
rect,
|
|
17018
18582
|
onAdd,
|
|
@@ -17020,7 +18584,7 @@ function FooterContainerChrome({
|
|
|
17020
18584
|
}) {
|
|
17021
18585
|
const chromeGap = 6;
|
|
17022
18586
|
const buttonMargin = 7;
|
|
17023
|
-
return /* @__PURE__ */ (0,
|
|
18587
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
17024
18588
|
"div",
|
|
17025
18589
|
{
|
|
17026
18590
|
"data-ohw-footer-container-chrome": "",
|
|
@@ -17032,8 +18596,8 @@ function FooterContainerChrome({
|
|
|
17032
18596
|
width: rect.width + chromeGap * 2,
|
|
17033
18597
|
height: rect.height + chromeGap * 2
|
|
17034
18598
|
},
|
|
17035
|
-
children: /* @__PURE__ */ (0,
|
|
17036
|
-
/* @__PURE__ */ (0,
|
|
18599
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Tooltip, { children: [
|
|
18600
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
17037
18601
|
"button",
|
|
17038
18602
|
{
|
|
17039
18603
|
type: "button",
|
|
@@ -17052,10 +18616,10 @@ function FooterContainerChrome({
|
|
|
17052
18616
|
if (addDisabled) return;
|
|
17053
18617
|
onAdd();
|
|
17054
18618
|
},
|
|
17055
|
-
children: /* @__PURE__ */ (0,
|
|
18619
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react18.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
17056
18620
|
}
|
|
17057
18621
|
) }),
|
|
17058
|
-
/* @__PURE__ */ (0,
|
|
18622
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(TooltipContent, { side: "bottom", sideOffset: 9, children: addDisabled ? "Maximum columns reached" : "Add item" })
|
|
17059
18623
|
] })
|
|
17060
18624
|
}
|
|
17061
18625
|
) });
|
|
@@ -17217,7 +18781,14 @@ function collectEditableNodes(extraContent, root = document) {
|
|
|
17217
18781
|
// so collecting the DOM alone left them behind: the draft knew the row was showing icons and
|
|
17218
18782
|
// had gained an item, and the published page went back to the template's own (OHH-736).
|
|
17219
18783
|
SOCIALS_ORDER_KEY,
|
|
17220
|
-
SOCIALS_DISPLAY_KEY
|
|
18784
|
+
SOCIALS_DISPLAY_KEY,
|
|
18785
|
+
// Button variant/size tokens and per-CTA assignments — JSON in editContent, applied on hydrate.
|
|
18786
|
+
BUTTON_VARIANTS_KEY,
|
|
18787
|
+
BUTTON_SIZES_KEY,
|
|
18788
|
+
BUTTON_ASSIGNMENTS_KEY,
|
|
18789
|
+
BUTTON_COLLECTIONS_KEY,
|
|
18790
|
+
BUTTON_SNAPSHOTS_KEY,
|
|
18791
|
+
BUTTON_HIDDEN_KEY
|
|
17221
18792
|
]) {
|
|
17222
18793
|
const text = extraContent[key];
|
|
17223
18794
|
if (typeof text === "string" && text.length > 0) {
|
|
@@ -17537,14 +19108,14 @@ function deleteSelectedNavFooterItem(deps) {
|
|
|
17537
19108
|
}
|
|
17538
19109
|
|
|
17539
19110
|
// src/ui/navbar-container-chrome.tsx
|
|
17540
|
-
var
|
|
17541
|
-
var
|
|
19111
|
+
var import_lucide_react19 = require("lucide-react");
|
|
19112
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
17542
19113
|
function NavbarContainerChrome({
|
|
17543
19114
|
rect,
|
|
17544
19115
|
onAdd
|
|
17545
19116
|
}) {
|
|
17546
19117
|
const chromeGap = 6;
|
|
17547
|
-
return /* @__PURE__ */ (0,
|
|
19118
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
17548
19119
|
"div",
|
|
17549
19120
|
{
|
|
17550
19121
|
"data-ohw-navbar-container-chrome": "",
|
|
@@ -17556,7 +19127,7 @@ function NavbarContainerChrome({
|
|
|
17556
19127
|
width: rect.width + chromeGap * 2,
|
|
17557
19128
|
height: rect.height + chromeGap * 2
|
|
17558
19129
|
},
|
|
17559
|
-
children: /* @__PURE__ */ (0,
|
|
19130
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
17560
19131
|
"button",
|
|
17561
19132
|
{
|
|
17562
19133
|
type: "button",
|
|
@@ -17573,7 +19144,7 @@ function NavbarContainerChrome({
|
|
|
17573
19144
|
e.stopPropagation();
|
|
17574
19145
|
onAdd();
|
|
17575
19146
|
},
|
|
17576
|
-
children: /* @__PURE__ */ (0,
|
|
19147
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react19.Plus, { className: "size-4 shrink-0 text-foreground", "aria-hidden": true })
|
|
17577
19148
|
}
|
|
17578
19149
|
)
|
|
17579
19150
|
}
|
|
@@ -17582,7 +19153,7 @@ function NavbarContainerChrome({
|
|
|
17582
19153
|
|
|
17583
19154
|
// src/ui/drop-indicator.tsx
|
|
17584
19155
|
var React11 = __toESM(require("react"), 1);
|
|
17585
|
-
var
|
|
19156
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
17586
19157
|
var dropIndicatorVariants = cva(
|
|
17587
19158
|
"ov-gap-line pointer-events-none shrink-0 transition-opacity duration-150",
|
|
17588
19159
|
{
|
|
@@ -17606,7 +19177,7 @@ var dropIndicatorVariants = cva(
|
|
|
17606
19177
|
);
|
|
17607
19178
|
var DropIndicator = React11.forwardRef(
|
|
17608
19179
|
({ className, direction, state, ...props }, ref) => {
|
|
17609
|
-
return /* @__PURE__ */ (0,
|
|
19180
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
17610
19181
|
"div",
|
|
17611
19182
|
{
|
|
17612
19183
|
ref,
|
|
@@ -17623,7 +19194,7 @@ var DropIndicator = React11.forwardRef(
|
|
|
17623
19194
|
DropIndicator.displayName = "DropIndicator";
|
|
17624
19195
|
|
|
17625
19196
|
// src/ui/badge.tsx
|
|
17626
|
-
var
|
|
19197
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
17627
19198
|
var badgeVariants = cva(
|
|
17628
19199
|
"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",
|
|
17629
19200
|
{
|
|
@@ -17641,12 +19212,12 @@ var badgeVariants = cva(
|
|
|
17641
19212
|
}
|
|
17642
19213
|
);
|
|
17643
19214
|
function Badge({ className, variant, ...props }) {
|
|
17644
|
-
return /* @__PURE__ */ (0,
|
|
19215
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
17645
19216
|
}
|
|
17646
19217
|
|
|
17647
19218
|
// src/OhhwellsBridge.tsx
|
|
17648
|
-
var
|
|
17649
|
-
var
|
|
19219
|
+
var import_lucide_react20 = require("lucide-react");
|
|
19220
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
17650
19221
|
var PRIMARY5 = "#0885FE";
|
|
17651
19222
|
var IMAGE_FADE_MS = 300;
|
|
17652
19223
|
var MEDIA_SETTLE_TIMEOUT_MS = 2500;
|
|
@@ -17768,7 +19339,7 @@ function duplicateSchedulingWidget(instanceId, scheduleId) {
|
|
|
17768
19339
|
schedulingRoots.set(container, root);
|
|
17769
19340
|
(0, import_react_dom4.flushSync)(() => {
|
|
17770
19341
|
root.render(
|
|
17771
|
-
/* @__PURE__ */ (0,
|
|
19342
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
17772
19343
|
SchedulingWidget,
|
|
17773
19344
|
{
|
|
17774
19345
|
notifyOnConnect: false,
|
|
@@ -17906,7 +19477,7 @@ function mountSchedulingWidget(insertAfter, notifyOnConnect = false, scheduleId,
|
|
|
17906
19477
|
schedulingRoots.set(container, root);
|
|
17907
19478
|
(0, import_react_dom4.flushSync)(() => {
|
|
17908
19479
|
root.render(
|
|
17909
|
-
/* @__PURE__ */ (0,
|
|
19480
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
17910
19481
|
SchedulingWidget,
|
|
17911
19482
|
{
|
|
17912
19483
|
notifyOnConnect,
|
|
@@ -18069,8 +19640,8 @@ function lockVideoBox(video) {
|
|
|
18069
19640
|
}
|
|
18070
19641
|
const fit = video.style.objectFit || getComputedStyle(video).objectFit;
|
|
18071
19642
|
const bg = getComputedStyle(video).backgroundColor;
|
|
18072
|
-
const
|
|
18073
|
-
if (fit === "contain" &&
|
|
19643
|
+
const isTransparent2 = bg === "rgba(0, 0, 0, 0)" || bg === "transparent" || !bg;
|
|
19644
|
+
if (fit === "contain" && isTransparent2) {
|
|
18074
19645
|
video.style.backgroundColor = "var(--color-dark, #000)";
|
|
18075
19646
|
}
|
|
18076
19647
|
}
|
|
@@ -18220,7 +19791,10 @@ function listNavigationItems() {
|
|
|
18220
19791
|
).filter((el) => isNavigationItem2(el));
|
|
18221
19792
|
}
|
|
18222
19793
|
function getNavigationItemReorderState(anchor) {
|
|
18223
|
-
if (isCtaButton(anchor))
|
|
19794
|
+
if (isCtaButton(anchor)) {
|
|
19795
|
+
if (!collectionDragEnabled(anchor)) return { key: null, disabled: true };
|
|
19796
|
+
return { key: buttonId(anchor), disabled: false };
|
|
19797
|
+
}
|
|
18224
19798
|
return getReorderHandleStateFromAnchor(anchor);
|
|
18225
19799
|
}
|
|
18226
19800
|
function getReorderHandleState(el) {
|
|
@@ -18319,6 +19893,12 @@ function isPointOverNavigation(x, y) {
|
|
|
18319
19893
|
const r2 = panel.getBoundingClientRect();
|
|
18320
19894
|
if (x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) return true;
|
|
18321
19895
|
}
|
|
19896
|
+
for (const el of document.querySelectorAll('[data-ohw-role="navbar-button"]')) {
|
|
19897
|
+
const r2 = el.getBoundingClientRect();
|
|
19898
|
+
if (r2.width > 0 && r2.height > 0 && x >= r2.left && x <= r2.right && y >= r2.top && y <= r2.bottom) {
|
|
19899
|
+
return true;
|
|
19900
|
+
}
|
|
19901
|
+
}
|
|
18322
19902
|
return false;
|
|
18323
19903
|
}
|
|
18324
19904
|
function findHoveredNavOrFooterContainer(x, y) {
|
|
@@ -18652,7 +20232,7 @@ function EditGlowChrome({
|
|
|
18652
20232
|
hideHandle = false
|
|
18653
20233
|
}) {
|
|
18654
20234
|
const GAP = SELECTION_CHROME_GAP2;
|
|
18655
|
-
return /* @__PURE__ */ (0,
|
|
20235
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
18656
20236
|
"div",
|
|
18657
20237
|
{
|
|
18658
20238
|
ref: elRef,
|
|
@@ -18667,7 +20247,7 @@ function EditGlowChrome({
|
|
|
18667
20247
|
zIndex: 2147483646
|
|
18668
20248
|
},
|
|
18669
20249
|
children: [
|
|
18670
|
-
/* @__PURE__ */ (0,
|
|
20250
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18671
20251
|
"div",
|
|
18672
20252
|
{
|
|
18673
20253
|
style: {
|
|
@@ -18681,7 +20261,7 @@ function EditGlowChrome({
|
|
|
18681
20261
|
}
|
|
18682
20262
|
}
|
|
18683
20263
|
),
|
|
18684
|
-
reorderHrefKey && !hideHandle && /* @__PURE__ */ (0,
|
|
20264
|
+
reorderHrefKey && !hideHandle && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18685
20265
|
"div",
|
|
18686
20266
|
{
|
|
18687
20267
|
"data-ohw-drag-handle-container": "",
|
|
@@ -18693,7 +20273,7 @@ function EditGlowChrome({
|
|
|
18693
20273
|
transform: "translate(calc(-100% - 7px), -50%)",
|
|
18694
20274
|
pointerEvents: dragDisabled ? "none" : "auto"
|
|
18695
20275
|
},
|
|
18696
|
-
children: /* @__PURE__ */ (0,
|
|
20276
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18697
20277
|
DragHandle,
|
|
18698
20278
|
{
|
|
18699
20279
|
"aria-label": `Reorder ${reorderHrefKey}`,
|
|
@@ -18707,22 +20287,12 @@ function EditGlowChrome({
|
|
|
18707
20287
|
}
|
|
18708
20288
|
);
|
|
18709
20289
|
}
|
|
18710
|
-
function getIframeVisibleClip(parentScroll) {
|
|
18711
|
-
if (!parentScroll) return null;
|
|
18712
|
-
const { iframeOffsetTop, headerH: visibleCanvasTop, canvasH } = parentScroll;
|
|
18713
|
-
const clipTop = Math.max(0, visibleCanvasTop - iframeOffsetTop);
|
|
18714
|
-
const clipBottom = Math.min(
|
|
18715
|
-
window.innerHeight,
|
|
18716
|
-
visibleCanvasTop + canvasH - iframeOffsetTop
|
|
18717
|
-
);
|
|
18718
|
-
return { top: clipTop, bottom: Math.max(clipTop, clipBottom) };
|
|
18719
|
-
}
|
|
18720
20290
|
function isRectOutsideClip(rect, clip) {
|
|
18721
20291
|
if (!clip) return false;
|
|
18722
20292
|
return rect.bottom < clip.top || rect.top > clip.bottom;
|
|
18723
20293
|
}
|
|
18724
20294
|
function applyVisibleViewport(el, parentScroll) {
|
|
18725
|
-
const clip =
|
|
20295
|
+
const clip = getIframeChromeClip(parentScroll);
|
|
18726
20296
|
const top = clip?.top ?? 0;
|
|
18727
20297
|
const height = clip ? clip.bottom - clip.top : window.innerHeight;
|
|
18728
20298
|
el.style.top = `${top}px`;
|
|
@@ -18762,7 +20332,7 @@ function clampToolbarLeft(centerX, toolbarWidth) {
|
|
|
18762
20332
|
function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
|
|
18763
20333
|
const GAP = TOOLBAR_OFFSET_FROM_ELEMENT;
|
|
18764
20334
|
const APPROX_H = 32;
|
|
18765
|
-
const clip =
|
|
20335
|
+
const clip = getIframeChromeClip(parentScroll);
|
|
18766
20336
|
const clipTop = clip?.top ?? 0;
|
|
18767
20337
|
const canvasTopInIframe = parentScroll != null ? parentScroll.headerH - parentScroll.iframeOffsetTop : 0;
|
|
18768
20338
|
const visibleTop = rect.top - canvasTopInIframe;
|
|
@@ -18907,7 +20477,7 @@ function FloatingToolbar({
|
|
|
18907
20477
|
return () => ro.disconnect();
|
|
18908
20478
|
}, [showEditLink, activeCommands]);
|
|
18909
20479
|
const { top, left, transform } = calcToolbarPos(rect, parentScroll, measuredW);
|
|
18910
|
-
return /* @__PURE__ */ (0,
|
|
20480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18911
20481
|
"div",
|
|
18912
20482
|
{
|
|
18913
20483
|
ref: setRefs,
|
|
@@ -18919,12 +20489,12 @@ function FloatingToolbar({
|
|
|
18919
20489
|
zIndex: 2147483647,
|
|
18920
20490
|
pointerEvents: "auto"
|
|
18921
20491
|
},
|
|
18922
|
-
children: /* @__PURE__ */ (0,
|
|
18923
|
-
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0,
|
|
18924
|
-
gi > 0 && /* @__PURE__ */ (0,
|
|
20492
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(CustomToolbar, { children: [
|
|
20493
|
+
TOOLBAR_GROUPS.map((btns, gi) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react19.default.Fragment, { children: [
|
|
20494
|
+
gi > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(CustomToolbarDivider, {}),
|
|
18925
20495
|
btns.map((btn) => {
|
|
18926
20496
|
const isActive = activeCommands.has(btn.cmd);
|
|
18927
|
-
return /* @__PURE__ */ (0,
|
|
20497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18928
20498
|
CustomToolbarButton,
|
|
18929
20499
|
{
|
|
18930
20500
|
title: btn.title,
|
|
@@ -18933,7 +20503,7 @@ function FloatingToolbar({
|
|
|
18933
20503
|
e.preventDefault();
|
|
18934
20504
|
onCommand(btn.cmd);
|
|
18935
20505
|
},
|
|
18936
|
-
children: /* @__PURE__ */ (0,
|
|
20506
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18937
20507
|
"svg",
|
|
18938
20508
|
{
|
|
18939
20509
|
width: "16",
|
|
@@ -18954,7 +20524,7 @@ function FloatingToolbar({
|
|
|
18954
20524
|
);
|
|
18955
20525
|
})
|
|
18956
20526
|
] }, gi)),
|
|
18957
|
-
showEditLink ? /* @__PURE__ */ (0,
|
|
20527
|
+
showEditLink ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18958
20528
|
CustomToolbarButton,
|
|
18959
20529
|
{
|
|
18960
20530
|
type: "button",
|
|
@@ -18968,7 +20538,7 @@ function FloatingToolbar({
|
|
|
18968
20538
|
e.preventDefault();
|
|
18969
20539
|
e.stopPropagation();
|
|
18970
20540
|
},
|
|
18971
|
-
children: /* @__PURE__ */ (0,
|
|
20541
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react20.Link, { className: "size-4 shrink-0", "aria-hidden": true })
|
|
18972
20542
|
}
|
|
18973
20543
|
) : null
|
|
18974
20544
|
] })
|
|
@@ -18985,7 +20555,7 @@ function StateToggle({
|
|
|
18985
20555
|
states,
|
|
18986
20556
|
onStateChange
|
|
18987
20557
|
}) {
|
|
18988
|
-
return /* @__PURE__ */ (0,
|
|
20558
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
18989
20559
|
ToggleGroup,
|
|
18990
20560
|
{
|
|
18991
20561
|
"data-ohw-state-toggle": "",
|
|
@@ -18999,7 +20569,7 @@ function StateToggle({
|
|
|
18999
20569
|
left: rect.right - 8,
|
|
19000
20570
|
transform: "translateX(-100%)"
|
|
19001
20571
|
},
|
|
19002
|
-
children: states.map((state) => /* @__PURE__ */ (0,
|
|
20572
|
+
children: states.map((state) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ToggleGroupItem, { value: state, size: "sm", children: state }, state))
|
|
19003
20573
|
}
|
|
19004
20574
|
);
|
|
19005
20575
|
}
|
|
@@ -19015,9 +20585,9 @@ var OHW_LOADER_STYLE = {
|
|
|
19015
20585
|
justifyContent: "center"
|
|
19016
20586
|
};
|
|
19017
20587
|
function OhwLoaderSpinner() {
|
|
19018
|
-
return /* @__PURE__ */ (0,
|
|
19019
|
-
/* @__PURE__ */ (0,
|
|
19020
|
-
/* @__PURE__ */ (0,
|
|
20588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", "aria-hidden": true, children: [
|
|
20589
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("circle", { cx: "14", cy: "14", r: "11", stroke: "#E7E5E4", strokeWidth: "3" }),
|
|
20590
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
19021
20591
|
"circle",
|
|
19022
20592
|
{
|
|
19023
20593
|
cx: "14",
|
|
@@ -19027,7 +20597,7 @@ function OhwLoaderSpinner() {
|
|
|
19027
20597
|
strokeWidth: "3",
|
|
19028
20598
|
strokeDasharray: "17 52",
|
|
19029
20599
|
strokeLinecap: "round",
|
|
19030
|
-
children: /* @__PURE__ */ (0,
|
|
20600
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
19031
20601
|
"animateTransform",
|
|
19032
20602
|
{
|
|
19033
20603
|
attributeName: "transform",
|
|
@@ -19043,7 +20613,7 @@ function OhwLoaderSpinner() {
|
|
|
19043
20613
|
] });
|
|
19044
20614
|
}
|
|
19045
20615
|
function OhwBrandMark() {
|
|
19046
|
-
return /* @__PURE__ */ (0,
|
|
20616
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
19047
20617
|
"svg",
|
|
19048
20618
|
{
|
|
19049
20619
|
width: "16",
|
|
@@ -19054,7 +20624,7 @@ function OhwBrandMark() {
|
|
|
19054
20624
|
style: { display: "block", flexShrink: 0 },
|
|
19055
20625
|
xmlns: "http://www.w3.org/2000/svg",
|
|
19056
20626
|
children: [
|
|
19057
|
-
/* @__PURE__ */ (0,
|
|
20627
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
19058
20628
|
"mask",
|
|
19059
20629
|
{
|
|
19060
20630
|
id: "ohw-badge-mark",
|
|
@@ -19064,15 +20634,15 @@ function OhwBrandMark() {
|
|
|
19064
20634
|
y: "0",
|
|
19065
20635
|
width: "48",
|
|
19066
20636
|
height: "48",
|
|
19067
|
-
children: /* @__PURE__ */ (0,
|
|
20637
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: "M23.8741 48C37.0594 48 47.7481 37.2548 47.7481 24C47.7481 10.7452 37.0594 0 23.8741 0C10.6888 0 0 10.7452 0 24C0 37.2548 10.6888 48 23.8741 48Z", fill: "white" })
|
|
19068
20638
|
}
|
|
19069
20639
|
),
|
|
19070
|
-
/* @__PURE__ */ (0,
|
|
19071
|
-
/* @__PURE__ */ (0,
|
|
19072
|
-
/* @__PURE__ */ (0,
|
|
19073
|
-
/* @__PURE__ */ (0,
|
|
19074
|
-
/* @__PURE__ */ (0,
|
|
19075
|
-
/* @__PURE__ */ (0,
|
|
20640
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("g", { mask: "url(#ohw-badge-mark)", children: [
|
|
20641
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: "M23.8731 48.0497C37.0584 48.0497 47.7472 37.3046 47.7472 24.0497C47.7472 10.7949 37.0584 0.0497208 23.8731 0.0497208C10.6878 0.0497208 -0.000976562 10.7949 -0.000976562 24.0497C-0.000976562 37.3046 10.6878 48.0497 23.8731 48.0497Z", fill: "#0078E5" }),
|
|
20642
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: "M17.1307 14.7172C13.1687 14.7172 9.38102 18.1154 8.65114 22.34C8.38885 23.8488 8.5598 25.2581 9.06929 26.4451C6.20005 29.1677 1.77216 27.8721 -1.40212 26.1536C-2.73618 25.4317 -3.92695 27.4745 -2.59037 28.1981C1.33389 30.3226 6.86037 31.6621 10.4402 28.4188C11.4718 29.3859 12.867 29.9621 14.4894 29.9621C18.4161 29.9621 22.2038 26.5318 22.9337 22.34C23.6636 18.1162 21.0566 14.7172 17.1298 14.7172H17.1307ZM19.9798 22.34C19.5281 25.0399 17.2689 27.231 14.9754 27.231C12.6466 27.231 11.1877 25.0399 11.6394 22.34C12.1262 19.6401 14.3151 17.4482 16.6438 17.4482C18.9374 17.4482 20.4667 19.6401 19.9798 22.34Z", fill: "white" }),
|
|
20643
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: "M40.0017 27.0262C39.1797 27.081 38.2721 26.995 37.4668 26.7415C37.3344 26.6993 37.28 26.5401 37.3529 26.4205C37.5959 26.0212 37.8255 25.6152 38.009 25.1889C38.1071 24.9918 38.2018 24.793 38.2897 24.5908C38.3274 24.5041 38.4163 24.451 38.5101 24.4619C38.63 24.4754 38.7054 24.4821 38.8881 24.4821L39.1529 24.4796L39.8283 24.4543C45.9229 24.0492 50.4765 20.4319 54.8466 16.9014C56.0172 15.9554 57.6932 17.6208 56.5116 18.5752C51.7687 22.4065 47.1966 26.5081 40.9319 26.9689", fill: "white" }),
|
|
20644
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: "M37.9687 24.27C38.4472 23.1319 38.7656 21.9045 38.9609 20.6991C39.5927 16.76 38.5058 14.2193 36.1553 14.2193C34.1835 14.2193 33.1469 17.2427 32.9199 18.8694C32.743 19.9872 32.5914 22.1219 33.6028 23.9524C33.7553 24.259 34.15 24.7712 34.471 25.1259C34.5447 25.2067 34.6746 25.2 34.7349 25.1082C34.9528 24.7788 35.1615 24.4039 35.3584 24.0257C35.5444 23.6677 35.5888 23.6138 35.8587 23.0207C35.8838 22.966 35.8813 22.9002 35.8478 22.8505C35.5888 22.4597 35.2168 21.9787 35.1204 21.4614C34.9184 20.4455 34.9436 19.2257 35.2218 18.1078C35.4413 17.3118 35.7195 16.7844 35.9039 16.5106C35.9466 16.4466 36.0279 16.4129 36.0975 16.4449C36.369 16.5671 36.5827 16.8838 36.7385 17.396C37.0167 18.2089 37.0167 19.3782 36.814 20.6999C36.6991 21.5271 36.4771 22.3729 36.1746 23.1673C36.1293 23.308 36.0757 23.4461 36.0187 23.5826C36.0187 23.5868 36.0187 23.591 36.0187 23.5961C35.9911 23.6946 35.9207 23.8067 35.8846 23.901C35.5536 24.5497 35.2344 25.1697 34.8439 25.7838C34.8388 25.7863 34.8346 25.7914 34.8296 25.7931C34.6528 26.0525 34.4718 26.2901 34.2866 26.4965C34.2774 26.5099 34.2682 26.5234 34.2589 26.5369C34.2405 26.5638 34.2179 26.5815 34.1944 26.595C33.5064 27.3212 32.7665 27.6893 32.0123 27.6893C31.8606 27.6893 31.6838 27.664 31.507 27.4349C31.3042 27.1299 30.85 26.0879 31.2539 22.9112C31.4785 21.3949 31.8011 20.0268 31.931 19.5408C31.9579 19.4413 31.8908 19.3419 31.7886 19.3293L30.0062 19.1162C29.9241 19.1061 29.8478 19.1566 29.8252 19.2366C29.2704 21.1615 27.0305 27.6885 24.9599 27.6885C24.328 27.6885 24.1512 26.6211 24.1001 26.2909C23.775 23.6264 25.528 18.5492 29.5302 16.2267C29.6048 16.1838 29.635 16.0928 29.5998 16.0136L28.9042 14.467C28.8632 14.3752 28.7501 14.3389 28.6638 14.3886C25.8079 16.0414 24.1847 18.5231 23.2915 20.3436C22.2046 22.5793 21.6993 25.0189 21.9515 26.8738C22.1795 28.7794 23.1398 29.872 24.6054 29.872C26.0543 29.872 27.4369 28.9066 28.7098 27.0187C28.7953 26.8915 28.9889 26.9311 29.0149 27.0819C29.2646 28.5283 29.9811 29.872 31.6579 29.872C33.5282 29.872 35.3232 28.7288 36.7134 26.6447C36.7712 26.5874 36.7972 26.5411 36.8181 26.4906C36.8232 26.4931 36.8282 26.4948 36.8332 26.4973C37.01 26.2025 37.181 25.9051 37.3444 25.6027C37.4508 25.4005 37.5572 25.1992 37.6586 24.9945C37.7181 24.874 37.7743 24.7527 37.8262 24.6289C37.838 24.6002 37.8547 24.5665 37.8706 24.5337", fill: "white" }),
|
|
20645
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("path", { d: "M30.5839 31.6397C25.7546 34.8577 19.4773 34.7853 14.6907 31.5243C13.5368 30.7384 12.5044 32.6498 13.6474 33.4281C19.034 37.0985 26.3077 37.096 31.7218 33.488C32.8791 32.7172 31.7478 30.8639 30.5839 31.6397Z", fill: "white" })
|
|
19076
20646
|
] })
|
|
19077
20647
|
]
|
|
19078
20648
|
}
|
|
@@ -19109,7 +20679,7 @@ var OHW_BADGE_LABEL_STYLE = {
|
|
|
19109
20679
|
whiteSpace: "nowrap"
|
|
19110
20680
|
};
|
|
19111
20681
|
function MadeWithOhhWells() {
|
|
19112
|
-
return /* @__PURE__ */ (0,
|
|
20682
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
19113
20683
|
"a",
|
|
19114
20684
|
{
|
|
19115
20685
|
href: "https://ohhwells.com",
|
|
@@ -19119,8 +20689,8 @@ function MadeWithOhhWells() {
|
|
|
19119
20689
|
"data-ohw-badge": "",
|
|
19120
20690
|
style: OHW_BADGE_STYLE,
|
|
19121
20691
|
children: [
|
|
19122
|
-
/* @__PURE__ */ (0,
|
|
19123
|
-
/* @__PURE__ */ (0,
|
|
20692
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(OhwBrandMark, {}),
|
|
20693
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { style: OHW_BADGE_LABEL_STYLE, children: "Made with OhhWells" })
|
|
19124
20694
|
]
|
|
19125
20695
|
}
|
|
19126
20696
|
);
|
|
@@ -19610,7 +21180,15 @@ function OhhwellsBridge() {
|
|
|
19610
21180
|
const [floatingPanel, setFloatingPanel] = (0, import_react19.useState)(null);
|
|
19611
21181
|
const floatingPanelOpenRef = (0, import_react19.useRef)(false);
|
|
19612
21182
|
floatingPanelOpenRef.current = floatingPanel !== null;
|
|
21183
|
+
const floatingPanelRef = (0, import_react19.useRef)(null);
|
|
21184
|
+
floatingPanelRef.current = floatingPanel;
|
|
19613
21185
|
const [floatingPanelPos, setFloatingPanelPos] = (0, import_react19.useState)(null);
|
|
21186
|
+
const buttonCollectionDragRef = (0, import_react19.useRef)(null);
|
|
21187
|
+
const buttonDropInsertIndexRef = (0, import_react19.useRef)(null);
|
|
21188
|
+
const [buttonDropSlots, setButtonDropSlots] = (0, import_react19.useState)([]);
|
|
21189
|
+
const [activeButtonDropIndex, setActiveButtonDropIndex] = (0, import_react19.useState)(null);
|
|
21190
|
+
const buttonPointerDragRef = (0, import_react19.useRef)(null);
|
|
21191
|
+
const [buttonStyleTick, setButtonStyleTick] = (0, import_react19.useState)(0);
|
|
19614
21192
|
const [logoSizeDraft, setLogoSizeDraft] = (0, import_react19.useState)(null);
|
|
19615
21193
|
const [editorViewport, setEditorViewport] = (0, import_react19.useState)("desktop");
|
|
19616
21194
|
const [parentScrollSnap, setParentScrollSnap] = (0, import_react19.useState)(null);
|
|
@@ -19911,6 +21489,7 @@ function OhhwellsBridge() {
|
|
|
19911
21489
|
hoveredItemElRef.current = null;
|
|
19912
21490
|
setHoveredItemRect(null);
|
|
19913
21491
|
setFloatingPanel(null);
|
|
21492
|
+
setFloatingPanelPos(null);
|
|
19914
21493
|
setLogoSizeDraft(null);
|
|
19915
21494
|
if (!activeElRef.current) {
|
|
19916
21495
|
if (nestedGroup?.isConnected) {
|
|
@@ -20511,6 +22090,47 @@ function OhhwellsBridge() {
|
|
|
20511
22090
|
},
|
|
20512
22091
|
[beginFooterDrag]
|
|
20513
22092
|
);
|
|
22093
|
+
const persistButtonCollectionDrag = (0, import_react19.useCallback)(
|
|
22094
|
+
(button, clientX) => {
|
|
22095
|
+
const insertIndex = buttonDropInsertIndexRef.current;
|
|
22096
|
+
if (insertIndex != null) insertButtonAtCollectionIndex(button, insertIndex);
|
|
22097
|
+
else if (typeof clientX === "number" && clientX !== 0) reorderButtonInCollection(button, clientX);
|
|
22098
|
+
buttonDropInsertIndexRef.current = null;
|
|
22099
|
+
const collection = buttonCollectionOf(button);
|
|
22100
|
+
if (collection) {
|
|
22101
|
+
const persisted = persistCollectionOrder(collection, editContentRef.current);
|
|
22102
|
+
if (persisted) {
|
|
22103
|
+
editContentRef.current = persisted.content;
|
|
22104
|
+
postToParent2({ type: "ow:change", nodes: persisted.nodes });
|
|
22105
|
+
}
|
|
22106
|
+
}
|
|
22107
|
+
buttonCollectionDragRef.current = null;
|
|
22108
|
+
buttonPointerDragRef.current = null;
|
|
22109
|
+
setButtonDropSlots([]);
|
|
22110
|
+
setActiveButtonDropIndex(null);
|
|
22111
|
+
setIsItemDragging(false);
|
|
22112
|
+
unlockFooterDragInteraction();
|
|
22113
|
+
if (button.isConnected) setToolbarRect(button.getBoundingClientRect());
|
|
22114
|
+
},
|
|
22115
|
+
[postToParent2]
|
|
22116
|
+
);
|
|
22117
|
+
const refreshButtonDragVisuals = (0, import_react19.useCallback)((button, clientX, clientY) => {
|
|
22118
|
+
const collection = buttonCollectionOf(button);
|
|
22119
|
+
if (!collection) {
|
|
22120
|
+
setButtonDropSlots([]);
|
|
22121
|
+
setActiveButtonDropIndex(null);
|
|
22122
|
+
buttonDropInsertIndexRef.current = null;
|
|
22123
|
+
return;
|
|
22124
|
+
}
|
|
22125
|
+
const slots = buildButtonCollectionDropSlots(collection);
|
|
22126
|
+
const active = hitTestButtonCollectionDropSlot(collection, clientX, clientY);
|
|
22127
|
+
setButtonDropSlots(slots);
|
|
22128
|
+
const idx = active ? slots.findIndex((slot) => slot.insertIndex === active.insertIndex) : -1;
|
|
22129
|
+
setActiveButtonDropIndex(idx >= 0 ? idx : null);
|
|
22130
|
+
buttonDropInsertIndexRef.current = active?.insertIndex ?? null;
|
|
22131
|
+
setDraggedItemRect(button.getBoundingClientRect());
|
|
22132
|
+
if (selectedElRef.current === button) setToolbarRect(button.getBoundingClientRect());
|
|
22133
|
+
}, []);
|
|
20514
22134
|
const handleItemDragStart = (0, import_react19.useCallback)(
|
|
20515
22135
|
(e) => {
|
|
20516
22136
|
const selected = selectedElRef.current;
|
|
@@ -20520,6 +22140,17 @@ function OhhwellsBridge() {
|
|
|
20520
22140
|
}
|
|
20521
22141
|
const clientX = e?.clientX ?? selected.getBoundingClientRect().left + 8;
|
|
20522
22142
|
const clientY = e?.clientY ?? selected.getBoundingClientRect().top + 8;
|
|
22143
|
+
if (isCtaButton(selected) && collectionDragEnabled(selected)) {
|
|
22144
|
+
buttonCollectionDragRef.current = selected;
|
|
22145
|
+
setMediaHover(null);
|
|
22146
|
+
if (e?.dataTransfer) {
|
|
22147
|
+
e.dataTransfer.effectAllowed = "move";
|
|
22148
|
+
e.dataTransfer.setData("text/plain", buttonId(selected) ?? "button");
|
|
22149
|
+
}
|
|
22150
|
+
setIsItemDragging(true);
|
|
22151
|
+
refreshButtonDragVisuals(selected, clientX, clientY);
|
|
22152
|
+
return;
|
|
22153
|
+
}
|
|
20523
22154
|
if (startFooterLinkDrag(selected, clientX, clientY, true)) return;
|
|
20524
22155
|
if (selected.hasAttribute("data-ohw-footer-col") || isInferredFooterGroup2(selected) && selected.closest("footer")) {
|
|
20525
22156
|
if (startFooterColumnDrag(selected, clientX, clientY, true)) return;
|
|
@@ -20529,10 +22160,15 @@ function OhhwellsBridge() {
|
|
|
20529
22160
|
setSiblingHintRect(null);
|
|
20530
22161
|
setIsItemDragging(true);
|
|
20531
22162
|
},
|
|
20532
|
-
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag]
|
|
22163
|
+
[startFooterColumnDrag, startFooterLinkDrag, startNavLinkDrag, refreshButtonDragVisuals]
|
|
20533
22164
|
);
|
|
20534
22165
|
const handleItemDragEnd = (0, import_react19.useCallback)(
|
|
20535
22166
|
(e) => {
|
|
22167
|
+
const collectionButton = buttonCollectionDragRef.current;
|
|
22168
|
+
if (collectionButton) {
|
|
22169
|
+
persistButtonCollectionDrag(collectionButton, e?.clientX);
|
|
22170
|
+
return;
|
|
22171
|
+
}
|
|
20536
22172
|
if (footerDragRef.current) {
|
|
20537
22173
|
const x = e?.clientX;
|
|
20538
22174
|
const y = e?.clientY;
|
|
@@ -20555,12 +22191,22 @@ function OhhwellsBridge() {
|
|
|
20555
22191
|
}
|
|
20556
22192
|
setIsItemDragging(false);
|
|
20557
22193
|
},
|
|
20558
|
-
[commitFooterDrag, commitNavDrag, navDragRef]
|
|
22194
|
+
[commitFooterDrag, commitNavDrag, navDragRef, persistButtonCollectionDrag]
|
|
20559
22195
|
);
|
|
20560
22196
|
const handleItemChromePointerDown = (0, import_react19.useCallback)((e) => {
|
|
20561
22197
|
if (e.button !== 0) return;
|
|
20562
22198
|
const selected = selectedElRef.current;
|
|
20563
22199
|
if (!selected) return;
|
|
22200
|
+
if (isCtaButton(selected) && collectionDragEnabled(selected)) {
|
|
22201
|
+
buttonPointerDragRef.current = {
|
|
22202
|
+
el: selected,
|
|
22203
|
+
startX: e.clientX,
|
|
22204
|
+
startY: e.clientY,
|
|
22205
|
+
pointerId: e.pointerId,
|
|
22206
|
+
started: false
|
|
22207
|
+
};
|
|
22208
|
+
return;
|
|
22209
|
+
}
|
|
20564
22210
|
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
20565
22211
|
if (hrefKey && isFooterHrefKey(hrefKey)) {
|
|
20566
22212
|
footerPointerDragRef.current = {
|
|
@@ -20639,10 +22285,29 @@ function OhhwellsBridge() {
|
|
|
20639
22285
|
setIsFooterFrameSelection(false);
|
|
20640
22286
|
setToolbarVariant("link-action");
|
|
20641
22287
|
setToolbarRect(anchor.getBoundingClientRect());
|
|
22288
|
+
if (glowElRef.current) glowElRef.current.style.display = "";
|
|
20642
22289
|
setToolbarShowEditLink(false);
|
|
20643
22290
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
20644
|
-
|
|
20645
|
-
|
|
22291
|
+
const panel = floatingPanelRef.current;
|
|
22292
|
+
if (panel?.kind === "button-style" && isCtaButton(anchor)) {
|
|
22293
|
+
const id = buttonId(anchor);
|
|
22294
|
+
if (id && panel.buttonId !== id) {
|
|
22295
|
+
captureButtonOrigin(anchor);
|
|
22296
|
+
setFloatingPanelPos(null);
|
|
22297
|
+
setParentScrollSnap(parentScrollRef.current);
|
|
22298
|
+
setFloatingPanel({
|
|
22299
|
+
...panel,
|
|
22300
|
+
key: `button-style:${id}`,
|
|
22301
|
+
buttonId: id,
|
|
22302
|
+
context: buttonStyleContext(anchor)
|
|
22303
|
+
});
|
|
22304
|
+
setButtonStyleTick((n) => n + 1);
|
|
22305
|
+
}
|
|
22306
|
+
} else {
|
|
22307
|
+
setFloatingPanel(null);
|
|
22308
|
+
setFloatingPanelPos(null);
|
|
22309
|
+
setLogoSizeDraft(null);
|
|
22310
|
+
}
|
|
20646
22311
|
}, [deactivate, markSelected]);
|
|
20647
22312
|
const selectFrame = (0, import_react19.useCallback)((el) => {
|
|
20648
22313
|
if (!isNavigationContainer(el)) return;
|
|
@@ -20682,6 +22347,7 @@ function OhhwellsBridge() {
|
|
|
20682
22347
|
setToolbarShowEditLink(false);
|
|
20683
22348
|
setActiveCommands(/* @__PURE__ */ new Set());
|
|
20684
22349
|
setFloatingPanel(null);
|
|
22350
|
+
setFloatingPanelPos(null);
|
|
20685
22351
|
setLogoSizeDraft(null);
|
|
20686
22352
|
}, [deactivate, markSelected, postToParent2]);
|
|
20687
22353
|
const selectLogo = (0, import_react19.useCallback)(
|
|
@@ -20727,6 +22393,7 @@ function OhhwellsBridge() {
|
|
|
20727
22393
|
});
|
|
20728
22394
|
}, []);
|
|
20729
22395
|
const openSocialsDisplayPanel = (0, import_react19.useCallback)((row) => {
|
|
22396
|
+
setFloatingPanelPos(null);
|
|
20730
22397
|
setParentScrollSnap(parentScrollRef.current);
|
|
20731
22398
|
setFloatingPanel({
|
|
20732
22399
|
key: "socials-display",
|
|
@@ -20736,6 +22403,87 @@ function OhhwellsBridge() {
|
|
|
20736
22403
|
row
|
|
20737
22404
|
});
|
|
20738
22405
|
}, []);
|
|
22406
|
+
const rememberButtonTokens = (0, import_react19.useCallback)(
|
|
22407
|
+
(content, tokens, nodes) => {
|
|
22408
|
+
if (nodes.length === 0) return content;
|
|
22409
|
+
const next = { ...content };
|
|
22410
|
+
for (const node of nodes) next[node.key] = node.text;
|
|
22411
|
+
editContentRef.current = next;
|
|
22412
|
+
postToParent2({ type: "ow:change", nodes });
|
|
22413
|
+
return next;
|
|
22414
|
+
},
|
|
22415
|
+
[postToParent2]
|
|
22416
|
+
);
|
|
22417
|
+
const tokensForButton = (0, import_react19.useCallback)(
|
|
22418
|
+
(el, persistFallback = false) => {
|
|
22419
|
+
const stored = readStoredStyleTokens(editContentRef.current);
|
|
22420
|
+
if (stored) return stored;
|
|
22421
|
+
const ensured = ensureButtonStyleTokens(document, editContentRef.current);
|
|
22422
|
+
if (ensured.tokens) {
|
|
22423
|
+
rememberButtonTokens(editContentRef.current, ensured.tokens, ensured.nodes);
|
|
22424
|
+
return ensured.tokens;
|
|
22425
|
+
}
|
|
22426
|
+
const fallback = tokensFromButton(el);
|
|
22427
|
+
if (persistFallback) rememberButtonTokens(editContentRef.current, fallback, styleTokenNodes(fallback));
|
|
22428
|
+
return fallback;
|
|
22429
|
+
},
|
|
22430
|
+
[rememberButtonTokens]
|
|
22431
|
+
);
|
|
22432
|
+
const openButtonStylePanel = (0, import_react19.useCallback)(
|
|
22433
|
+
(anchor) => {
|
|
22434
|
+
const id = buttonId(anchor);
|
|
22435
|
+
if (!id) return;
|
|
22436
|
+
captureButtonOrigin(anchor);
|
|
22437
|
+
tokensForButton(anchor);
|
|
22438
|
+
setFloatingPanelPos(null);
|
|
22439
|
+
setParentScrollSnap(parentScrollRef.current);
|
|
22440
|
+
setFloatingPanel({
|
|
22441
|
+
key: `button-style:${id}`,
|
|
22442
|
+
title: "Style",
|
|
22443
|
+
context: buttonStyleContext(anchor),
|
|
22444
|
+
kind: "button-style",
|
|
22445
|
+
buttonId: id
|
|
22446
|
+
});
|
|
22447
|
+
},
|
|
22448
|
+
[tokensForButton]
|
|
22449
|
+
);
|
|
22450
|
+
const applySelectedButtonStyle = (0, import_react19.useCallback)(
|
|
22451
|
+
(patch) => {
|
|
22452
|
+
const panel = floatingPanelRef.current;
|
|
22453
|
+
const id = panel?.kind === "button-style" ? panel.buttonId : null;
|
|
22454
|
+
const el = id ? document.querySelector(`[data-ohw-href-key="${CSS.escape(id)}"]`) : null;
|
|
22455
|
+
if (!el || !id || !isCtaButton(el)) return;
|
|
22456
|
+
const tokens = tokensFromButton(el);
|
|
22457
|
+
const next = { ...assignmentFor(el, editContentRef.current, tokens), ...patch };
|
|
22458
|
+
const assignments = withAssignment(editContentRef.current, id, next);
|
|
22459
|
+
const text = JSON.stringify(assignments);
|
|
22460
|
+
editContentRef.current = { ...editContentRef.current, [BUTTON_ASSIGNMENTS_KEY]: text };
|
|
22461
|
+
applyButtonStyle(el, next, tokens);
|
|
22462
|
+
postToParent2({ type: "ow:change", nodes: [{ key: BUTTON_ASSIGNMENTS_KEY, text }] });
|
|
22463
|
+
setButtonStyleTick((n) => n + 1);
|
|
22464
|
+
if (selectedElRef.current === el) setToolbarRect(el.getBoundingClientRect());
|
|
22465
|
+
},
|
|
22466
|
+
[postToParent2]
|
|
22467
|
+
);
|
|
22468
|
+
(0, import_react19.useEffect)(() => {
|
|
22469
|
+
const onDragOver = (e) => {
|
|
22470
|
+
const dragged = buttonCollectionDragRef.current;
|
|
22471
|
+
if (!dragged) return;
|
|
22472
|
+
e.preventDefault();
|
|
22473
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
22474
|
+
refreshButtonDragVisuals(dragged, e.clientX, e.clientY);
|
|
22475
|
+
};
|
|
22476
|
+
const onDrop = (e) => {
|
|
22477
|
+
if (!buttonCollectionDragRef.current) return;
|
|
22478
|
+
e.preventDefault();
|
|
22479
|
+
};
|
|
22480
|
+
document.addEventListener("dragover", onDragOver);
|
|
22481
|
+
document.addEventListener("drop", onDrop);
|
|
22482
|
+
return () => {
|
|
22483
|
+
document.removeEventListener("dragover", onDragOver);
|
|
22484
|
+
document.removeEventListener("drop", onDrop);
|
|
22485
|
+
};
|
|
22486
|
+
}, [refreshButtonDragVisuals]);
|
|
20739
22487
|
const isEditModeRef = (0, import_react19.useRef)(false);
|
|
20740
22488
|
const requestMissingSocialIconsRef = (0, import_react19.useRef)(() => {
|
|
20741
22489
|
});
|
|
@@ -20778,11 +22526,13 @@ function OhhwellsBridge() {
|
|
|
20778
22526
|
);
|
|
20779
22527
|
const closeFloatingPanelOnly = (0, import_react19.useCallback)(() => {
|
|
20780
22528
|
setFloatingPanel(null);
|
|
22529
|
+
setFloatingPanelPos(null);
|
|
20781
22530
|
setLogoSizeDraft(null);
|
|
20782
22531
|
}, []);
|
|
20783
22532
|
closeFloatingPanelOnlyRef.current = closeFloatingPanelOnly;
|
|
20784
22533
|
const closeFloatingPanelAndDeselect = (0, import_react19.useCallback)(() => {
|
|
20785
22534
|
setFloatingPanel(null);
|
|
22535
|
+
setFloatingPanelPos(null);
|
|
20786
22536
|
setLogoSizeDraft(null);
|
|
20787
22537
|
deselectRef.current();
|
|
20788
22538
|
}, []);
|
|
@@ -20994,6 +22744,7 @@ function OhhwellsBridge() {
|
|
|
20994
22744
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
20995
22745
|
}
|
|
20996
22746
|
applyBrandChrome(content);
|
|
22747
|
+
applyCustomCodeToHead(content);
|
|
20997
22748
|
initSectionInstancesFromContent(content, window.location.pathname);
|
|
20998
22749
|
for (const [key, val] of Object.entries(content)) {
|
|
20999
22750
|
if (key === "__ohw_sections") continue;
|
|
@@ -21002,6 +22753,7 @@ function OhhwellsBridge() {
|
|
|
21002
22753
|
if (key === STYLE_STORE_KEY) continue;
|
|
21003
22754
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
21004
22755
|
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
22756
|
+
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
21005
22757
|
if (LOGO_IMAGE_KEYS.includes(key)) continue;
|
|
21006
22758
|
if (applyVideoSettingNode(key, val)) continue;
|
|
21007
22759
|
if (applyCarouselNode(key, val)) continue;
|
|
@@ -21049,6 +22801,7 @@ function OhhwellsBridge() {
|
|
|
21049
22801
|
reconcileSocialsFromContent(content);
|
|
21050
22802
|
applySocialsDisplayFromContent(content);
|
|
21051
22803
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
22804
|
+
syncButtonsFromContent(document, content);
|
|
21052
22805
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
21053
22806
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
21054
22807
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
@@ -21249,6 +23002,7 @@ function OhhwellsBridge() {
|
|
|
21249
23002
|
reconcileSocialsFromContent(content);
|
|
21250
23003
|
applySocialsDisplayFromContent(content);
|
|
21251
23004
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
23005
|
+
syncButtonsFromContent(document, content);
|
|
21252
23006
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
21253
23007
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
21254
23008
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
@@ -21337,7 +23091,10 @@ function OhhwellsBridge() {
|
|
|
21337
23091
|
if (roots.length === 0) {
|
|
21338
23092
|
reconcileNavbarItemsFromContent(contentForNav());
|
|
21339
23093
|
reconcileFooterOrderFromContent(contentForNav());
|
|
21340
|
-
if (isEditMode)
|
|
23094
|
+
if (isEditMode) {
|
|
23095
|
+
syncButtonsFromContent(document, contentForNav());
|
|
23096
|
+
syncNavigationDragCursorAttrs();
|
|
23097
|
+
}
|
|
21341
23098
|
return;
|
|
21342
23099
|
}
|
|
21343
23100
|
let rafId = null;
|
|
@@ -21349,7 +23106,7 @@ function OhhwellsBridge() {
|
|
|
21349
23106
|
}
|
|
21350
23107
|
};
|
|
21351
23108
|
const run = () => {
|
|
21352
|
-
if (footerDragRef.current || navDragRef.current || applying) return;
|
|
23109
|
+
if (footerDragRef.current || navDragRef.current || buttonCollectionDragRef.current || applying) return;
|
|
21353
23110
|
applying = true;
|
|
21354
23111
|
observer?.disconnect();
|
|
21355
23112
|
try {
|
|
@@ -21359,6 +23116,7 @@ function OhhwellsBridge() {
|
|
|
21359
23116
|
reconcileSocialsFromContent(content);
|
|
21360
23117
|
applySocialsDisplayFromContent(content);
|
|
21361
23118
|
applySocialsLabelsFromContent(content, document, { fillEmptyOnly: isEditModeRef.current });
|
|
23119
|
+
syncButtonsFromContent(document, content);
|
|
21362
23120
|
if (isEditModeRef.current) requestMissingSocialIconsRef.current();
|
|
21363
23121
|
document.querySelectorAll("footer [data-ohw-href-key]").forEach((el) => {
|
|
21364
23122
|
if (isFooterHrefKey(el.getAttribute("data-ohw-href-key")) || getSocialItem(el)) {
|
|
@@ -21366,9 +23124,9 @@ function OhhwellsBridge() {
|
|
|
21366
23124
|
}
|
|
21367
23125
|
});
|
|
21368
23126
|
document.querySelectorAll(
|
|
21369
|
-
|
|
23127
|
+
'nav [data-ohw-href-key], [data-ohw-nav-container] [data-ohw-href-key], [data-ohw-nav-drawer] [data-ohw-href-key], [data-ohw-role="navbar-button"]'
|
|
21370
23128
|
).forEach((el) => {
|
|
21371
|
-
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key"))) {
|
|
23129
|
+
if (isNavbarHrefKey(el.getAttribute("data-ohw-href-key")) || isCtaButton(el)) {
|
|
21372
23130
|
disableNativeHrefDrag(el);
|
|
21373
23131
|
}
|
|
21374
23132
|
});
|
|
@@ -21393,6 +23151,44 @@ function OhhwellsBridge() {
|
|
|
21393
23151
|
observer?.disconnect();
|
|
21394
23152
|
};
|
|
21395
23153
|
}, [isEditMode, pathname, subdomain, fetchState, resyncSelectedNavigationItem]);
|
|
23154
|
+
(0, import_react19.useEffect)(() => {
|
|
23155
|
+
if (!isEditMode) return;
|
|
23156
|
+
let applying = false;
|
|
23157
|
+
let rafId = null;
|
|
23158
|
+
const run = () => {
|
|
23159
|
+
if (applying || buttonCollectionDragRef.current) return;
|
|
23160
|
+
const content = editContentRef.current;
|
|
23161
|
+
if (!content[BUTTON_COLLECTIONS_KEY] && !content[BUTTON_SNAPSHOTS_KEY]) return;
|
|
23162
|
+
applying = true;
|
|
23163
|
+
try {
|
|
23164
|
+
syncButtonsFromContent(document, content);
|
|
23165
|
+
} finally {
|
|
23166
|
+
applying = false;
|
|
23167
|
+
}
|
|
23168
|
+
};
|
|
23169
|
+
const schedule = () => {
|
|
23170
|
+
if (rafId != null) return;
|
|
23171
|
+
rafId = requestAnimationFrame(() => {
|
|
23172
|
+
rafId = null;
|
|
23173
|
+
run();
|
|
23174
|
+
});
|
|
23175
|
+
};
|
|
23176
|
+
const observer = new MutationObserver((mutations) => {
|
|
23177
|
+
if (mutations.every((m) => {
|
|
23178
|
+
const t = m.target;
|
|
23179
|
+
return t instanceof Element && Boolean(t.closest("[data-ohw-bridge], [data-ohw-bridge-root], [data-ohw-button-collection]"));
|
|
23180
|
+
})) {
|
|
23181
|
+
return;
|
|
23182
|
+
}
|
|
23183
|
+
schedule();
|
|
23184
|
+
});
|
|
23185
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
23186
|
+
run();
|
|
23187
|
+
return () => {
|
|
23188
|
+
if (rafId != null) cancelAnimationFrame(rafId);
|
|
23189
|
+
observer.disconnect();
|
|
23190
|
+
};
|
|
23191
|
+
}, [isEditMode, pathname]);
|
|
21396
23192
|
(0, import_react19.useEffect)(() => {
|
|
21397
23193
|
if (!isEditMode) return;
|
|
21398
23194
|
let lastPosted = 0;
|
|
@@ -21919,14 +23715,6 @@ function OhhwellsBridge() {
|
|
|
21919
23715
|
}
|
|
21920
23716
|
const clickedButton = findClosestButtonLike(target);
|
|
21921
23717
|
const buttonOnMedia = Boolean(clickedButton && isMediaEditable(editable) && editable.contains(clickedButton));
|
|
21922
|
-
console.log("[click-debug]", {
|
|
21923
|
-
editableType: editable.dataset.ohwEditable,
|
|
21924
|
-
editableTag: editable.tagName,
|
|
21925
|
-
targetTag: target.tagName,
|
|
21926
|
-
clickedButtonTag: clickedButton?.tagName ?? null,
|
|
21927
|
-
buttonOnMedia,
|
|
21928
|
-
isMediaEditableEditable: isMediaEditable(editable)
|
|
21929
|
-
});
|
|
21930
23718
|
if (isMediaEditable(editable) && !buttonOnMedia) {
|
|
21931
23719
|
e.preventDefault();
|
|
21932
23720
|
e.stopPropagation();
|
|
@@ -21961,11 +23749,6 @@ function OhhwellsBridge() {
|
|
|
21961
23749
|
const hrefLookupTarget = buttonOnMedia ? clickedButton : editable;
|
|
21962
23750
|
const hrefCtx = getHrefKeyFromElement(hrefLookupTarget);
|
|
21963
23751
|
const navAnchor = hrefCtx ? getNavigationItemAnchor(hrefCtx.anchor) : null;
|
|
21964
|
-
console.log("[click-debug 2]", {
|
|
21965
|
-
hrefLookupTargetTag: hrefLookupTarget.tagName,
|
|
21966
|
-
hrefCtx: hrefCtx ? { key: hrefCtx.key } : null,
|
|
21967
|
-
navAnchorTag: navAnchor?.tagName ?? null
|
|
21968
|
-
});
|
|
21969
23752
|
if (navAnchor) {
|
|
21970
23753
|
e.preventDefault();
|
|
21971
23754
|
e.stopPropagation();
|
|
@@ -22481,6 +24264,20 @@ function OhhwellsBridge() {
|
|
|
22481
24264
|
}
|
|
22482
24265
|
return;
|
|
22483
24266
|
}
|
|
24267
|
+
const navbarCtaHit = findNavbarCtaAtPoint(x, y);
|
|
24268
|
+
if (navbarCtaHit) {
|
|
24269
|
+
hoveredNavContainerRef.current = null;
|
|
24270
|
+
setHoveredNavContainerRect(null);
|
|
24271
|
+
if (selected !== navbarCtaHit && !selected?.contains(navbarCtaHit)) {
|
|
24272
|
+
clearHrefKeyHover(navbarCtaHit);
|
|
24273
|
+
hoveredItemElRef.current = navbarCtaHit;
|
|
24274
|
+
setHoveredItemRect(navbarCtaHit.getBoundingClientRect());
|
|
24275
|
+
} else if (hoveredItemElRef.current === navbarCtaHit) {
|
|
24276
|
+
hoveredItemElRef.current = null;
|
|
24277
|
+
setHoveredItemRect(null);
|
|
24278
|
+
}
|
|
24279
|
+
return;
|
|
24280
|
+
}
|
|
22484
24281
|
const navContainers = Array.from(
|
|
22485
24282
|
document.querySelectorAll("[data-ohw-nav-container]")
|
|
22486
24283
|
);
|
|
@@ -22583,6 +24380,24 @@ function OhhwellsBridge() {
|
|
|
22583
24380
|
return;
|
|
22584
24381
|
}
|
|
22585
24382
|
const { x, y } = toProbeCoords(clientX, clientY, fromParentViewport);
|
|
24383
|
+
if (!isDragOver) {
|
|
24384
|
+
const buttonHit = findButtonAtPoint(x, y);
|
|
24385
|
+
if (buttonHit) {
|
|
24386
|
+
dismissImageHover();
|
|
24387
|
+
if (findNavbarCtaAtPoint(x, y)) {
|
|
24388
|
+
probeNavigationHoverAt(x, y);
|
|
24389
|
+
return;
|
|
24390
|
+
}
|
|
24391
|
+
document.querySelectorAll("[data-ohw-hovered]").forEach((el) => el.removeAttribute("data-ohw-hovered"));
|
|
24392
|
+
const selected = selectedElRef.current;
|
|
24393
|
+
if (selected !== buttonHit && !selected?.contains(buttonHit)) {
|
|
24394
|
+
clearHrefKeyHover(buttonHit);
|
|
24395
|
+
hoveredItemElRef.current = buttonHit;
|
|
24396
|
+
setHoveredItemRect(buttonHit.getBoundingClientRect());
|
|
24397
|
+
}
|
|
24398
|
+
return;
|
|
24399
|
+
}
|
|
24400
|
+
}
|
|
22586
24401
|
if (isPointOverNavigation(x, y)) {
|
|
22587
24402
|
dismissImageHover();
|
|
22588
24403
|
probeNavigationHoverAt(x, y);
|
|
@@ -23004,6 +24819,11 @@ function OhhwellsBridge() {
|
|
|
23004
24819
|
return;
|
|
23005
24820
|
}
|
|
23006
24821
|
if (onNavDragOver(e)) return;
|
|
24822
|
+
if (buttonCollectionDragRef.current) {
|
|
24823
|
+
e.preventDefault();
|
|
24824
|
+
if (e.dataTransfer) e.dataTransfer.dropEffect = "move";
|
|
24825
|
+
return;
|
|
24826
|
+
}
|
|
23007
24827
|
e.preventDefault();
|
|
23008
24828
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
23009
24829
|
if (!el) {
|
|
@@ -23028,6 +24848,7 @@ function OhhwellsBridge() {
|
|
|
23028
24848
|
};
|
|
23029
24849
|
const handleDrop = (e) => {
|
|
23030
24850
|
e.preventDefault();
|
|
24851
|
+
if (buttonCollectionDragRef.current || navDragRef.current || footerDragRef.current) return;
|
|
23031
24852
|
const el = findImageAtPoint(e.clientX, e.clientY, false);
|
|
23032
24853
|
if (!el) return;
|
|
23033
24854
|
const file = e.dataTransfer?.files?.[0];
|
|
@@ -23330,6 +25151,7 @@ function OhhwellsBridge() {
|
|
|
23330
25151
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
23331
25152
|
}
|
|
23332
25153
|
applyBrandChrome(content);
|
|
25154
|
+
applyCustomCodeToHead(content);
|
|
23333
25155
|
initSectionInstancesFromContent(content, window.location.pathname);
|
|
23334
25156
|
let sectionsJson = null;
|
|
23335
25157
|
for (const [key, val] of Object.entries(content)) {
|
|
@@ -23342,6 +25164,7 @@ function OhhwellsBridge() {
|
|
|
23342
25164
|
if (key === STYLE_STORE_KEY) continue;
|
|
23343
25165
|
if (BRAND_CHROME_KEYS.has(key)) continue;
|
|
23344
25166
|
if (key === LOGO_PLACEHOLDER_KEY) continue;
|
|
25167
|
+
if (key === CUSTOM_CODE_AFTER_HEAD_KEY || key === CUSTOM_CODE_BEFORE_HEAD_KEY) continue;
|
|
23345
25168
|
if (LOGO_IMAGE_KEYS.includes(key) && !String(val ?? "").trim()) continue;
|
|
23346
25169
|
if (applyVideoSettingNode(key, val)) continue;
|
|
23347
25170
|
if (applyCarouselNode(key, val)) continue;
|
|
@@ -23381,6 +25204,7 @@ function OhhwellsBridge() {
|
|
|
23381
25204
|
editContentRef.current = { ...editContentRef.current, ...content };
|
|
23382
25205
|
reconcileNavbarItemsFromContent(editContentRef.current);
|
|
23383
25206
|
reconcileFooterOrderFromContent(editContentRef.current);
|
|
25207
|
+
syncButtonsFromContent(document, editContentRef.current);
|
|
23384
25208
|
syncNavigationDragCursorAttrs();
|
|
23385
25209
|
if (typeof content[STYLE_STORE_KEY] === "string") {
|
|
23386
25210
|
applyStylesToDom(parseStyleStore(content[STYLE_STORE_KEY]));
|
|
@@ -24053,6 +25877,16 @@ function OhhwellsBridge() {
|
|
|
24053
25877
|
if (brandKitRef.current) {
|
|
24054
25878
|
nodes.push({ key: BRAND_KIT_KEY, type: "brand", text: brandKitRef.current });
|
|
24055
25879
|
}
|
|
25880
|
+
nodes.push({
|
|
25881
|
+
key: CUSTOM_CODE_BEFORE_HEAD_KEY,
|
|
25882
|
+
type: "text",
|
|
25883
|
+
text: editContentRef.current[CUSTOM_CODE_BEFORE_HEAD_KEY] ?? ""
|
|
25884
|
+
});
|
|
25885
|
+
nodes.push({
|
|
25886
|
+
key: CUSTOM_CODE_AFTER_HEAD_KEY,
|
|
25887
|
+
type: "text",
|
|
25888
|
+
text: editContentRef.current[CUSTOM_CODE_AFTER_HEAD_KEY] ?? ""
|
|
25889
|
+
});
|
|
24056
25890
|
document.querySelectorAll('[data-ohw-editable="form"]').forEach((form) => {
|
|
24057
25891
|
const formKey = formKeyOf(form);
|
|
24058
25892
|
if (!formKey) return;
|
|
@@ -24280,11 +26114,8 @@ function OhhwellsBridge() {
|
|
|
24280
26114
|
};
|
|
24281
26115
|
const handleParentScroll = (e) => {
|
|
24282
26116
|
if (e.data?.type !== "ow:parent-scroll") return;
|
|
24283
|
-
const { iframeOffsetTop, headerH, canvasH } = e.data;
|
|
24284
|
-
parentScrollRef.current = { iframeOffsetTop, headerH, canvasH };
|
|
24285
|
-
if (floatingPanelOpenRef.current) {
|
|
24286
|
-
setParentScrollSnap({ iframeOffsetTop, headerH, canvasH });
|
|
24287
|
-
}
|
|
26117
|
+
const { iframeOffsetTop, headerH, canvasH, promptBarH = 0 } = e.data;
|
|
26118
|
+
parentScrollRef.current = { iframeOffsetTop, headerH, canvasH, promptBarH };
|
|
24288
26119
|
if (visibleViewportRef.current) {
|
|
24289
26120
|
applyVisibleViewport(visibleViewportRef.current, parentScrollRef.current);
|
|
24290
26121
|
}
|
|
@@ -24674,6 +26505,97 @@ function OhhwellsBridge() {
|
|
|
24674
26505
|
unlockFooterDragInteraction();
|
|
24675
26506
|
};
|
|
24676
26507
|
}, [isEditMode]);
|
|
26508
|
+
(0, import_react19.useEffect)(() => {
|
|
26509
|
+
if (!isEditMode) return;
|
|
26510
|
+
const THRESHOLD = 10;
|
|
26511
|
+
const onPointerDown = (e) => {
|
|
26512
|
+
if (e.button !== 0) return;
|
|
26513
|
+
if (buttonCollectionDragRef.current || navDragRef.current || footerDragRef.current) return;
|
|
26514
|
+
if (buttonPointerDragRef.current) return;
|
|
26515
|
+
const target = e.target;
|
|
26516
|
+
if (!target) return;
|
|
26517
|
+
if (target.closest(
|
|
26518
|
+
'[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]'
|
|
26519
|
+
)) {
|
|
26520
|
+
return;
|
|
26521
|
+
}
|
|
26522
|
+
const fromTarget = target.closest('[data-ohw-role="navbar-button"]');
|
|
26523
|
+
const anchor = (fromTarget && !fromTarget.closest("[data-ohw-bridge]") ? fromTarget : null) ?? findNavbarCtaAtPoint(e.clientX, e.clientY);
|
|
26524
|
+
if (!anchor || !collectionDragEnabled(anchor)) return;
|
|
26525
|
+
disableNativeHrefDrag(anchor);
|
|
26526
|
+
setMediaHover(null);
|
|
26527
|
+
buttonPointerDragRef.current = {
|
|
26528
|
+
el: anchor,
|
|
26529
|
+
startX: e.clientX,
|
|
26530
|
+
startY: e.clientY,
|
|
26531
|
+
pointerId: e.pointerId,
|
|
26532
|
+
started: false
|
|
26533
|
+
};
|
|
26534
|
+
};
|
|
26535
|
+
const onPointerMove = (e) => {
|
|
26536
|
+
const pending = buttonPointerDragRef.current;
|
|
26537
|
+
if (!pending) return;
|
|
26538
|
+
if (pending.started) {
|
|
26539
|
+
e.preventDefault();
|
|
26540
|
+
clearTextSelection();
|
|
26541
|
+
const dragged = buttonCollectionDragRef.current;
|
|
26542
|
+
if (!dragged) return;
|
|
26543
|
+
refreshButtonDragVisuals(dragged, e.clientX, e.clientY);
|
|
26544
|
+
return;
|
|
26545
|
+
}
|
|
26546
|
+
const dx = e.clientX - pending.startX;
|
|
26547
|
+
const dy = e.clientY - pending.startY;
|
|
26548
|
+
if (dx * dx + dy * dy < THRESHOLD * THRESHOLD) return;
|
|
26549
|
+
e.preventDefault();
|
|
26550
|
+
pending.started = true;
|
|
26551
|
+
armFooterPressDrag();
|
|
26552
|
+
clearTextSelection();
|
|
26553
|
+
try {
|
|
26554
|
+
document.body.setPointerCapture(pending.pointerId);
|
|
26555
|
+
} catch {
|
|
26556
|
+
}
|
|
26557
|
+
if (linkPopoverOpenRef.current) setLinkPopoverRef.current(null);
|
|
26558
|
+
if (activeElRef.current) deactivateRef.current();
|
|
26559
|
+
ensureNavbarButtonCollection(pending.el, editContentRef.current);
|
|
26560
|
+
buttonCollectionDragRef.current = pending.el;
|
|
26561
|
+
lockFooterDuringDrag();
|
|
26562
|
+
setIsItemDragging(true);
|
|
26563
|
+
refreshButtonDragVisuals(pending.el, e.clientX, e.clientY);
|
|
26564
|
+
};
|
|
26565
|
+
const endPointerDrag = (e) => {
|
|
26566
|
+
const pending = buttonPointerDragRef.current;
|
|
26567
|
+
buttonPointerDragRef.current = null;
|
|
26568
|
+
try {
|
|
26569
|
+
if (document.body.hasPointerCapture(e.pointerId)) {
|
|
26570
|
+
document.body.releasePointerCapture(e.pointerId);
|
|
26571
|
+
}
|
|
26572
|
+
} catch {
|
|
26573
|
+
}
|
|
26574
|
+
if (!pending) return;
|
|
26575
|
+
if (!pending.started) {
|
|
26576
|
+
unlockFooterDragInteraction();
|
|
26577
|
+
return;
|
|
26578
|
+
}
|
|
26579
|
+
suppressNextClickRef.current = true;
|
|
26580
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
26581
|
+
persistButtonCollectionDrag(pending.el, e.clientX);
|
|
26582
|
+
};
|
|
26583
|
+
const blockSelectStart = (e) => {
|
|
26584
|
+
if (buttonCollectionDragRef.current || buttonPointerDragRef.current?.started) e.preventDefault();
|
|
26585
|
+
};
|
|
26586
|
+
document.addEventListener("pointerdown", onPointerDown, true);
|
|
26587
|
+
document.addEventListener("pointermove", onPointerMove, true);
|
|
26588
|
+
document.addEventListener("pointerup", endPointerDrag, true);
|
|
26589
|
+
document.addEventListener("pointercancel", endPointerDrag, true);
|
|
26590
|
+
document.addEventListener("selectstart", blockSelectStart, true);
|
|
26591
|
+
return () => {
|
|
26592
|
+
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
26593
|
+
document.removeEventListener("pointermove", onPointerMove, true);
|
|
26594
|
+
document.removeEventListener("pointerup", endPointerDrag, true);
|
|
26595
|
+
document.removeEventListener("pointercancel", endPointerDrag, true);
|
|
26596
|
+
document.removeEventListener("selectstart", blockSelectStart, true);
|
|
26597
|
+
};
|
|
26598
|
+
}, [isEditMode, persistButtonCollectionDrag, refreshButtonDragVisuals]);
|
|
24677
26599
|
(0, import_react19.useEffect)(() => {
|
|
24678
26600
|
const handler = (e) => {
|
|
24679
26601
|
if (e.data?.type !== "ow:request-schedule-config") return;
|
|
@@ -24714,7 +26636,7 @@ function OhhwellsBridge() {
|
|
|
24714
26636
|
postToParent2({
|
|
24715
26637
|
type: "ow:ready",
|
|
24716
26638
|
version: "1",
|
|
24717
|
-
bridgeVersion: "0.1.
|
|
26639
|
+
bridgeVersion: "0.1.121",
|
|
24718
26640
|
path: pathname,
|
|
24719
26641
|
nodes: collectEditableNodes(editContentRef.current),
|
|
24720
26642
|
sections
|
|
@@ -24793,12 +26715,12 @@ function OhhwellsBridge() {
|
|
|
24793
26715
|
return;
|
|
24794
26716
|
}
|
|
24795
26717
|
if (type !== "ow:logo-size-set") return;
|
|
24796
|
-
const
|
|
24797
|
-
if (!Number.isFinite(
|
|
24798
|
-
const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx:
|
|
26718
|
+
const px2 = Number(e.data.px);
|
|
26719
|
+
if (!Number.isFinite(px2)) return;
|
|
26720
|
+
const next = editorViewport === "mobile" ? { ...logoSizeDraft, mobilePx: px2, mobileFollowing: false } : {
|
|
24799
26721
|
...logoSizeDraft,
|
|
24800
|
-
desktopPx:
|
|
24801
|
-
mobilePx: logoSizeDraft.mobileFollowing ?
|
|
26722
|
+
desktopPx: px2,
|
|
26723
|
+
mobilePx: logoSizeDraft.mobileFollowing ? px2 : logoSizeDraft.mobilePx
|
|
24802
26724
|
};
|
|
24803
26725
|
setLogoSizeDraft(next);
|
|
24804
26726
|
persistLogoSizeDraft(session.placement, next);
|
|
@@ -24896,6 +26818,36 @@ function OhhwellsBridge() {
|
|
|
24896
26818
|
const handleDuplicateSelected = (0, import_react19.useCallback)(() => {
|
|
24897
26819
|
const selected = selectedElRef.current;
|
|
24898
26820
|
if (!selected || !isNavigationItem2(selected)) return;
|
|
26821
|
+
if (isCtaButton(selected)) {
|
|
26822
|
+
const id = buttonId(selected);
|
|
26823
|
+
if (!id) return;
|
|
26824
|
+
const tokens = tokensForButton(selected, true);
|
|
26825
|
+
if (!readAssignments(editContentRef.current)[id]) {
|
|
26826
|
+
const assignment = assignmentFor(selected, editContentRef.current, tokens);
|
|
26827
|
+
const assignments = withAssignment(editContentRef.current, id, assignment);
|
|
26828
|
+
editContentRef.current = {
|
|
26829
|
+
...editContentRef.current,
|
|
26830
|
+
[BUTTON_ASSIGNMENTS_KEY]: JSON.stringify(assignments)
|
|
26831
|
+
};
|
|
26832
|
+
applyButtonStyle(selected, assignment, tokens);
|
|
26833
|
+
}
|
|
26834
|
+
const result = duplicateButton(selected, editContentRef.current);
|
|
26835
|
+
if (!result) return;
|
|
26836
|
+
editContentRef.current = result.content;
|
|
26837
|
+
const copyHref = result.copy.getAttribute("data-ohw-href-key");
|
|
26838
|
+
const copyHrefVal = copyHref ? result.content[copyHref] : void 0;
|
|
26839
|
+
if (copyHref && copyHrefVal !== void 0) applyLinkByKey(copyHref, copyHrefVal);
|
|
26840
|
+
postToParent2({ type: "ow:change", nodes: result.nodes });
|
|
26841
|
+
enforceLinkHrefs();
|
|
26842
|
+
requestAnimationFrame(() => {
|
|
26843
|
+
selectRef.current(result.copy);
|
|
26844
|
+
requestAnimationFrame(() => {
|
|
26845
|
+
const el = selectedElRef.current;
|
|
26846
|
+
if (el?.isConnected) setToolbarRect(el.getBoundingClientRect());
|
|
26847
|
+
});
|
|
26848
|
+
});
|
|
26849
|
+
return;
|
|
26850
|
+
}
|
|
24899
26851
|
const hrefKey = selected.getAttribute("data-ohw-href-key");
|
|
24900
26852
|
if (!hrefKey) return;
|
|
24901
26853
|
const social = getSocialItem(selected);
|
|
@@ -25025,7 +26977,7 @@ function OhhwellsBridge() {
|
|
|
25025
26977
|
selectRef.current(result.anchor);
|
|
25026
26978
|
});
|
|
25027
26979
|
}
|
|
25028
|
-
}, [postToParent2]);
|
|
26980
|
+
}, [postToParent2, tokensForButton]);
|
|
25029
26981
|
const runPendingDeleteUndo = (0, import_react19.useCallback)(() => {
|
|
25030
26982
|
const pending = pendingDeleteUndoRef.current;
|
|
25031
26983
|
if (!pending) return false;
|
|
@@ -25037,6 +26989,38 @@ function OhhwellsBridge() {
|
|
|
25037
26989
|
const handleDeleteSelected = (0, import_react19.useCallback)(() => {
|
|
25038
26990
|
const selected = selectedElRef.current;
|
|
25039
26991
|
if (!selected) return false;
|
|
26992
|
+
if (isCtaButton(selected)) {
|
|
26993
|
+
if (!canDeleteButton(selected)) return false;
|
|
26994
|
+
const previousContent = editContentRef.current;
|
|
26995
|
+
const result = deleteButton(selected, previousContent);
|
|
26996
|
+
if (!result) return false;
|
|
26997
|
+
editContentRef.current = result.content;
|
|
26998
|
+
postToParent2({ type: "ow:change", nodes: result.nodes });
|
|
26999
|
+
const actionId = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `delete-${Date.now()}`;
|
|
27000
|
+
const restoreNodes = result.nodes.map((node) => ({
|
|
27001
|
+
key: node.key,
|
|
27002
|
+
text: previousContent[node.key] ?? ""
|
|
27003
|
+
}));
|
|
27004
|
+
pendingDeleteUndoRef.current = {
|
|
27005
|
+
actionId,
|
|
27006
|
+
restore: () => {
|
|
27007
|
+
result.undo();
|
|
27008
|
+
editContentRef.current = { ...editContentRef.current, ...Object.fromEntries(restoreNodes.map((node) => [node.key, node.text])) };
|
|
27009
|
+
postToParent2({ type: "ow:change", nodes: restoreNodes });
|
|
27010
|
+
syncButtonsFromContent(document, editContentRef.current);
|
|
27011
|
+
}
|
|
27012
|
+
};
|
|
27013
|
+
deselectRef.current();
|
|
27014
|
+
postToParent2({
|
|
27015
|
+
type: "ow:toast",
|
|
27016
|
+
title: "Button deleted",
|
|
27017
|
+
toastType: "success",
|
|
27018
|
+
actionLabel: "Undo",
|
|
27019
|
+
actionId,
|
|
27020
|
+
duration: 6e3
|
|
27021
|
+
});
|
|
27022
|
+
return true;
|
|
27023
|
+
}
|
|
25040
27024
|
return deleteSelectedNavFooterItem({
|
|
25041
27025
|
selected,
|
|
25042
27026
|
isTextEditing: Boolean(activeElRef.current),
|
|
@@ -25174,14 +27158,14 @@ function OhhwellsBridge() {
|
|
|
25174
27158
|
},
|
|
25175
27159
|
[postToParent2]
|
|
25176
27160
|
);
|
|
25177
|
-
return /* @__PURE__ */ (0,
|
|
25178
|
-
/* @__PURE__ */ (0,
|
|
25179
|
-
/* @__PURE__ */ (0,
|
|
25180
|
-
subdomain && !isEditMode && showBranding && /* @__PURE__ */ (0,
|
|
27161
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
27162
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { id: "ohw-loader", suppressHydrationWarning: true, style: { ...OHW_LOADER_STYLE, display: "none" }, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(OhwLoaderSpinner, {}) }),
|
|
27163
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("script", { suppressHydrationWarning: true, dangerouslySetInnerHTML: { __html: OHW_LOADER_PREHYDRATE_SCRIPT } }),
|
|
27164
|
+
subdomain && !isEditMode && showBranding && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(MadeWithOhhWells, {}),
|
|
25181
27165
|
bridgeRoot ? (0, import_react_dom5.createPortal)(
|
|
25182
|
-
/* @__PURE__ */ (0,
|
|
25183
|
-
/* @__PURE__ */ (0,
|
|
25184
|
-
isEditMode && /* @__PURE__ */ (0,
|
|
27166
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
27167
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ref: attachVisibleViewport, "data-ohw-visible-viewport": "", "aria-hidden": true }),
|
|
27168
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25185
27169
|
AiSectionOverlay,
|
|
25186
27170
|
{
|
|
25187
27171
|
postToParent: postToParent2,
|
|
@@ -25189,7 +27173,7 @@ function OhhwellsBridge() {
|
|
|
25189
27173
|
onSelectionChange: handleAiSectionSelectionChange
|
|
25190
27174
|
}
|
|
25191
27175
|
),
|
|
25192
|
-
isEditMode && /* @__PURE__ */ (0,
|
|
27176
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25193
27177
|
AiMediaStripOverlay,
|
|
25194
27178
|
{
|
|
25195
27179
|
postToParent: postToParent2,
|
|
@@ -25198,7 +27182,7 @@ function OhhwellsBridge() {
|
|
|
25198
27182
|
clearInteractionChromeRef
|
|
25199
27183
|
}
|
|
25200
27184
|
),
|
|
25201
|
-
isEditMode && /* @__PURE__ */ (0,
|
|
27185
|
+
isEditMode && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25202
27186
|
AiPricingCardOverlay,
|
|
25203
27187
|
{
|
|
25204
27188
|
postToParent: postToParent2,
|
|
@@ -25206,12 +27190,12 @@ function OhhwellsBridge() {
|
|
|
25206
27190
|
applyTreeLocalRef
|
|
25207
27191
|
}
|
|
25208
27192
|
),
|
|
25209
|
-
isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0,
|
|
27193
|
+
isSectionDragging && sectionDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25210
27194
|
"div",
|
|
25211
27195
|
{
|
|
25212
27196
|
className: "pointer-events-none fixed z-2147483646",
|
|
25213
27197
|
style: { left: slot.left, top: slot.y, width: slot.width, height: 3, transform: "translateY(-50%)" },
|
|
25214
|
-
children: /* @__PURE__ */ (0,
|
|
27198
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25215
27199
|
DropIndicator,
|
|
25216
27200
|
{
|
|
25217
27201
|
direction: "horizontal",
|
|
@@ -25222,7 +27206,7 @@ function OhhwellsBridge() {
|
|
|
25222
27206
|
},
|
|
25223
27207
|
`section-drop-${slot.insertIndex}-${i}`
|
|
25224
27208
|
)),
|
|
25225
|
-
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0,
|
|
27209
|
+
Object.entries(uploadingRects).map(([key, { rect, fadingOut }]) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25226
27210
|
MediaOverlay,
|
|
25227
27211
|
{
|
|
25228
27212
|
hover: { key, rect, elementType: "image", isDragOver: false, hasTextOverlap: false },
|
|
@@ -25233,7 +27217,7 @@ function OhhwellsBridge() {
|
|
|
25233
27217
|
},
|
|
25234
27218
|
`uploading-${key}`
|
|
25235
27219
|
)),
|
|
25236
|
-
mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ (0,
|
|
27220
|
+
mediaHover && !(mediaHover.key in uploadingRects) && mediaHover.key !== selectedMedia?.key && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25237
27221
|
MediaOverlay,
|
|
25238
27222
|
{
|
|
25239
27223
|
hover: mediaHover,
|
|
@@ -25244,7 +27228,7 @@ function OhhwellsBridge() {
|
|
|
25244
27228
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
25245
27229
|
}
|
|
25246
27230
|
),
|
|
25247
|
-
selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ (0,
|
|
27231
|
+
selectedMedia && !(selectedMedia.key in uploadingRects) && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25248
27232
|
MediaOverlay,
|
|
25249
27233
|
{
|
|
25250
27234
|
hover: selectedMedia,
|
|
@@ -25256,7 +27240,7 @@ function OhhwellsBridge() {
|
|
|
25256
27240
|
onVideoSettingsChange: handleVideoSettingsChange
|
|
25257
27241
|
}
|
|
25258
27242
|
),
|
|
25259
|
-
carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0,
|
|
27243
|
+
carouselHover && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25260
27244
|
CarouselOverlay,
|
|
25261
27245
|
{
|
|
25262
27246
|
hover: carouselHover,
|
|
@@ -25264,10 +27248,10 @@ function OhhwellsBridge() {
|
|
|
25264
27248
|
cueOnly: !!carouselHover.fullBleedSectionId && carouselHover.fullBleedSectionId !== selectedAiSectionId
|
|
25265
27249
|
}
|
|
25266
27250
|
),
|
|
25267
|
-
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0,
|
|
25268
|
-
siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0,
|
|
25269
|
-
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && /* @__PURE__ */ (0,
|
|
25270
|
-
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0,
|
|
27251
|
+
siblingHintRect && !linkPopover && !isItemDragging && siblingHintRects.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: siblingHintRect, state: "sibling-hint" }),
|
|
27252
|
+
siblingHintRects.length > 0 && !linkPopover && !isItemDragging && siblingHintRects.map((rect, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect, state: "sibling-hint" }, `sibling-hint-${i}`)),
|
|
27253
|
+
isItemDragging && draggedItemRect && selectedElRef.current !== footerDragRef.current?.draggedEl && selectedElRef.current !== navDragRef.current?.draggedEl && selectedElRef.current !== buttonCollectionDragRef.current && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: draggedItemRect, state: "dragging" }),
|
|
27254
|
+
isItemDragging && footerDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25271
27255
|
"div",
|
|
25272
27256
|
{
|
|
25273
27257
|
className: "pointer-events-none fixed z-2147483646",
|
|
@@ -25277,7 +27261,7 @@ function OhhwellsBridge() {
|
|
|
25277
27261
|
width: slot.width,
|
|
25278
27262
|
height: slot.height
|
|
25279
27263
|
},
|
|
25280
|
-
children: /* @__PURE__ */ (0,
|
|
27264
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25281
27265
|
DropIndicator,
|
|
25282
27266
|
{
|
|
25283
27267
|
direction: slot.direction,
|
|
@@ -25288,7 +27272,7 @@ function OhhwellsBridge() {
|
|
|
25288
27272
|
},
|
|
25289
27273
|
`footer-drop-${slot.direction}-${slot.columnIndex}-${slot.insertIndex}-${i}`
|
|
25290
27274
|
)),
|
|
25291
|
-
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0,
|
|
27275
|
+
isItemDragging && navDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25292
27276
|
"div",
|
|
25293
27277
|
{
|
|
25294
27278
|
className: "pointer-events-none fixed z-2147483646",
|
|
@@ -25298,7 +27282,7 @@ function OhhwellsBridge() {
|
|
|
25298
27282
|
width: slot.width,
|
|
25299
27283
|
height: slot.height
|
|
25300
27284
|
},
|
|
25301
|
-
children: /* @__PURE__ */ (0,
|
|
27285
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25302
27286
|
DropIndicator,
|
|
25303
27287
|
{
|
|
25304
27288
|
direction: slot.direction,
|
|
@@ -25309,10 +27293,31 @@ function OhhwellsBridge() {
|
|
|
25309
27293
|
},
|
|
25310
27294
|
`nav-drop-${slot.direction}-${slot.parentId ?? "root"}-${slot.insertIndex}-${i}`
|
|
25311
27295
|
)),
|
|
25312
|
-
|
|
25313
|
-
|
|
25314
|
-
|
|
25315
|
-
|
|
27296
|
+
isItemDragging && buttonDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
27297
|
+
"div",
|
|
27298
|
+
{
|
|
27299
|
+
className: "pointer-events-none fixed z-2147483646",
|
|
27300
|
+
style: {
|
|
27301
|
+
left: slot.left,
|
|
27302
|
+
top: slot.top,
|
|
27303
|
+
width: slot.width,
|
|
27304
|
+
height: slot.height
|
|
27305
|
+
},
|
|
27306
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
27307
|
+
DropIndicator,
|
|
27308
|
+
{
|
|
27309
|
+
direction: slot.direction,
|
|
27310
|
+
state: activeButtonDropIndex === i ? "dragActive" : "dragIdle",
|
|
27311
|
+
className: "!h-full !w-full"
|
|
27312
|
+
}
|
|
27313
|
+
)
|
|
27314
|
+
},
|
|
27315
|
+
`button-drop-${slot.direction}-${slot.insertIndex}-${i}`
|
|
27316
|
+
)),
|
|
27317
|
+
hoveredNavContainerRect && (toolbarVariant !== "select-frame" || isFooterFrameSelection) && !linkPopover && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: hoveredNavContainerRect, state: "hover" }),
|
|
27318
|
+
hoveredItemRect && !linkPopover && !hoveredNavContainerRect && !isItemDragging && hoveredItemElRef.current !== selectedElRef.current && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: hoveredItemRect, state: "hover" }),
|
|
27319
|
+
hoveredTextRect && !hoveredNavContainerRect && !hoveredItemRect && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ItemInteractionLayer, { rect: hoveredTextRect, state: "hover" }),
|
|
27320
|
+
formPickRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25316
27321
|
ItemInteractionLayer,
|
|
25317
27322
|
{
|
|
25318
27323
|
rect: formPickRect,
|
|
@@ -25320,13 +27325,13 @@ function OhhwellsBridge() {
|
|
|
25320
27325
|
itemDragSurface: false,
|
|
25321
27326
|
toolbarAlign: "left",
|
|
25322
27327
|
chromeGap: 24,
|
|
25323
|
-
toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0,
|
|
27328
|
+
toolbar: fieldPickRect ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
25324
27329
|
"div",
|
|
25325
27330
|
{
|
|
25326
27331
|
"data-ohw-form-toolbar": "",
|
|
25327
27332
|
className: "pointer-events-auto flex items-center gap-0.5 whitespace-nowrap rounded-lg border border-border bg-background p-1 shadow-md",
|
|
25328
27333
|
children: [
|
|
25329
|
-
/* @__PURE__ */ (0,
|
|
27334
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25330
27335
|
"button",
|
|
25331
27336
|
{
|
|
25332
27337
|
type: "button",
|
|
@@ -25334,11 +27339,11 @@ function OhhwellsBridge() {
|
|
|
25334
27339
|
className: "flex h-7 w-7 items-center justify-center rounded-md text-foreground transition-colors hover:bg-muted/80",
|
|
25335
27340
|
onClick: () => setFieldTypePickerOpen((open) => !open),
|
|
25336
27341
|
"data-ohw-add-field": "",
|
|
25337
|
-
children: /* @__PURE__ */ (0,
|
|
27342
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react20.Plus, { size: 15, "aria-hidden": true })
|
|
25338
27343
|
}
|
|
25339
27344
|
),
|
|
25340
|
-
/* @__PURE__ */ (0,
|
|
25341
|
-
/* @__PURE__ */ (0,
|
|
27345
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
27346
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
25342
27347
|
"button",
|
|
25343
27348
|
{
|
|
25344
27349
|
type: "button",
|
|
@@ -25354,11 +27359,11 @@ function OhhwellsBridge() {
|
|
|
25354
27359
|
});
|
|
25355
27360
|
},
|
|
25356
27361
|
children: [
|
|
25357
|
-
/* @__PURE__ */ (0,
|
|
27362
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react20.Settings, { size: 14, "aria-hidden": true }),
|
|
25358
27363
|
"Form settings",
|
|
25359
27364
|
formPickCount ? (
|
|
25360
27365
|
// Counter pill, per the design — not a text suffix.
|
|
25361
|
-
/* @__PURE__ */ (0,
|
|
27366
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25362
27367
|
"span",
|
|
25363
27368
|
{
|
|
25364
27369
|
"data-ohw-form-count": "",
|
|
@@ -25370,8 +27375,8 @@ function OhhwellsBridge() {
|
|
|
25370
27375
|
]
|
|
25371
27376
|
}
|
|
25372
27377
|
),
|
|
25373
|
-
/* @__PURE__ */ (0,
|
|
25374
|
-
/* @__PURE__ */ (0,
|
|
27378
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
27379
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex items-center rounded-md bg-muted/70 p-0.5", children: ["default", "success"].map((state) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25375
27380
|
"button",
|
|
25376
27381
|
{
|
|
25377
27382
|
type: "button",
|
|
@@ -25402,7 +27407,7 @@ function OhhwellsBridge() {
|
|
|
25402
27407
|
)
|
|
25403
27408
|
}
|
|
25404
27409
|
),
|
|
25405
|
-
formHoverRect && !isItemDragging && /* @__PURE__ */ (0,
|
|
27410
|
+
formHoverRect && !isItemDragging && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25406
27411
|
ItemInteractionLayer,
|
|
25407
27412
|
{
|
|
25408
27413
|
rect: formHoverRect,
|
|
@@ -25410,7 +27415,7 @@ function OhhwellsBridge() {
|
|
|
25410
27415
|
chromeGap: formHoverElRef.current && getFieldWrapper(formHoverElRef.current) ? 8 : 24
|
|
25411
27416
|
}
|
|
25412
27417
|
),
|
|
25413
|
-
fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0,
|
|
27418
|
+
fieldPickRect && fieldPickState && !isItemDragging && toolbarVariant !== "rich-text" && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25414
27419
|
ItemInteractionLayer,
|
|
25415
27420
|
{
|
|
25416
27421
|
rect: fieldPickRect,
|
|
@@ -25422,7 +27427,7 @@ function OhhwellsBridge() {
|
|
|
25422
27427
|
dragHandleLabel: "Reorder field",
|
|
25423
27428
|
onDragHandleDragStart: handleFieldDragStart,
|
|
25424
27429
|
onDragHandleDragEnd: handleFieldDragEnd,
|
|
25425
|
-
toolbar: /* @__PURE__ */ (0,
|
|
27430
|
+
toolbar: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25426
27431
|
FormFieldToolbar,
|
|
25427
27432
|
{
|
|
25428
27433
|
type: fieldPickState.type,
|
|
@@ -25435,12 +27440,12 @@ function OhhwellsBridge() {
|
|
|
25435
27440
|
)
|
|
25436
27441
|
}
|
|
25437
27442
|
),
|
|
25438
|
-
fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0,
|
|
27443
|
+
fieldDragging ? fieldDropSlots.map((slot, i) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25439
27444
|
"div",
|
|
25440
27445
|
{
|
|
25441
27446
|
className: "pointer-events-none fixed z-[2147483644]",
|
|
25442
27447
|
style: { top: slot.top, left: slot.left, width: slot.width },
|
|
25443
|
-
children: /* @__PURE__ */ (0,
|
|
27448
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25444
27449
|
DropIndicator,
|
|
25445
27450
|
{
|
|
25446
27451
|
direction: "horizontal",
|
|
@@ -25453,7 +27458,7 @@ function OhhwellsBridge() {
|
|
|
25453
27458
|
)) : null,
|
|
25454
27459
|
fieldTypePickerOpen && formPickRect ? (() => {
|
|
25455
27460
|
const toolbar = document.querySelector("[data-ohw-form-toolbar]")?.getBoundingClientRect();
|
|
25456
|
-
return /* @__PURE__ */ (0,
|
|
27461
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25457
27462
|
"div",
|
|
25458
27463
|
{
|
|
25459
27464
|
className: "pointer-events-none fixed z-[2147483645]",
|
|
@@ -25461,12 +27466,12 @@ function OhhwellsBridge() {
|
|
|
25461
27466
|
top: toolbar ? toolbar.bottom + 6 : formPickRect.top + 16,
|
|
25462
27467
|
left: toolbar ? toolbar.left : formPickRect.left + 24
|
|
25463
27468
|
},
|
|
25464
|
-
children: /* @__PURE__ */ (0,
|
|
27469
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(FieldTypePicker, { onPick: handleAddField })
|
|
25465
27470
|
}
|
|
25466
27471
|
);
|
|
25467
27472
|
})() : null,
|
|
25468
|
-
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0,
|
|
25469
|
-
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0,
|
|
27473
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isNavbarLinksContainer2(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(NavbarContainerChrome, { rect: toolbarRect, onAdd: handleAddTopLevelNavItem }),
|
|
27474
|
+
toolbarVariant === "select-frame" && toolbarRect && !linkPopover && !isItemDragging && !isFooterFrameSelection && selectedElRef.current && isFooterLinksContainer(selectedElRef.current) && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25470
27475
|
FooterContainerChrome,
|
|
25471
27476
|
{
|
|
25472
27477
|
rect: toolbarRect,
|
|
@@ -25474,13 +27479,17 @@ function OhhwellsBridge() {
|
|
|
25474
27479
|
addDisabled: !canAddFooterColumn()
|
|
25475
27480
|
}
|
|
25476
27481
|
),
|
|
25477
|
-
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0,
|
|
27482
|
+
toolbarRect && !linkPopover && (toolbarVariant === "link-action" || toolbarVariant === "select-frame" || toolbarVariant === "logo") && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25478
27483
|
ItemInteractionLayer,
|
|
25479
27484
|
{
|
|
25480
|
-
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected) ? draggedItemRect : toolbarRect,
|
|
27485
|
+
rect: isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected || selectedElRef.current === buttonCollectionDragRef.current) ? draggedItemRect : toolbarRect,
|
|
25481
27486
|
toolbarBelowRect: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanelRect(selectedElRef.current) : null,
|
|
25482
27487
|
toolbarBelowEl: selectedElRef.current && isNavigationItem2(selectedElRef.current) ? getOpenNavDropdownPanel(selectedElRef.current) : null,
|
|
25483
27488
|
elRef: glowElRef,
|
|
27489
|
+
hidden: isRectOutsideClip(
|
|
27490
|
+
isItemDragging && draggedItemRect && (footerDragRef.current?.wasSelected || navDragRef.current?.wasSelected || selectedElRef.current === buttonCollectionDragRef.current) ? draggedItemRect : toolbarRect,
|
|
27491
|
+
getIframeVisibleClip(parentScrollRef.current)
|
|
27492
|
+
),
|
|
25484
27493
|
state: isItemDragging ? "dragging" : selectedElRef.current && isNavigationItem2(selectedElRef.current) && getOpenNavDropdownPanel(selectedElRef.current) ? "active-bottom" : resolveItemInteractionState(toolbarRect, parentScrollRef.current),
|
|
25485
27494
|
showHandle: toolbarVariant === "link-action" && Boolean(reorderHrefKey) || toolbarVariant === "select-frame" && isFooterFrameSelection,
|
|
25486
27495
|
dragDisabled: reorderDragDisabled,
|
|
@@ -25490,18 +27499,25 @@ function OhhwellsBridge() {
|
|
|
25490
27499
|
onItemPointerDown: toolbarVariant === "logo" ? void 0 : handleItemChromePointerDown,
|
|
25491
27500
|
onItemClick: toolbarVariant === "logo" ? void 0 : handleItemChromeClick,
|
|
25492
27501
|
itemDragSurface: toolbarVariant !== "logo" && !isFooterFrameSelection && !selectedIsSocialsRow,
|
|
25493
|
-
toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0,
|
|
27502
|
+
toolbar: toolbarVariant === "link-action" && !isItemDragging || toolbarVariant === "select-frame" && (isFooterFrameSelection || selectedIsSocialsRow) && !isItemDragging ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25494
27503
|
ItemActionToolbar,
|
|
25495
27504
|
{
|
|
25496
27505
|
onEditLink: openLinkPopoverForSelected,
|
|
25497
27506
|
onStyle: () => {
|
|
25498
27507
|
const row = selectedElRef.current;
|
|
25499
27508
|
if (!row) return;
|
|
25500
|
-
|
|
27509
|
+
suppressNextClickRef.current = true;
|
|
27510
|
+
suppressClickUntilRef.current = Date.now() + 500;
|
|
27511
|
+
if (isCtaButton(row)) {
|
|
27512
|
+
if (floatingPanelRef.current?.kind === "button-style") closeFloatingPanelOnly();
|
|
27513
|
+
else openButtonStylePanel(row);
|
|
27514
|
+
return;
|
|
27515
|
+
}
|
|
27516
|
+
if (floatingPanelRef.current?.kind === "socials-display") closeFloatingPanelOnly();
|
|
25501
27517
|
else openSocialsDisplayPanel(row);
|
|
25502
27518
|
},
|
|
25503
|
-
showStyle: selectedIsSocialsRow,
|
|
25504
|
-
styleActive: floatingPanel?.kind === "socials-display",
|
|
27519
|
+
showStyle: selectedIsSocialsRow || selectedIsCta,
|
|
27520
|
+
styleActive: floatingPanel?.kind === "socials-display" || floatingPanel?.kind === "button-style",
|
|
25505
27521
|
onAddItem: handleAddChildItem,
|
|
25506
27522
|
onSelectParent: handleSelectParent,
|
|
25507
27523
|
onDuplicate: handleDuplicateSelected,
|
|
@@ -25512,11 +27528,11 @@ function OhhwellsBridge() {
|
|
|
25512
27528
|
})(),
|
|
25513
27529
|
editLinkDisabled: false,
|
|
25514
27530
|
moreDisabled: false,
|
|
25515
|
-
deleteDisabled: selectedElRef.current !== null && (() => {
|
|
27531
|
+
deleteDisabled: selectedElRef.current !== null && isCtaButton(selectedElRef.current) && !canDeleteButton(selectedElRef.current) || selectedElRef.current !== null && (() => {
|
|
25516
27532
|
const social = getSocialItem(selectedElRef.current);
|
|
25517
27533
|
return social ? !canRemoveSocialItem(social) : false;
|
|
25518
27534
|
})(),
|
|
25519
|
-
duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && (() => {
|
|
27535
|
+
duplicateDisabled: isFooterFrameSelection || selectedIsSocialsRow || selectedElRef.current !== null && isCtaButton(selectedElRef.current) && !canDuplicateButton(selectedElRef.current) || selectedElRef.current !== null && (() => {
|
|
25520
27536
|
const social = getSocialItem(selectedElRef.current);
|
|
25521
27537
|
const row = social ? findSocialsRow(social) : null;
|
|
25522
27538
|
return row ? !canAddSocialItem(row) : false;
|
|
@@ -25525,7 +27541,7 @@ function OhhwellsBridge() {
|
|
|
25525
27541
|
showAddItem: isFooterFrameSelection || selectedIsSocialsRow || !selectedIsCta && Boolean(
|
|
25526
27542
|
selectedElRef.current && isNavbarHrefKey(selectedElRef.current.getAttribute("data-ohw-href-key")) && !isNestedNavChild(selectedElRef.current)
|
|
25527
27543
|
),
|
|
25528
|
-
showMore:
|
|
27544
|
+
showMore: !selectedIsSocialsRow,
|
|
25529
27545
|
dropdownOpen: navDropdownPreviewOpen,
|
|
25530
27546
|
onDropdownOpenChange: handleNavDropdownOpenChange,
|
|
25531
27547
|
headingVisible: footerHeadingVisible,
|
|
@@ -25534,8 +27550,8 @@ function OhhwellsBridge() {
|
|
|
25534
27550
|
) : void 0
|
|
25535
27551
|
}
|
|
25536
27552
|
),
|
|
25537
|
-
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && !isRectOutsideClip(toolbarRect, getIframeVisibleClip(parentScrollRef.current)) && /* @__PURE__ */ (0,
|
|
25538
|
-
/* @__PURE__ */ (0,
|
|
27553
|
+
toolbarRect && toolbarVariant === "rich-text" && !linkPopover && !isRectOutsideClip(toolbarRect, getIframeVisibleClip(parentScrollRef.current)) && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
27554
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25539
27555
|
EditGlowChrome,
|
|
25540
27556
|
{
|
|
25541
27557
|
rect: toolbarRect,
|
|
@@ -25545,7 +27561,7 @@ function OhhwellsBridge() {
|
|
|
25545
27561
|
hideHandle: isItemDragging
|
|
25546
27562
|
}
|
|
25547
27563
|
),
|
|
25548
|
-
/* @__PURE__ */ (0,
|
|
27564
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25549
27565
|
FloatingToolbar,
|
|
25550
27566
|
{
|
|
25551
27567
|
rect: toolbarRect,
|
|
@@ -25558,7 +27574,7 @@ function OhhwellsBridge() {
|
|
|
25558
27574
|
}
|
|
25559
27575
|
)
|
|
25560
27576
|
] }),
|
|
25561
|
-
maxBadge && /* @__PURE__ */ (0,
|
|
27577
|
+
maxBadge && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
25562
27578
|
"div",
|
|
25563
27579
|
{
|
|
25564
27580
|
"data-ohw-max-badge": "",
|
|
@@ -25584,7 +27600,7 @@ function OhhwellsBridge() {
|
|
|
25584
27600
|
]
|
|
25585
27601
|
}
|
|
25586
27602
|
),
|
|
25587
|
-
toggleState && !linkPopover && /* @__PURE__ */ (0,
|
|
27603
|
+
toggleState && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25588
27604
|
StateToggle,
|
|
25589
27605
|
{
|
|
25590
27606
|
rect: toggleState.rect,
|
|
@@ -25593,15 +27609,15 @@ function OhhwellsBridge() {
|
|
|
25593
27609
|
onStateChange: handleStateChange
|
|
25594
27610
|
}
|
|
25595
27611
|
),
|
|
25596
|
-
sectionGap && !linkPopover && /* @__PURE__ */ (0,
|
|
27612
|
+
sectionGap && !linkPopover && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
25597
27613
|
"div",
|
|
25598
27614
|
{
|
|
25599
27615
|
"data-ohw-section-insert-line": "",
|
|
25600
27616
|
className: "fixed left-0 w-full z-2147483646 flex items-center pointer-events-none",
|
|
25601
27617
|
style: { top: sectionGap.y, transform: "translateY(-50%)" },
|
|
25602
27618
|
children: [
|
|
25603
|
-
/* @__PURE__ */ (0,
|
|
25604
|
-
/* @__PURE__ */ (0,
|
|
27619
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } }),
|
|
27620
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25605
27621
|
Badge,
|
|
25606
27622
|
{
|
|
25607
27623
|
className: "px-8 py-1 bg-bridge-primary hover:bg-bridge-primary text-primary-foreground text-xs font-medium shrink-0 rounded-full cursor-pointer pointer-events-auto",
|
|
@@ -25618,11 +27634,11 @@ function OhhwellsBridge() {
|
|
|
25618
27634
|
children: "Add Section"
|
|
25619
27635
|
}
|
|
25620
27636
|
),
|
|
25621
|
-
/* @__PURE__ */ (0,
|
|
27637
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1 bg-bridge-primary", style: { height: 3 } })
|
|
25622
27638
|
]
|
|
25623
27639
|
}
|
|
25624
27640
|
),
|
|
25625
|
-
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0,
|
|
27641
|
+
linkPopover && dialogPortalContainer ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25626
27642
|
LinkPopover,
|
|
25627
27643
|
{
|
|
25628
27644
|
panelRef: linkPopoverPanelRef,
|
|
@@ -25639,7 +27655,7 @@ function OhhwellsBridge() {
|
|
|
25639
27655
|
},
|
|
25640
27656
|
linkPopover.key
|
|
25641
27657
|
) : null,
|
|
25642
|
-
floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0,
|
|
27658
|
+
floatingPanel && floatingPanel.kind === "socials-display" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25643
27659
|
FloatingPanel,
|
|
25644
27660
|
{
|
|
25645
27661
|
open: true,
|
|
@@ -25649,7 +27665,7 @@ function OhhwellsBridge() {
|
|
|
25649
27665
|
onPositionChange: setFloatingPanelPos,
|
|
25650
27666
|
parentScroll: parentScrollSnap ?? parentScrollRef.current,
|
|
25651
27667
|
onClose: closeFloatingPanelOnly,
|
|
25652
|
-
children: /* @__PURE__ */ (0,
|
|
27668
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
25653
27669
|
SocialsDisplayPanel,
|
|
25654
27670
|
{
|
|
25655
27671
|
display: socialsDisplayFor(floatingPanel.row, editContentRef.current),
|
|
@@ -25660,7 +27676,48 @@ function OhhwellsBridge() {
|
|
|
25660
27676
|
}
|
|
25661
27677
|
)
|
|
25662
27678
|
}
|
|
25663
|
-
) : null
|
|
27679
|
+
) : null,
|
|
27680
|
+
floatingPanel && floatingPanel.kind === "button-style" ? (() => {
|
|
27681
|
+
const button = document.querySelector(
|
|
27682
|
+
`[data-ohw-href-key="${CSS.escape(floatingPanel.buttonId)}"]`
|
|
27683
|
+
);
|
|
27684
|
+
if (!button) return null;
|
|
27685
|
+
captureButtonOrigin(button);
|
|
27686
|
+
const tokens = tokensFromButton(button);
|
|
27687
|
+
const current = assignmentFor(button, editContentRef.current, tokens);
|
|
27688
|
+
void buttonStyleTick;
|
|
27689
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
27690
|
+
FloatingPanel,
|
|
27691
|
+
{
|
|
27692
|
+
open: true,
|
|
27693
|
+
title: floatingPanel.title,
|
|
27694
|
+
context: floatingPanel.context,
|
|
27695
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_lucide_react20.Brush, { className: "size-4 shrink-0", "aria-hidden": true }),
|
|
27696
|
+
position: floatingPanelPos,
|
|
27697
|
+
onPositionChange: setFloatingPanelPos,
|
|
27698
|
+
parentScroll: parentScrollSnap ?? parentScrollRef.current,
|
|
27699
|
+
onClose: closeFloatingPanelOnly,
|
|
27700
|
+
bodyClassName: "gap-5",
|
|
27701
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
27702
|
+
ButtonStylePanel,
|
|
27703
|
+
{
|
|
27704
|
+
variants: tokens.variants,
|
|
27705
|
+
sizes: tokens.sizes,
|
|
27706
|
+
variant: current.variant,
|
|
27707
|
+
size: current.size,
|
|
27708
|
+
slotBackground: previewSlotBackground(button),
|
|
27709
|
+
previewLabel: (button.querySelector(
|
|
27710
|
+
'[data-ohw-editable="text"], [data-ohw-editable="plain"]'
|
|
27711
|
+
)?.textContent ?? button.textContent ?? "Book Now").trim() || "Book Now",
|
|
27712
|
+
onVariant: (variant) => applySelectedButtonStyle({ variant }),
|
|
27713
|
+
onSize: (size) => applySelectedButtonStyle({ size })
|
|
27714
|
+
},
|
|
27715
|
+
floatingPanel.key
|
|
27716
|
+
)
|
|
27717
|
+
},
|
|
27718
|
+
floatingPanel.key
|
|
27719
|
+
);
|
|
27720
|
+
})() : null
|
|
25664
27721
|
] }),
|
|
25665
27722
|
bridgeRoot
|
|
25666
27723
|
) : null
|