@ohhwells/bridge 0.1.139-next.382 → 0.1.139-next.385

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6558,6 +6558,13 @@ function applyIconNameToTree(tree, path, icon) {
6558
6558
  if (feature) {
6559
6559
  return setPricingCardFeatureIcon(tree, Number(feature[1]), Number(feature[2]), icon);
6560
6560
  }
6561
+ return rewriteIconSlot(tree, path, `lucide:${icon}`);
6562
+ }
6563
+ function applyIconUploadToTree(tree, path, mediaRef) {
6564
+ if (FEATURE_ICON_PATH.test(path)) return null;
6565
+ return rewriteIconSlot(tree, path, `icon:${mediaRef}`);
6566
+ }
6567
+ function rewriteIconSlot(tree, path, ref) {
6561
6568
  const segments = path.split(".");
6562
6569
  const slot = segments.pop();
6563
6570
  if (!slot || NODE_SEGMENT.test(slot)) return null;
@@ -6565,8 +6572,8 @@ function applyIconNameToTree(tree, path, icon) {
6565
6572
  const node = nodeAtPath(next, segments);
6566
6573
  if (!node) return null;
6567
6574
  const current = node.slots?.[slot];
6568
- if (typeof current !== "string" || !/^(lucide|simple):/.test(current)) return null;
6569
- node.slots = { ...node.slots, [slot]: `lucide:${icon}` };
6575
+ if (typeof current !== "string" || !/^(lucide|simple|icon):/.test(current)) return null;
6576
+ node.slots = { ...node.slots, [slot]: ref };
6570
6577
  return next;
6571
6578
  }
6572
6579
 
@@ -7953,7 +7960,7 @@ function MediaBox({
7953
7960
  onError
7954
7961
  }) {
7955
7962
  const url = refValue ? ctx.resolveMedia(refValue) : null;
7956
- const isIcon = /^(lucide|simple):/.test(refValue);
7963
+ const isIcon = /^(lucide|simple|icon):/.test(refValue);
7957
7964
  const aspectRatio = aspect && /^\d+:\d+$/.test(aspect) ? aspect.replace(":", " / ") : void 0;
7958
7965
  const editAttrs = ctx.keyFor && editPath && !isIcon ? {
7959
7966
  "data-ohw-key": ctx.keyFor(editPath),
@@ -7961,6 +7968,7 @@ function MediaBox({
7961
7968
  } : {};
7962
7969
  if (isIcon) {
7963
7970
  const Icon = refValue.startsWith("lucide:") ? lucideByName(refValue.slice(7)) : null;
7971
+ const uploadedIconUrl = refValue.startsWith("icon:") ? ctx.resolveMedia(refValue.slice(5)) : null;
7964
7972
  const iconEditAttrs = ctx.keyFor && editPath && genericImageEdit ? { "data-ohw-key": ctx.keyFor(editPath), "data-ohw-editable": "icon" } : {};
7965
7973
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
7966
7974
  "span",
@@ -7975,7 +7983,7 @@ function MediaBox({
7975
7983
  justifyContent: "center",
7976
7984
  color: ctx.brand.palette.dark
7977
7985
  },
7978
- children: Icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { size: 48, color: ctx.brand.palette.dark, strokeWidth: 1.5 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 24 }, children: "\u25C6" })
7986
+ children: uploadedIconUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: uploadedIconUrl, alt: "", style: { width: 48, height: 48, objectFit: "contain" } }) : Icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { size: 48, color: ctx.brand.palette.dark, strokeWidth: 1.5 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 24 }, children: "\u25C6" })
7979
7987
  }
7980
7988
  );
7981
7989
  }
@@ -17960,7 +17968,7 @@ function AiSectionOverlay({
17960
17968
 
17961
17969
  // src/ui/ai-section/AiMediaStripOverlay.tsx
17962
17970
  var import_react10 = require("react");
17963
- var import_lucide_react8 = require("lucide-react");
17971
+ var import_lucide_react9 = require("lucide-react");
17964
17972
 
17965
17973
  // src/lib/ai-media-strip-tree.ts
17966
17974
  var MEDIA_STRIP_ITEM_MIN = 1;
@@ -18074,14 +18082,6 @@ function setMediaStripItemAsset(tree, index, assetId) {
18074
18082
  return true;
18075
18083
  });
18076
18084
  }
18077
- function setMediaStripItemAlt(tree, index, alt) {
18078
- return withMediaStrip(tree, (block) => {
18079
- const items = block.items;
18080
- if (index < 0 || index >= items.length) return false;
18081
- items[index] = { ...items[index], alt };
18082
- return true;
18083
- });
18084
- }
18085
18085
  function setMediaStripItemLink(tree, index, link) {
18086
18086
  return withMediaStrip(tree, (block) => {
18087
18087
  const items = block.items;
@@ -18099,11 +18099,117 @@ function setMediaStripItemLink(tree, index, link) {
18099
18099
  });
18100
18100
  }
18101
18101
 
18102
- // src/ui/ai-section/AiMediaStripOverlay.tsx
18102
+ // src/ui/dialog.tsx
18103
+ var React9 = __toESM(require("react"), 1);
18104
+ var import_radix_ui6 = require("radix-ui");
18105
+ var import_lucide_react8 = require("lucide-react");
18103
18106
  var import_jsx_runtime19 = require("react/jsx-runtime");
18104
- var PRIMARY3 = "#0885FE";
18105
- var OHW_BLUE = `var(--ohw-primary, ${PRIMARY3})`;
18106
- var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY3}) 60%, #000000)`;
18107
+ function Dialog2({
18108
+ ...props
18109
+ }) {
18110
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
18111
+ }
18112
+ function DialogPortal({
18113
+ ...props
18114
+ }) {
18115
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
18116
+ }
18117
+ function DialogOverlay({
18118
+ className,
18119
+ ...props
18120
+ }) {
18121
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18122
+ import_radix_ui6.Dialog.Overlay,
18123
+ {
18124
+ "data-slot": "dialog-overlay",
18125
+ "data-ohw-link-modal-root": "",
18126
+ className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
18127
+ ...props
18128
+ }
18129
+ );
18130
+ }
18131
+ var DialogContent = React9.forwardRef(
18132
+ ({ className, children, showCloseButton = true, container, ...props }, ref) => {
18133
+ const positionMode = container ? "absolute" : "fixed";
18134
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(DialogPortal, { container: container ?? void 0, children: [
18135
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
18136
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
18137
+ import_radix_ui6.Dialog.Content,
18138
+ {
18139
+ ref,
18140
+ "data-slot": "dialog-content",
18141
+ className: cn(
18142
+ positionMode,
18143
+ "left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
18144
+ "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
18145
+ container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
18146
+ className
18147
+ ),
18148
+ onMouseDown: (e) => e.stopPropagation(),
18149
+ ...props,
18150
+ children: [
18151
+ children,
18152
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18153
+ import_radix_ui6.Dialog.Close,
18154
+ {
18155
+ type: "button",
18156
+ className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
18157
+ "aria-label": "Close",
18158
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.X, { size: 16, "aria-hidden": true })
18159
+ }
18160
+ ) : null
18161
+ ]
18162
+ }
18163
+ )
18164
+ ] });
18165
+ }
18166
+ );
18167
+ DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
18168
+ function DialogHeader({
18169
+ className,
18170
+ ...props
18171
+ }) {
18172
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
18173
+ }
18174
+ function DialogFooter({
18175
+ className,
18176
+ ...props
18177
+ }) {
18178
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18179
+ "div",
18180
+ {
18181
+ className: cn("flex items-center justify-end gap-2", className),
18182
+ ...props
18183
+ }
18184
+ );
18185
+ }
18186
+ var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18187
+ import_radix_ui6.Dialog.Title,
18188
+ {
18189
+ ref,
18190
+ className: cn(
18191
+ "text-lg font-semibold leading-none tracking-tight text-card-foreground",
18192
+ className
18193
+ ),
18194
+ ...props
18195
+ }
18196
+ ));
18197
+ DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
18198
+ var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18199
+ import_radix_ui6.Dialog.Description,
18200
+ {
18201
+ ref,
18202
+ className: cn("text-sm text-muted-foreground", className),
18203
+ ...props
18204
+ }
18205
+ ));
18206
+ DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
18207
+ var DialogClose = import_radix_ui6.Dialog.Close;
18208
+
18209
+ // src/ui/ai-section/AiMediaStripOverlay.tsx
18210
+ var import_jsx_runtime20 = require("react/jsx-runtime");
18211
+ var PRIMARY3 = "var(--ohw-primary, #0885FE)";
18212
+ var CHROME_SELECTOR = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
18107
18213
  function findMediaStripItemElement(sectionId, index) {
18108
18214
  const sectionEl = findByInstanceId(sectionId);
18109
18215
  if (!sectionEl) return null;
@@ -18113,14 +18219,35 @@ function findMediaStripItemElement(sectionId, index) {
18113
18219
  }
18114
18220
  return null;
18115
18221
  }
18116
- function readRect2(ref) {
18117
- const el = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18222
+ function itemRefFromTarget(target) {
18223
+ if (!(target instanceof Element)) return null;
18224
+ if (target.closest(CHROME_SELECTOR)) return null;
18225
+ const itemEl = target.closest("[data-ohw-media-strip-item]");
18226
+ if (!itemEl) return null;
18227
+ const sectionEl = itemEl.closest("[data-ohw-section]");
18228
+ const unit = sectionEl ? movableUnit(sectionEl) : null;
18229
+ const sectionId = unit ? instanceIdOf(unit) || null : null;
18230
+ const index = Number(itemEl.dataset.ohwMediaStripIndex);
18231
+ if (!sectionId || Number.isNaN(index)) return null;
18232
+ return { sectionId, index };
18233
+ }
18234
+ function sameRef(a, b) {
18235
+ return a?.sectionId === b?.sectionId && a?.index === b?.index;
18236
+ }
18237
+ function rectOf(el) {
18118
18238
  if (!el) return null;
18119
18239
  const r2 = el.getBoundingClientRect();
18120
18240
  if (r2.width <= 0 || r2.height <= 0) return null;
18121
18241
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
18122
18242
  }
18123
- function useLiveItemRect(ref) {
18243
+ function readRect2(ref) {
18244
+ return rectOf(ref && findMediaStripItemElement(ref.sectionId, ref.index));
18245
+ }
18246
+ function readStripRect(ref) {
18247
+ const item = ref && findMediaStripItemElement(ref.sectionId, ref.index);
18248
+ return rectOf(item?.closest("[data-ohw-media-strip]") ?? item);
18249
+ }
18250
+ function useLiveItemRect(ref, strip = false) {
18124
18251
  const [rect, setRect] = (0, import_react10.useState)(null);
18125
18252
  (0, import_react10.useEffect)(() => {
18126
18253
  if (!ref) {
@@ -18128,7 +18255,7 @@ function useLiveItemRect(ref) {
18128
18255
  return;
18129
18256
  }
18130
18257
  const update = () => {
18131
- const next = readRect2(ref);
18258
+ const next = strip ? readStripRect(ref) : readRect2(ref);
18132
18259
  setRect(
18133
18260
  (prev) => prev && next && prev.top === next.top && prev.left === next.left && prev.width === next.width && prev.height === next.height ? prev : next
18134
18261
  );
@@ -18143,9 +18270,49 @@ function useLiveItemRect(ref) {
18143
18270
  window.removeEventListener("resize", update);
18144
18271
  clearInterval(interval);
18145
18272
  };
18146
- }, [ref?.sectionId, ref?.index]);
18273
+ }, [ref?.sectionId, ref?.index, strip]);
18147
18274
  return rect;
18148
18275
  }
18276
+ var TOOLBAR_STRIP_GAP = 52;
18277
+ var TOOLBAR_STRIP_GAP_MOBILE = 42;
18278
+ var TOOLBAR_EDGE_MARGIN2 = 4;
18279
+ function StripToolbarSlot({ stripRect, children }) {
18280
+ const slotRef = (0, import_react10.useRef)(null);
18281
+ const [shift, setShift] = (0, import_react10.useState)(0);
18282
+ const centerX = stripRect.left + stripRect.width / 2;
18283
+ (0, import_react10.useLayoutEffect)(() => {
18284
+ const slot = slotRef.current;
18285
+ if (!slot) return;
18286
+ const clamp = () => {
18287
+ const w = slot.offsetWidth;
18288
+ if (w <= 0) return;
18289
+ const half = w / 2;
18290
+ const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
18291
+ setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
18292
+ };
18293
+ clamp();
18294
+ const ro = new ResizeObserver(clamp);
18295
+ ro.observe(slot);
18296
+ return () => ro.disconnect();
18297
+ }, [centerX, children]);
18298
+ const mobile = window.innerWidth <= 480;
18299
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18300
+ "div",
18301
+ {
18302
+ ref: slotRef,
18303
+ "data-ohw-bridge": "",
18304
+ "data-ohw-item-interaction": "",
18305
+ className: "pointer-events-auto fixed",
18306
+ style: {
18307
+ top: stripRect.top - (mobile ? TOOLBAR_STRIP_GAP_MOBILE : TOOLBAR_STRIP_GAP),
18308
+ left: centerX + shift,
18309
+ transform: "translate(-50%, -100%)",
18310
+ zIndex: 2147483645
18311
+ },
18312
+ children
18313
+ }
18314
+ );
18315
+ }
18149
18316
  function requestValidateTree(postToParent2, tree) {
18150
18317
  return new Promise((resolve) => {
18151
18318
  const id = `ai-validate-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -18182,116 +18349,72 @@ function requestAssetPick(postToParent2) {
18182
18349
  postToParent2({ type: "ow:asset-pick", id });
18183
18350
  });
18184
18351
  }
18185
- function Pill({
18352
+ function ToolbarAction({
18186
18353
  label,
18187
18354
  onClick,
18188
- disabled,
18189
- active
18355
+ disabled = false,
18356
+ active = false,
18357
+ children
18190
18358
  }) {
18191
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18192
- "button",
18193
- {
18194
- type: "button",
18195
- onClick,
18196
- disabled,
18197
- style: {
18198
- height: 28,
18199
- padding: "0 10px",
18200
- display: "inline-flex",
18201
- alignItems: "center",
18202
- gap: 4,
18203
- borderRadius: 999,
18204
- border: "none",
18205
- cursor: disabled ? "default" : "pointer",
18206
- background: active ? OHW_BLUE_DARK : "#ffffff",
18207
- color: active ? "#ffffff" : OHW_BLUE_DARK,
18208
- opacity: disabled ? 0.4 : 1,
18209
- fontSize: 12,
18210
- lineHeight: "16px",
18211
- fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18212
- whiteSpace: "nowrap",
18213
- flex: "0 0 auto"
18214
- },
18215
- children: label
18216
- }
18217
- );
18359
+ const button = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, active, onClick, className: "size-8", children });
18360
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
18361
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex", children: button }) : button }),
18362
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18363
+ ] });
18218
18364
  }
18219
- function AltInput({ value, onCommit }) {
18220
- const [draft, setDraft] = (0, import_react10.useState)(value);
18221
- (0, import_react10.useEffect)(() => setDraft(value), [value]);
18222
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
18223
- "div",
18224
- {
18225
- style: {
18226
- display: "flex",
18227
- alignItems: "center",
18228
- gap: 6,
18229
- height: 28,
18230
- padding: "0 12px",
18231
- borderRadius: 999,
18232
- background: "#ffffff",
18233
- width: "100%",
18234
- maxWidth: 260,
18235
- boxSizing: "border-box"
18236
- },
18237
- children: [
18238
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18239
- "span",
18240
- {
18241
- style: {
18242
- flex: "0 0 auto",
18243
- color: OHW_BLUE_DARK,
18244
- fontSize: 10,
18245
- fontWeight: 700,
18246
- textTransform: "uppercase",
18247
- letterSpacing: 0.4
18248
- },
18249
- children: "Alt"
18250
- }
18251
- ),
18252
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18253
- "input",
18365
+ function ToolbarSeparator() {
18366
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18367
+ }
18368
+ function OptionMenu({
18369
+ label,
18370
+ value,
18371
+ options,
18372
+ onChange
18373
+ }) {
18374
+ const current = options.find((o) => o.value === value) ?? options[0];
18375
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18376
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-xs text-muted-foreground", children: label }),
18377
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu, { modal: false, children: [
18378
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18379
+ "button",
18380
+ {
18381
+ type: "button",
18382
+ "aria-label": label,
18383
+ className: "inline-flex h-8 min-w-[76px] items-center gap-[7px] rounded-[6px] bg-transparent px-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted data-[state=open]:bg-muted",
18384
+ children: [
18385
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex-1 text-left", children: current.label }),
18386
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
18387
+ ]
18388
+ }
18389
+ ) }),
18390
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[132px] min-w-[132px] p-1", children: options.map((option) => {
18391
+ const selected = option.value === value;
18392
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18393
+ DropdownMenuItem,
18254
18394
  {
18255
- type: "text",
18256
- value: draft,
18257
- onChange: (e) => setDraft(e.target.value),
18258
- onBlur: () => {
18259
- if (draft !== value) onCommit(draft);
18260
- },
18261
- onKeyDown: (e) => {
18262
- if (e.key === "Enter") e.currentTarget.blur();
18263
- if (e.key === "Escape") {
18264
- setDraft(value);
18265
- e.currentTarget.blur();
18266
- }
18267
- },
18268
- placeholder: "Describe this image",
18269
- "aria-label": "Image alt text",
18270
- style: {
18271
- flex: 1,
18272
- minWidth: 0,
18273
- border: "none",
18274
- outline: "none",
18275
- background: "transparent",
18276
- fontSize: 12,
18277
- lineHeight: "16px",
18278
- fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18279
- color: "#1f2937"
18280
- }
18281
- }
18282
- )
18283
- ]
18284
- }
18285
- );
18395
+ role: "menuitemradio",
18396
+ "aria-checked": selected,
18397
+ onSelect: () => onChange(option.value),
18398
+ className: cn("grid grid-cols-[1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
18399
+ children: [
18400
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: option.label }),
18401
+ selected && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
18402
+ ]
18403
+ },
18404
+ option.value
18405
+ );
18406
+ }) })
18407
+ ] })
18408
+ ] });
18286
18409
  }
18287
18410
  var VARIANTS = [
18288
18411
  { value: "logos", label: "Logos" },
18289
18412
  { value: "reel", label: "Reel" }
18290
18413
  ];
18291
18414
  var ALIGNS = [
18292
- { value: "left", label: "Left" },
18293
- { value: "center", label: "Center" },
18294
- { value: "right", label: "Right" }
18415
+ { value: "left", label: "Align left", Icon: import_lucide_react9.AlignLeft },
18416
+ { value: "center", label: "Align center", Icon: import_lucide_react9.AlignCenter },
18417
+ { value: "right", label: "Align right", Icon: import_lucide_react9.AlignRight }
18295
18418
  ];
18296
18419
  var HOVERS = [
18297
18420
  { value: "none", label: "None" },
@@ -18299,104 +18422,104 @@ var HOVERS = [
18299
18422
  { value: "zoom", label: "Zoom" },
18300
18423
  { value: "fade", label: "Fade" }
18301
18424
  ];
18302
- var TREATMENTS = [
18303
- { value: "color", label: "Color" },
18304
- { value: "grayscale", label: "Grayscale" }
18305
- ];
18306
18425
  var HTTP_URL_RE = /^https?:\/\/\S+$/i;
18307
- function LinkInput({ value, onCommit }) {
18308
- const [draft, setDraft] = (0, import_react10.useState)(value);
18426
+ function LinkModal({
18427
+ href,
18428
+ linkTarget,
18429
+ onClose,
18430
+ onSave
18431
+ }) {
18432
+ const [draft, setDraft] = (0, import_react10.useState)(href);
18433
+ const [newTab, setNewTab] = (0, import_react10.useState)(linkTarget !== "same-tab");
18309
18434
  const [invalid, setInvalid] = (0, import_react10.useState)(false);
18310
- (0, import_react10.useEffect)(() => {
18311
- setDraft(value);
18312
- setInvalid(false);
18313
- }, [value]);
18314
- const commit = () => {
18435
+ const save = () => {
18315
18436
  const next = draft.trim();
18316
- if (next === value) return setInvalid(false);
18317
- if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
18318
- setInvalid(false);
18319
- onCommit(next);
18320
- };
18321
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
18322
- "div",
18323
- {
18324
- style: {
18325
- display: "flex",
18326
- alignItems: "center",
18327
- gap: 6,
18328
- height: 28,
18329
- padding: "0 12px",
18330
- borderRadius: 999,
18331
- background: "#ffffff",
18332
- width: "100%",
18333
- maxWidth: 260,
18334
- boxSizing: "border-box",
18335
- boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
18336
- },
18337
- children: [
18338
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18339
- "span",
18340
- {
18341
- style: {
18342
- flex: "0 0 auto",
18343
- color: OHW_BLUE_DARK,
18344
- fontSize: 10,
18345
- fontWeight: 700,
18346
- textTransform: "uppercase",
18347
- letterSpacing: 0.4
18348
- },
18349
- children: "Link"
18350
- }
18351
- ),
18352
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18353
- "input",
18354
- {
18355
- type: "text",
18356
- inputMode: "url",
18357
- value: draft,
18358
- onChange: (e) => setDraft(e.target.value),
18359
- onBlur: commit,
18360
- onKeyDown: (e) => {
18361
- if (e.key === "Enter") e.currentTarget.blur();
18362
- if (e.key === "Escape") {
18363
- setDraft(value);
18364
- setInvalid(false);
18365
- e.currentTarget.blur();
18366
- }
18367
- },
18368
- placeholder: "https://example.com",
18369
- "aria-label": "Image link URL",
18370
- "aria-invalid": invalid,
18371
- style: {
18372
- flex: 1,
18373
- minWidth: 0,
18374
- border: "none",
18375
- outline: "none",
18376
- background: "transparent",
18377
- fontSize: 12,
18378
- lineHeight: "16px",
18379
- fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
18380
- color: "#1f2937"
18381
- }
18382
- }
18383
- )
18384
- ]
18437
+ if (next && !HTTP_URL_RE.test(next)) {
18438
+ setInvalid(true);
18439
+ return;
18385
18440
  }
18386
- );
18441
+ onSave(next, newTab ? "new-tab" : "same-tab");
18442
+ onClose();
18443
+ };
18444
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Dialog2, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogContent, { "data-ohw-link-modal-root": "", className: "max-w-[400px] gap-4 p-5", children: [
18445
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DialogTitle, { className: "text-base", children: "Image link" }) }),
18446
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-3", children: [
18447
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18448
+ "input",
18449
+ {
18450
+ autoFocus: true,
18451
+ type: "text",
18452
+ inputMode: "url",
18453
+ value: draft,
18454
+ onChange: (e) => {
18455
+ setDraft(e.target.value);
18456
+ setInvalid(false);
18457
+ },
18458
+ onKeyDown: (e) => {
18459
+ if (e.key === "Enter") save();
18460
+ },
18461
+ placeholder: "https://example.com",
18462
+ "aria-label": "Image link URL",
18463
+ "aria-invalid": invalid,
18464
+ className: cn(
18465
+ "h-9 w-full rounded-[6px] border border-border bg-background px-3 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/70 focus:border-bridge-primary",
18466
+ invalid && "border-destructive focus:border-destructive"
18467
+ )
18468
+ }
18469
+ ),
18470
+ invalid && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-xs text-destructive", children: "Enter a full URL starting with http:// or https://" }),
18471
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("label", { className: "flex items-center gap-2 text-[13px] text-foreground", children: [
18472
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { type: "checkbox", checked: newTab, onChange: (e) => setNewTab(e.target.checked) }),
18473
+ "Open in new tab"
18474
+ ] })
18475
+ ] }),
18476
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DialogFooter, { children: [
18477
+ href && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18478
+ "button",
18479
+ {
18480
+ type: "button",
18481
+ onClick: () => {
18482
+ onSave("", "new-tab");
18483
+ onClose();
18484
+ },
18485
+ className: "mr-auto rounded-[6px] px-3 py-2 text-[13px] font-medium text-destructive transition-colors hover:bg-muted",
18486
+ children: "Remove link"
18487
+ }
18488
+ ),
18489
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18490
+ "button",
18491
+ {
18492
+ type: "button",
18493
+ onClick: onClose,
18494
+ className: "rounded-[6px] px-3 py-2 text-[13px] font-medium text-foreground transition-colors hover:bg-muted",
18495
+ children: "Cancel"
18496
+ }
18497
+ ),
18498
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18499
+ "button",
18500
+ {
18501
+ type: "button",
18502
+ onClick: save,
18503
+ className: "rounded-[6px] bg-bridge-primary px-3 py-2 text-[13px] font-medium text-primary-foreground transition-opacity hover:opacity-90",
18504
+ children: "Save"
18505
+ }
18506
+ )
18507
+ ] })
18508
+ ] }) });
18387
18509
  }
18388
18510
  function MediaStripToolbar({
18389
18511
  entry,
18390
18512
  index,
18391
18513
  pending,
18392
18514
  error,
18515
+ itemEditOn,
18516
+ onToggleItemEdit,
18393
18517
  onSetVariant,
18394
18518
  onSetAlign,
18395
18519
  onSetHover,
18396
18520
  onSetTreatment,
18397
18521
  onResize,
18398
- onSetAlt,
18399
- onSetLink,
18522
+ onOpenLink,
18400
18523
  onAddItem,
18401
18524
  onRemoveItem,
18402
18525
  onChangeImage,
@@ -18405,81 +18528,102 @@ function MediaStripToolbar({
18405
18528
  }) {
18406
18529
  const items = mediaStripItems(entry.tree);
18407
18530
  const itemCount = items.length;
18408
- const currentAlt = items[index]?.alt ?? "";
18409
- const currentHref = items[index]?.href ?? "";
18410
- const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
18411
18531
  const slots = findMediaStripSlots(entry.tree);
18412
18532
  const variant = slots?.variant === "reel" ? "reel" : "logos";
18413
18533
  const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
18414
18534
  const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
18415
18535
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
18416
18536
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18417
- const isMobile = window.innerWidth <= 480;
18418
- const rowStyle = isMobile ? {
18419
- display: "flex",
18420
- gap: 6,
18421
- flexWrap: "nowrap",
18422
- justifyContent: "center",
18423
- overflowX: "auto",
18424
- WebkitOverflowScrolling: "touch",
18425
- width: "100%",
18426
- scrollbarWidth: "none"
18427
- } : { display: "flex", gap: 6, flexWrap: "nowrap", justifyContent: "center" };
18428
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
18537
+ const mobile = window.innerWidth <= 480;
18538
+ const gatedLabel = (label) => itemEditOn ? label : "Turn on the star to edit this image";
18539
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18429
18540
  "div",
18430
18541
  {
18431
18542
  "data-ohw-bridge": "",
18432
18543
  "data-ohw-toolbar": "",
18433
18544
  onMouseDown: (e) => e.stopPropagation(),
18434
- style: {
18435
- display: "flex",
18436
- flexDirection: "column",
18437
- gap: 6,
18438
- alignItems: "center",
18439
- background: OHW_BLUE,
18440
- padding: 8,
18441
- borderRadius: 12,
18442
- boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
18443
- pointerEvents: pending ? "none" : "auto",
18444
- opacity: pending ? 0.6 : 1,
18445
- maxWidth: isMobile ? "calc(100vw - 24px)" : "none"
18446
- },
18545
+ className: cn("flex flex-col items-center gap-1.5 font-sans", pending && "pointer-events-none opacity-60"),
18546
+ style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
18447
18547
  children: [
18448
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: rowStyle, children: [
18449
- VARIANTS.map((v) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: v.label, active: variant === v.value, onClick: () => onSetVariant(v.value) }, v.value)),
18450
- ALIGNS.map((a) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: a.label, active: align === a.value, onClick: () => onSetAlign(a.value) }, a.value))
18451
- ] }),
18452
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: rowStyle, children: [
18453
- HOVERS.map((h) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: h.label, active: hover === h.value, onClick: () => onSetHover(h.value) }, h.value)),
18454
- TREATMENTS.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: t.label, active: treatment === t.value, onClick: () => onSetTreatment(t.value) }, t.value))
18455
- ] }),
18456
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
18457
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "\u2212", onClick: () => onResize(-8) }),
18458
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { style: { color: "#ffffff", fontSize: 12, minWidth: 34, textAlign: "center" }, children: [
18459
- sizeValue,
18460
- "px"
18461
- ] }),
18462
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "+", onClick: () => onResize(8) })
18463
- ] }),
18464
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
18465
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
18466
- currentHref && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: rowStyle, children: [
18467
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
18468
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
18469
- ] }),
18470
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: rowStyle, children: [
18471
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "Change Image", onClick: onChangeImage }),
18472
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "+ Item", onClick: onAddItem }),
18473
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "\u2212 Item", onClick: onRemoveItem, disabled: itemCount <= 1 })
18474
- ] }),
18475
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: rowStyle, children: [
18476
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "\u2190 Move", onClick: onMoveLeft, disabled: index <= 0 }),
18477
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Pill, { label: "\u2192 Move", onClick: onMoveRight, disabled: index >= itemCount - 1 })
18478
- ] }),
18479
- error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
18548
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
18549
+ "div",
18550
+ {
18551
+ className: cn(
18552
+ "flex items-center gap-1 rounded-[10px] border border-border bg-background p-1 whitespace-nowrap",
18553
+ "shadow-[0px_10px_15px_-3px_rgba(0,0,0,0.1),0px_4px_6px_-4px_rgba(0,0,0,0.1)]",
18554
+ mobile ? "flex-wrap justify-center" : "flex-nowrap"
18555
+ ),
18556
+ children: [
18557
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
18558
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18559
+ CustomToolbarButton,
18560
+ {
18561
+ type: "button",
18562
+ "aria-label": itemEditOn ? "Done editing this image" : "Edit this image",
18563
+ "aria-pressed": itemEditOn,
18564
+ onClick: onToggleItemEdit,
18565
+ className: "group size-8",
18566
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18567
+ import_lucide_react9.Star,
18568
+ {
18569
+ size: 16,
18570
+ fill: "currentColor",
18571
+ strokeWidth: 0,
18572
+ className: cn(
18573
+ "transition-colors",
18574
+ itemEditOn ? "text-[#f59e0b] group-hover:text-[#d97706]" : "text-[#d6d3d1] group-hover:text-[#fbbf24]"
18575
+ ),
18576
+ style: { pointerEvents: "none" }
18577
+ }
18578
+ )
18579
+ }
18580
+ ) }),
18581
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: itemEditOn ? "Done editing this image" : "Edit this image" })
18582
+ ] }),
18583
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
18584
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Change image"), onClick: onChangeImage, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Image, { size: 16, style: { pointerEvents: "none" } }) }),
18585
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Link"), onClick: onOpenLink, disabled: !itemEditOn, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Link, { size: 16, style: { pointerEvents: "none" } }) }),
18586
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Move left"), onClick: onMoveLeft, disabled: !itemEditOn || index <= 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ArrowLeft, { size: 16, style: { pointerEvents: "none" } }) }),
18587
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18588
+ ToolbarAction,
18589
+ {
18590
+ label: gatedLabel("Move right"),
18591
+ onClick: onMoveRight,
18592
+ disabled: !itemEditOn || index >= itemCount - 1,
18593
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ArrowRight, { size: 16, style: { pointerEvents: "none" } })
18594
+ }
18595
+ ),
18596
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: gatedLabel("Remove image"), onClick: onRemoveItem, disabled: !itemEditOn || itemCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ImageMinus, { size: 16, style: { pointerEvents: "none" } }) }),
18597
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
18598
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OptionMenu, { label: "Layout", value: variant, options: VARIANTS, onChange: onSetVariant }),
18599
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OptionMenu, { label: "Hover", value: hover, options: HOVERS, onChange: onSetHover }),
18600
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18601
+ ToolbarAction,
18602
+ {
18603
+ label: treatment === "grayscale" ? "Show in color" : "Show grayscale",
18604
+ active: treatment === "grayscale",
18605
+ onClick: () => onSetTreatment(treatment === "grayscale" ? "color" : "grayscale"),
18606
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Palette, { size: 16, style: { pointerEvents: "none" } })
18607
+ }
18608
+ ),
18609
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
18610
+ ALIGNS.map(({ value, label, Icon }) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label, active: align === value, onClick: () => onSetAlign(value), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { size: 16, style: { pointerEvents: "none" } }) }, value)),
18611
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
18612
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Smaller", onClick: () => onResize(-8), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) }),
18613
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "min-w-[40px] text-center text-xs tabular-nums text-muted-foreground", children: [
18614
+ sizeValue,
18615
+ "px"
18616
+ ] }),
18617
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Larger", onClick: () => onResize(8), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
18618
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
18619
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Add image", onClick: onAddItem, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ImagePlus, { size: 16, style: { pointerEvents: "none" } }) })
18620
+ ]
18621
+ }
18622
+ ),
18623
+ error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
18480
18624
  ]
18481
18625
  }
18482
- );
18626
+ ) });
18483
18627
  }
18484
18628
  function findMediaStripSlots(tree) {
18485
18629
  const stack = tree.rows.flatMap((row) => row.blocks);
@@ -18498,31 +18642,23 @@ function AiMediaStripOverlay({
18498
18642
  }) {
18499
18643
  const [hover, setHover] = (0, import_react10.useState)(null);
18500
18644
  const [active, setActive] = (0, import_react10.useState)(null);
18645
+ const [itemEditOn, setItemEditOn] = (0, import_react10.useState)(false);
18646
+ const [linkOpen, setLinkOpen] = (0, import_react10.useState)(false);
18501
18647
  const [pending, setPending] = (0, import_react10.useState)(false);
18502
18648
  const [error, setError] = (0, import_react10.useState)(null);
18503
18649
  const activeRef = (0, import_react10.useRef)(null);
18504
18650
  activeRef.current = active;
18651
+ const linkOpenRef = (0, import_react10.useRef)(false);
18652
+ linkOpenRef.current = linkOpen;
18505
18653
  (0, import_react10.useEffect)(() => {
18506
18654
  const onMove = (e) => {
18655
+ const ref = itemRefFromTarget(e.target);
18507
18656
  const t = e.target;
18508
- if (!(t instanceof HTMLElement)) return;
18509
- if (t.closest("[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review]")) {
18510
- return;
18511
- }
18512
- const itemEl = t.closest("[data-ohw-media-strip-item]");
18513
- if (!itemEl) {
18514
- setHover(null);
18515
- return;
18516
- }
18517
- const sectionEl = itemEl.closest("[data-ohw-section]");
18518
- const unit = sectionEl ? movableUnit(sectionEl) : null;
18519
- const sectionId = unit ? instanceIdOf(unit) || null : null;
18520
- const index = Number(itemEl.dataset.ohwMediaStripIndex);
18521
- if (!sectionId || Number.isNaN(index)) {
18522
- setHover(null);
18523
- return;
18524
- }
18525
- setHover({ sectionId, index });
18657
+ const overEditable = Boolean(t?.closest?.("[data-ohw-editable]"));
18658
+ setHover((prev) => {
18659
+ const next = ref && !overEditable ? ref : null;
18660
+ return sameRef(prev, next) ? prev : next;
18661
+ });
18526
18662
  };
18527
18663
  const onLeave = () => setHover(null);
18528
18664
  document.addEventListener("mousemove", onMove, { passive: true });
@@ -18534,23 +18670,25 @@ function AiMediaStripOverlay({
18534
18670
  }, []);
18535
18671
  (0, import_react10.useEffect)(() => {
18536
18672
  const onClick = (e) => {
18537
- const current = activeRef.current;
18538
- if (!current) return;
18539
18673
  const t = e.target;
18540
- if (!(t instanceof HTMLElement)) return;
18541
- if (t.closest("[data-ohw-item-interaction]")) return;
18542
- const itemEl = findMediaStripItemElement(current.sectionId, current.index);
18543
- if (itemEl && itemEl.contains(t)) return;
18544
- setActive(null);
18674
+ if (!(t instanceof Element)) return;
18675
+ if (t.closest(CHROME_SELECTOR)) return;
18676
+ const ref = itemRefFromTarget(t);
18677
+ if (sameRef(activeRef.current, ref)) return;
18678
+ if (ref) clearInteractionChromeRef.current();
18679
+ setItemEditOn(false);
18545
18680
  setError(null);
18681
+ setActive(ref);
18546
18682
  };
18547
18683
  document.addEventListener("click", onClick, true);
18548
18684
  return () => document.removeEventListener("click", onClick, true);
18549
- }, []);
18685
+ }, [clearInteractionChromeRef]);
18550
18686
  (0, import_react10.useEffect)(() => {
18551
18687
  const onBlur = () => {
18552
18688
  if (!activeRef.current) return;
18553
18689
  setActive(null);
18690
+ setItemEditOn(false);
18691
+ setLinkOpen(false);
18554
18692
  setError(null);
18555
18693
  };
18556
18694
  window.addEventListener("blur", onBlur);
@@ -18560,7 +18698,10 @@ function AiMediaStripOverlay({
18560
18698
  const onKeyDown = (e) => {
18561
18699
  if (e.key !== "Escape") return;
18562
18700
  if (!activeRef.current) return;
18701
+ if (linkOpenRef.current) return;
18702
+ if (document.querySelector('[data-ohw-more-menu][data-state="open"]')) return;
18563
18703
  setActive(null);
18704
+ setItemEditOn(false);
18564
18705
  setError(null);
18565
18706
  };
18566
18707
  document.addEventListener("keydown", onKeyDown);
@@ -18594,137 +18735,133 @@ function AiMediaStripOverlay({
18594
18735
  tree: nextTree,
18595
18736
  label: entry.label,
18596
18737
  media: extraMedia ? { ...entry.media, ...extraMedia } : entry.media,
18597
- ...entry.brand ? { brand: entry.brand } : {}
18738
+ ...entry.brand ? { brand: entry.brand } : {},
18739
+ // The user is already looking at the strip they just edited — recentering the viewport
18740
+ // on every edit reads as the section jumping around.
18741
+ skipScrollIntoView: true
18598
18742
  });
18599
18743
  return true;
18600
18744
  },
18601
18745
  [findEntry, postToParent2, applyTreeLocalRef]
18602
18746
  );
18603
18747
  const activeEntry = active ? findEntry(active.sectionId) : null;
18604
- const hoverHandleRect = useLiveItemRect(!active && hover ? hover : null);
18605
18748
  const activeItemRect = useLiveItemRect(active);
18606
- const TOOLBAR_APPROX_H = 170;
18607
- const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
18608
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
18609
- hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18610
- "button",
18611
- {
18612
- type: "button",
18613
- "data-ohw-toolbar": "",
18614
- onClick: () => {
18615
- clearInteractionChromeRef.current();
18616
- setActive(hover);
18617
- },
18618
- "aria-label": "Configure media item",
18619
- style: {
18620
- position: "fixed",
18621
- top: hoverHandleRect.top + 8,
18622
- left: hoverHandleRect.left + hoverHandleRect.width - 36,
18623
- width: 28,
18624
- height: 28,
18625
- borderRadius: 8,
18626
- border: `1.5px dashed ${PRIMARY3}`,
18627
- background: "#ffffff",
18628
- color: PRIMARY3,
18629
- display: "flex",
18630
- alignItems: "center",
18631
- justifyContent: "center",
18632
- cursor: "pointer",
18633
- zIndex: 2147483643,
18634
- fontSize: 14,
18635
- fontWeight: 700
18636
- },
18637
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.Star, { size: 14, style: { pointerEvents: "none" } })
18638
- }
18639
- ),
18640
- activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18641
- ItemInteractionLayer,
18642
- {
18643
- rect: activeItemRect,
18644
- state: toolbarState,
18645
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
18646
- MediaStripToolbar,
18647
- {
18648
- entry: activeEntry,
18649
- index: active.index,
18650
- pending,
18651
- error,
18652
- onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
18653
- onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
18654
- onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
18655
- onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
18656
- onResize: (delta) => {
18657
- const slots = findMediaStripSlots(activeEntry.tree);
18658
- const variant = slots?.variant === "reel" ? "reel" : "logos";
18659
- const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18660
- void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
18661
- },
18662
- onSetAlt: (alt) => {
18663
- void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
18664
- },
18665
- onSetLink: (href, linkTarget) => {
18749
+ const activeStripRect = useLiveItemRect(active, true);
18750
+ const hoverRect = useLiveItemRect(hover && !sameRef(hover, active) ? hover : null);
18751
+ const activeItems = activeEntry ? mediaStripItems(activeEntry.tree) : [];
18752
+ const activeItem = active ? activeItems[active.index] : void 0;
18753
+ const activeHref = activeItem?.href ?? "";
18754
+ const activeTarget = activeItem?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
18755
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
18756
+ hoverRect && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
18757
+ activeItemRect && activeStripRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
18758
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ItemInteractionLayer, { rect: activeItemRect, state: "active-top" }),
18759
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StripToolbarSlot, { stripRect: activeStripRect, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18760
+ MediaStripToolbar,
18761
+ {
18762
+ entry: activeEntry,
18763
+ index: active.index,
18764
+ pending,
18765
+ error,
18766
+ itemEditOn,
18767
+ onToggleItemEdit: () => setItemEditOn((on) => !on),
18768
+ onSetVariant: (variant) => runMutation(active.sectionId, (tree) => setMediaStripVariant(tree, variant)),
18769
+ onSetAlign: (align) => runMutation(active.sectionId, (tree) => setMediaStripAlign(tree, align)),
18770
+ onSetHover: (hoverPreset) => runMutation(active.sectionId, (tree) => setMediaStripHover(tree, hoverPreset)),
18771
+ onSetTreatment: (treatment) => runMutation(active.sectionId, (tree) => setMediaStripTreatment(tree, treatment)),
18772
+ onResize: (delta) => {
18773
+ const slots = findMediaStripSlots(activeEntry.tree);
18774
+ const variant = slots?.variant === "reel" ? "reel" : "logos";
18775
+ const current = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
18776
+ void runMutation(active.sectionId, (tree) => setMediaStripSizing(tree, current + delta));
18777
+ },
18778
+ onOpenLink: () => setLinkOpen(true),
18779
+ onAddItem: () => {
18780
+ void requestAssetPick(postToParent2).then((picked) => {
18781
+ if (!picked) return;
18782
+ const item = { assetId: picked.assetId, alt: "Logo" };
18666
18783
  void runMutation(
18667
18784
  active.sectionId,
18668
- (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
18669
- );
18670
- },
18671
- onAddItem: () => {
18672
- void requestAssetPick(postToParent2).then((picked) => {
18673
- if (!picked) return;
18674
- const item = { assetId: picked.assetId, alt: "Logo" };
18675
- void runMutation(
18676
- active.sectionId,
18677
- (tree) => addMediaStripItem(tree, item, active.index),
18678
- { [picked.assetId]: picked.url }
18679
- ).then((applied) => {
18680
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18681
- });
18785
+ (tree) => addMediaStripItem(tree, item, active.index),
18786
+ { [picked.assetId]: picked.url }
18787
+ ).then((applied) => {
18788
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18682
18789
  });
18683
- },
18684
- onChangeImage: () => {
18685
- void requestAssetPick(postToParent2).then((picked) => {
18686
- if (!picked) return;
18687
- void runMutation(
18688
- active.sectionId,
18689
- (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
18690
- { [picked.assetId]: picked.url }
18691
- );
18692
- });
18693
- },
18694
- onRemoveItem: () => {
18695
- void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
18696
- (applied) => {
18697
- if (applied) setActive(null);
18698
- }
18699
- );
18700
- },
18701
- onMoveLeft: () => {
18702
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
18703
- (applied) => {
18704
- if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
18705
- }
18706
- );
18707
- },
18708
- onMoveRight: () => {
18709
- void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
18710
- (applied) => {
18711
- if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18712
- }
18790
+ });
18791
+ },
18792
+ onChangeImage: () => {
18793
+ void requestAssetPick(postToParent2).then((picked) => {
18794
+ if (!picked) return;
18795
+ void runMutation(
18796
+ active.sectionId,
18797
+ (tree) => setMediaStripItemAsset(tree, active.index, picked.assetId),
18798
+ { [picked.assetId]: picked.url }
18713
18799
  );
18714
- }
18800
+ });
18801
+ },
18802
+ onRemoveItem: () => {
18803
+ void runMutation(active.sectionId, (tree) => removeMediaStripItem(tree, active.index)).then(
18804
+ (applied) => {
18805
+ if (applied) setActive(null);
18806
+ }
18807
+ );
18808
+ },
18809
+ onMoveLeft: () => {
18810
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, -1)).then(
18811
+ (applied) => {
18812
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index - 1 });
18813
+ }
18814
+ );
18815
+ },
18816
+ onMoveRight: () => {
18817
+ void runMutation(active.sectionId, (tree) => reorderMediaStripItem(tree, active.index, 1)).then(
18818
+ (applied) => {
18819
+ if (applied) setActive({ sectionId: active.sectionId, index: active.index + 1 });
18820
+ }
18821
+ );
18715
18822
  }
18716
- )
18717
- }
18718
- )
18823
+ }
18824
+ ) }),
18825
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18826
+ "div",
18827
+ {
18828
+ "data-ohw-bridge": "",
18829
+ "data-ohw-item-interaction": "",
18830
+ "aria-hidden": true,
18831
+ className: "pointer-events-none fixed rounded-[4px] px-[7px] py-[3px] font-sans text-[11px] font-medium leading-none text-primary-foreground whitespace-nowrap",
18832
+ style: {
18833
+ top: activeItemRect.top + activeItemRect.height + 10,
18834
+ left: activeItemRect.left - 5,
18835
+ background: PRIMARY3,
18836
+ zIndex: 2147483644
18837
+ },
18838
+ children: "Media item"
18839
+ }
18840
+ ),
18841
+ linkOpen && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18842
+ LinkModal,
18843
+ {
18844
+ href: activeHref,
18845
+ linkTarget: activeTarget,
18846
+ onClose: () => setLinkOpen(false),
18847
+ onSave: (href, linkTarget) => {
18848
+ void runMutation(
18849
+ active.sectionId,
18850
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
18851
+ );
18852
+ }
18853
+ }
18854
+ )
18855
+ ] })
18719
18856
  ] });
18720
18857
  }
18721
18858
 
18722
18859
  // src/ui/ai-section/AiPricingCardOverlay.tsx
18723
18860
  var import_react11 = require("react");
18724
- var import_lucide_react9 = require("lucide-react");
18725
- var import_jsx_runtime20 = require("react/jsx-runtime");
18861
+ var import_lucide_react10 = require("lucide-react");
18862
+ var import_jsx_runtime21 = require("react/jsx-runtime");
18726
18863
  var PRIMARY4 = "var(--ohw-primary, #0885FE)";
18727
- var CHROME_SELECTOR = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
18864
+ var CHROME_SELECTOR2 = "[data-ohw-toolbar], [data-ohw-edit-chrome], [data-ohw-item-interaction], [data-ohw-link-modal-root], [data-ohw-section-picker], [data-ohw-ai-review], [data-ohw-more-menu]";
18728
18865
  function findPricingCardElement(sectionId, index) {
18729
18866
  const sectionEl = findByInstanceId(sectionId);
18730
18867
  if (!sectionEl) return null;
@@ -18736,7 +18873,7 @@ function findPricingCardElement(sectionId, index) {
18736
18873
  }
18737
18874
  function cardRefFromTarget(target) {
18738
18875
  if (!(target instanceof Element)) return null;
18739
- if (target.closest(CHROME_SELECTOR)) return null;
18876
+ if (target.closest(CHROME_SELECTOR2)) return null;
18740
18877
  const cardEl = target.closest("[data-ohw-pricing-card]");
18741
18878
  if (!cardEl) return null;
18742
18879
  const sectionEl = cardEl.closest("[data-ohw-section]");
@@ -18746,21 +18883,21 @@ function cardRefFromTarget(target) {
18746
18883
  if (!sectionId || Number.isNaN(index)) return null;
18747
18884
  return { sectionId, index };
18748
18885
  }
18749
- function sameRef(a, b) {
18886
+ function sameRef2(a, b) {
18750
18887
  return a?.sectionId === b?.sectionId && a?.index === b?.index;
18751
18888
  }
18752
- function rectOf(el) {
18889
+ function rectOf2(el) {
18753
18890
  if (!el) return null;
18754
18891
  const r2 = el.getBoundingClientRect();
18755
18892
  if (r2.width <= 0 || r2.height <= 0) return null;
18756
18893
  return { top: r2.top, left: r2.left, width: r2.width, height: r2.height };
18757
18894
  }
18758
18895
  function readRect3(ref) {
18759
- return rectOf(ref && findPricingCardElement(ref.sectionId, ref.index));
18896
+ return rectOf2(ref && findPricingCardElement(ref.sectionId, ref.index));
18760
18897
  }
18761
18898
  function readGridRect(ref) {
18762
18899
  const card = ref && findPricingCardElement(ref.sectionId, ref.index);
18763
- return rectOf(card?.closest("[data-ohw-pricing-collection]") ?? card);
18900
+ return rectOf2(card?.closest("[data-ohw-pricing-collection]") ?? card);
18764
18901
  }
18765
18902
  function useLiveCardRect(ref, grid = false) {
18766
18903
  const [rect, setRect] = (0, import_react11.useState)(null);
@@ -18790,7 +18927,7 @@ function useLiveCardRect(ref, grid = false) {
18790
18927
  }
18791
18928
  var TOOLBAR_GRID_GAP = 52;
18792
18929
  var TOOLBAR_GRID_GAP_MOBILE = 42;
18793
- var TOOLBAR_EDGE_MARGIN2 = 4;
18930
+ var TOOLBAR_EDGE_MARGIN3 = 4;
18794
18931
  function GridToolbarSlot({ gridRect, children }) {
18795
18932
  const slotRef = (0, import_react11.useRef)(null);
18796
18933
  const [shift, setShift] = (0, import_react11.useState)(0);
@@ -18802,7 +18939,7 @@ function GridToolbarSlot({ gridRect, children }) {
18802
18939
  const w = slot.offsetWidth;
18803
18940
  if (w <= 0) return;
18804
18941
  const half = w / 2;
18805
- const clamped = Math.max(TOOLBAR_EDGE_MARGIN2 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN2 - half));
18942
+ const clamped = Math.max(TOOLBAR_EDGE_MARGIN3 + half, Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half));
18806
18943
  setShift((prev) => Math.abs(prev - (clamped - centerX)) < 0.5 ? prev : clamped - centerX);
18807
18944
  };
18808
18945
  clamp();
@@ -18811,7 +18948,7 @@ function GridToolbarSlot({ gridRect, children }) {
18811
18948
  return () => ro.disconnect();
18812
18949
  }, [centerX, children]);
18813
18950
  const mobile = window.innerWidth <= 480;
18814
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18951
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18815
18952
  "div",
18816
18953
  {
18817
18954
  ref: slotRef,
@@ -18846,7 +18983,7 @@ function requestValidateTree2(postToParent2, tree) {
18846
18983
  });
18847
18984
  }
18848
18985
  function StyleSwatch({ style }) {
18849
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
18986
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18850
18987
  "span",
18851
18988
  {
18852
18989
  "aria-hidden": true,
@@ -18860,35 +18997,35 @@ function StyleSwatch({ style }) {
18860
18997
  );
18861
18998
  }
18862
18999
  function ButtonGlyph() {
18863
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
18864
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
18865
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
19000
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "12", viewBox: "0 0 18 12", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19001
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "0.75", y: "0.75", width: "16.5", height: "10.5", rx: "3", stroke: "currentColor", strokeWidth: "1.5" }),
19002
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5.5 6H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
18866
19003
  ] });
18867
19004
  }
18868
19005
  function FeatureGlyph({ mode }) {
18869
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
18870
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
18871
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
18872
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
18873
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
18874
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
18875
- mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
19006
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", fill: "none", "aria-hidden": true, style: { pointerEvents: "none" }, children: [
19007
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "8", cy: "8", r: "7.25", stroke: "currentColor", strokeWidth: "1.5" }),
19008
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M5 8.2L7.2 10.3L11 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
19009
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "4.25", fill: "var(--ohw-background, #ffffff)", stroke: "var(--ohw-background, #ffffff)", strokeWidth: "1" }),
19010
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("circle", { cx: "13.5", cy: "13.5", r: "3.75", fill: "var(--ohw-background, #ffffff)", stroke: PRIMARY4, strokeWidth: "1" }),
19011
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M11.5 13.5H15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" }),
19012
+ mode === "add" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M13.5 11.5V15.5", stroke: PRIMARY4, strokeWidth: "1.5", strokeLinecap: "round" })
18876
19013
  ] });
18877
19014
  }
18878
- function ToolbarAction({
19015
+ function ToolbarAction2({
18879
19016
  label,
18880
19017
  onClick,
18881
19018
  disabled = false,
18882
19019
  children
18883
19020
  }) {
18884
- const button = /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
18885
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
18886
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex", children: button }) : button }),
18887
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
19021
+ const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CustomToolbarButton, { type: "button", "aria-label": label, disabled, onClick, className: "size-8", children });
19022
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19023
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: button }) : button }),
19024
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: label })
18888
19025
  ] });
18889
19026
  }
18890
- function ToolbarSeparator() {
18891
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
19027
+ function ToolbarSeparator2() {
19028
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { "aria-hidden": true, className: "mx-0.5 block h-6 w-px shrink-0 bg-border" });
18892
19029
  }
18893
19030
  function CardStyleMenu({
18894
19031
  value,
@@ -18896,7 +19033,7 @@ function CardStyleMenu({
18896
19033
  disabled = false
18897
19034
  }) {
18898
19035
  const current = PRICING_CARD_STYLES.find((s) => s.value === value) ?? PRICING_CARD_STYLES[0];
18899
- const trigger = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
19036
+ const trigger = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18900
19037
  "button",
18901
19038
  {
18902
19039
  type: "button",
@@ -18907,28 +19044,28 @@ function CardStyleMenu({
18907
19044
  disabled && "cursor-not-allowed opacity-40 hover:bg-transparent"
18908
19045
  ),
18909
19046
  children: [
18910
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StyleSwatch, { style: current.value }),
18911
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex-1 text-left", children: current.label }),
18912
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
19047
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: current.value }),
19048
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex-1 text-left", children: current.label }),
19049
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.ChevronDown, { size: 16, style: { pointerEvents: "none" } })
18913
19050
  ]
18914
19051
  }
18915
19052
  );
18916
19053
  if (disabled) {
18917
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18918
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
18919
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
18920
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex", children: trigger }) }),
18921
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
19054
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19055
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground opacity-50", children: "Card style" }),
19056
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19057
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "inline-flex", children: trigger }) }),
19058
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: "Mark as featured to edit card style" })
18922
19059
  ] })
18923
19060
  ] });
18924
19061
  }
18925
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
18926
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
18927
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(DropdownMenu, { modal: false, children: [
18928
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
18929
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
19062
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 pl-1.5", children: [
19063
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-xs text-muted-foreground", children: "Card style" }),
19064
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DropdownMenu, { modal: false, children: [
19065
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuTrigger, { asChild: true, children: trigger }),
19066
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DropdownMenuContent, { align: "end", sideOffset: 8, className: "w-[152px] min-w-[152px] p-1", children: PRICING_CARD_STYLES.map((style) => {
18930
19067
  const selected = style.value === value;
18931
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
19068
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18932
19069
  DropdownMenuItem,
18933
19070
  {
18934
19071
  role: "menuitemradio",
@@ -18936,9 +19073,9 @@ function CardStyleMenu({
18936
19073
  onSelect: () => onChange(style.value),
18937
19074
  className: cn("grid grid-cols-[18px_1fr_16px] gap-2 py-2 pl-2 pr-2 text-[13px]", selected && "bg-muted"),
18938
19075
  children: [
18939
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StyleSwatch, { style: style.value }),
18940
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: style.label }),
18941
- selected && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Check, { size: 16, className: "text-bridge-primary" })
19076
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(StyleSwatch, { style: style.value }),
19077
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: style.label }),
19078
+ selected && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Check, { size: 16, className: "text-bridge-primary" })
18942
19079
  ]
18943
19080
  },
18944
19081
  style.value
@@ -18968,7 +19105,7 @@ function PricingCardToolbar({
18968
19105
  const style = pricingCardStyle(entry.tree, index);
18969
19106
  const featuredTag = pricingCardFeaturedTag(entry.tree, index);
18970
19107
  const mobile = window.innerWidth <= 480;
18971
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
19108
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18972
19109
  "div",
18973
19110
  {
18974
19111
  "data-ohw-bridge": "",
@@ -18980,7 +19117,7 @@ function PricingCardToolbar({
18980
19117
  ),
18981
19118
  style: { maxWidth: mobile ? "calc(100vw - 24px)" : void 0 },
18982
19119
  children: [
18983
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
19120
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
18984
19121
  "div",
18985
19122
  {
18986
19123
  className: cn(
@@ -18989,8 +19126,8 @@ function PricingCardToolbar({
18989
19126
  mobile ? "flex-wrap justify-center" : "flex-nowrap"
18990
19127
  ),
18991
19128
  children: [
18992
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Tooltip, { children: [
18993
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19129
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
19130
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
18994
19131
  CustomToolbarButton,
18995
19132
  {
18996
19133
  type: "button",
@@ -18998,8 +19135,8 @@ function PricingCardToolbar({
18998
19135
  "aria-pressed": featuredTag,
18999
19136
  onClick: () => onSetFeaturedTag(!featuredTag),
19000
19137
  className: "group size-8",
19001
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19002
- import_lucide_react9.Star,
19138
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19139
+ import_lucide_react10.Star,
19003
19140
  {
19004
19141
  size: 16,
19005
19142
  fill: "currentColor",
@@ -19013,25 +19150,25 @@ function PricingCardToolbar({
19013
19150
  )
19014
19151
  }
19015
19152
  ) }),
19016
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19153
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipContent, { side: "bottom", sideOffset: 8, children: featuredTag ? "Unmark featured" : "Mark as featured" })
19017
19154
  ] }),
19018
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
19019
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19020
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
19021
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ButtonGlyph, {}) }),
19022
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "relative inline-flex", children: [
19023
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ButtonGlyph, {}),
19024
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19155
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator2, {}),
19156
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CardStyleMenu, { value: style, onChange: onSetStyle, disabled: !featuredTag }),
19157
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator2, {}),
19158
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Add button", onClick: onAddButton, disabled: buttonCount >= 2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}) }),
19159
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Remove button", onClick: onRemoveButton, disabled: buttonCount === 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "relative inline-flex", children: [
19160
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ButtonGlyph, {}),
19161
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Minus, { size: 10, strokeWidth: 2.5, className: "absolute -right-1.5 -top-1.5 rounded-full bg-background text-bridge-primary" })
19025
19162
  ] }) }),
19026
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FeatureGlyph, { mode: "add" }) }),
19027
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(FeatureGlyph, { mode: "remove" }) }),
19028
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarSeparator, {}),
19029
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
19030
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ToolbarAction, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.Minus, { size: 16, style: { pointerEvents: "none" } }) })
19163
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Add feature", onClick: onAddFeature, disabled: featureCount >= 10, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "add" }) }),
19164
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Remove feature", onClick: onRemoveFeature, disabled: featureCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FeatureGlyph, { mode: "remove" }) }),
19165
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarSeparator2, {}),
19166
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Add tier", onClick: onAddTier, disabled: collectionCount >= 4, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Plus, { size: 16, style: { pointerEvents: "none" } }) }),
19167
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ToolbarAction2, { label: "Remove tier", onClick: onRemoveTier, disabled: collectionCount <= 1, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Minus, { size: 16, style: { pointerEvents: "none" } }) })
19031
19168
  ]
19032
19169
  }
19033
19170
  ),
19034
- error && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19171
+ error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-[260px] rounded-md bg-background px-2 py-1 text-center text-[11px] text-destructive shadow-sm", children: error })
19035
19172
  ]
19036
19173
  }
19037
19174
  ) });
@@ -19065,7 +19202,7 @@ function AiPricingCardOverlay({
19065
19202
  const overEditable = Boolean(t?.closest?.("[data-ohw-editable], [data-ohw-role], a, button"));
19066
19203
  setHover((prev) => {
19067
19204
  const next = ref && !overEditable ? ref : null;
19068
- return sameRef(prev, next) ? prev : next;
19205
+ return sameRef2(prev, next) ? prev : next;
19069
19206
  });
19070
19207
  };
19071
19208
  const onLeave = () => setHover(null);
@@ -19080,10 +19217,10 @@ function AiPricingCardOverlay({
19080
19217
  const onClick = (e) => {
19081
19218
  const t = e.target;
19082
19219
  if (!(t instanceof Element)) return;
19083
- if (t.closest(CHROME_SELECTOR)) return;
19220
+ if (t.closest(CHROME_SELECTOR2)) return;
19084
19221
  const ref = cardRefFromTarget(t);
19085
- setActive((prev) => sameRef(prev, ref) ? prev : ref);
19086
- if (!ref || !sameRef(activeRef.current, ref)) setError(null);
19222
+ setActive((prev) => sameRef2(prev, ref) ? prev : ref);
19223
+ if (!ref || !sameRef2(activeRef.current, ref)) setError(null);
19087
19224
  };
19088
19225
  document.addEventListener("click", onClick, true);
19089
19226
  return () => document.removeEventListener("click", onClick, true);
@@ -19148,12 +19285,12 @@ function AiPricingCardOverlay({
19148
19285
  const activeEntry = active ? findEntry(active.sectionId) : null;
19149
19286
  const activeCardRect = useLiveCardRect(active);
19150
19287
  const activeGridRect = useLiveCardRect(active, true);
19151
- const hoverRect = useLiveCardRect(hover && !sameRef(hover, active) ? hover : null);
19152
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
19153
- hoverRect && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19154
- activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
19155
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19156
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19288
+ const hoverRect = useLiveCardRect(hover && !sameRef2(hover, active) ? hover : null);
19289
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19290
+ hoverRect && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: hoverRect, state: "hover" }),
19291
+ activeCardRect && activeGridRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19292
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ItemInteractionLayer, { rect: activeCardRect, state: "active-top" }),
19293
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GridToolbarSlot, { gridRect: activeGridRect, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19157
19294
  PricingCardToolbar,
19158
19295
  {
19159
19296
  entry: activeEntry,
@@ -19181,7 +19318,7 @@ function AiPricingCardOverlay({
19181
19318
  onRemoveFeature: () => runMutation(active.sectionId, (tree) => removePricingCardFeature(tree, active.index))
19182
19319
  }
19183
19320
  ) }),
19184
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
19321
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19185
19322
  "div",
19186
19323
  {
19187
19324
  "data-ohw-bridge": "",
@@ -19203,7 +19340,7 @@ function AiPricingCardOverlay({
19203
19340
 
19204
19341
  // src/ui/ai-section/AiVideoOverlay.tsx
19205
19342
  var import_react12 = require("react");
19206
- var import_lucide_react10 = require("lucide-react");
19343
+ var import_lucide_react11 = require("lucide-react");
19207
19344
 
19208
19345
  // src/lib/ai-video-tree.ts
19209
19346
  function resolveVideoBlock(tree, path) {
@@ -19274,10 +19411,10 @@ function extractYouTubeId(input) {
19274
19411
  }
19275
19412
 
19276
19413
  // src/ui/ai-section/AiVideoOverlay.tsx
19277
- var import_jsx_runtime21 = require("react/jsx-runtime");
19414
+ var import_jsx_runtime22 = require("react/jsx-runtime");
19278
19415
  var PRIMARY5 = "#0885FE";
19279
- var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY5})`;
19280
- var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19416
+ var OHW_BLUE = `var(--ohw-primary, ${PRIMARY5})`;
19417
+ var OHW_BLUE_DARK = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY5}) 60%, #000000)`;
19281
19418
  function findVideoBlockElement(sectionId, path) {
19282
19419
  const sectionEl = findByInstanceId(sectionId);
19283
19420
  if (!sectionEl) return null;
@@ -19337,12 +19474,12 @@ function requestValidateTree3(postToParent2, tree) {
19337
19474
  postToParent2({ type: "ow:ai-validate-tree-request", id, tree });
19338
19475
  });
19339
19476
  }
19340
- function Pill2({
19477
+ function Pill({
19341
19478
  label,
19342
19479
  onClick,
19343
19480
  disabled
19344
19481
  }) {
19345
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19482
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19346
19483
  "button",
19347
19484
  {
19348
19485
  type: "button",
@@ -19358,7 +19495,7 @@ function Pill2({
19358
19495
  border: "none",
19359
19496
  cursor: disabled ? "default" : "pointer",
19360
19497
  background: "#ffffff",
19361
- color: OHW_BLUE_DARK2,
19498
+ color: OHW_BLUE_DARK,
19362
19499
  opacity: disabled ? 0.4 : 1,
19363
19500
  fontSize: 12,
19364
19501
  lineHeight: "16px",
@@ -19401,8 +19538,8 @@ function VideoUrlInput({ value, onCommit }) {
19401
19538
  onCommit(id);
19402
19539
  }
19403
19540
  };
19404
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19405
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19541
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 4, width: "100%", maxWidth: 280 }, children: [
19542
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19406
19543
  "div",
19407
19544
  {
19408
19545
  style: {
@@ -19418,12 +19555,12 @@ function VideoUrlInput({ value, onCommit }) {
19418
19555
  boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
19419
19556
  },
19420
19557
  children: [
19421
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19558
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19422
19559
  "span",
19423
19560
  {
19424
19561
  style: {
19425
19562
  flex: "0 0 auto",
19426
- color: OHW_BLUE_DARK2,
19563
+ color: OHW_BLUE_DARK,
19427
19564
  fontSize: 10,
19428
19565
  lineHeight: "16px",
19429
19566
  fontWeight: 700,
@@ -19433,7 +19570,7 @@ function VideoUrlInput({ value, onCommit }) {
19433
19570
  children: "Video"
19434
19571
  }
19435
19572
  ),
19436
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19573
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19437
19574
  "input",
19438
19575
  {
19439
19576
  type: "text",
@@ -19470,7 +19607,7 @@ function VideoUrlInput({ value, onCommit }) {
19470
19607
  ]
19471
19608
  }
19472
19609
  ),
19473
- invalid && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
19610
+ invalid && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, textAlign: "center" }, children: "That doesn't look like a YouTube link \u2014 try pasting the video URL again." })
19474
19611
  ] });
19475
19612
  }
19476
19613
  function VideoToolbar({
@@ -19480,7 +19617,7 @@ function VideoToolbar({
19480
19617
  onSetVideoId,
19481
19618
  onRemove
19482
19619
  }) {
19483
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
19620
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19484
19621
  "div",
19485
19622
  {
19486
19623
  "data-ohw-bridge": "",
@@ -19492,7 +19629,7 @@ function VideoToolbar({
19492
19629
  gap: 6,
19493
19630
  alignItems: "center",
19494
19631
  width: 280,
19495
- background: OHW_BLUE2,
19632
+ background: OHW_BLUE,
19496
19633
  padding: 8,
19497
19634
  borderRadius: 12,
19498
19635
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -19500,9 +19637,9 @@ function VideoToolbar({
19500
19637
  opacity: pending ? 0.6 : 1
19501
19638
  },
19502
19639
  children: [
19503
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19504
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Pill2, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19505
- error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19640
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VideoUrlInput, { value: videoId, onCommit: onSetVideoId }),
19641
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Pill, { label: "Remove video", onClick: onRemove, disabled: !videoId }),
19642
+ error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19506
19643
  ]
19507
19644
  }
19508
19645
  );
@@ -19622,8 +19759,8 @@ function AiVideoOverlay({
19622
19759
  const activeBlockRect = useLiveBlockRect(active);
19623
19760
  const TOOLBAR_APPROX_H = 90;
19624
19761
  const toolbarState = activeBlockRect && activeBlockRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
19625
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
19626
- hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19762
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
19763
+ hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19627
19764
  "button",
19628
19765
  {
19629
19766
  type: "button",
@@ -19651,15 +19788,15 @@ function AiVideoOverlay({
19651
19788
  fontSize: 14,
19652
19789
  fontWeight: 700
19653
19790
  },
19654
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.Star, { size: 14, style: { pointerEvents: "none" } })
19791
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
19655
19792
  }
19656
19793
  ),
19657
- activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19794
+ activeBlockRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19658
19795
  ItemInteractionLayer,
19659
19796
  {
19660
19797
  rect: activeBlockRect,
19661
19798
  state: toolbarState,
19662
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
19799
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19663
19800
  VideoToolbar,
19664
19801
  {
19665
19802
  videoId: videoIdAt(activeEntry.tree, active.path),
@@ -19683,7 +19820,7 @@ function AiVideoOverlay({
19683
19820
 
19684
19821
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
19685
19822
  var import_react13 = require("react");
19686
- var import_lucide_react11 = require("lucide-react");
19823
+ var import_lucide_react12 = require("lucide-react");
19687
19824
 
19688
19825
  // src/lib/ai-carousel-tree.ts
19689
19826
  function isCarouselBlock(node) {
@@ -19734,10 +19871,10 @@ function setCarouselAutoplay(tree, on) {
19734
19871
  }
19735
19872
 
19736
19873
  // src/ui/ai-section/AiFadeCarouselOverlay.tsx
19737
- var import_jsx_runtime22 = require("react/jsx-runtime");
19874
+ var import_jsx_runtime23 = require("react/jsx-runtime");
19738
19875
  var PRIMARY6 = "#0885FE";
19739
- var OHW_BLUE3 = `var(--ohw-primary, ${PRIMARY6})`;
19740
- var OHW_BLUE_DARK3 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
19876
+ var OHW_BLUE2 = `var(--ohw-primary, ${PRIMARY6})`;
19877
+ var OHW_BLUE_DARK2 = `color-mix(in srgb, var(--ohw-primary, ${PRIMARY6}) 60%, #000000)`;
19741
19878
  function findCarouselItemElement(sectionId, index) {
19742
19879
  const sectionEl = findByInstanceId(sectionId);
19743
19880
  if (!sectionEl) return null;
@@ -19816,8 +19953,8 @@ function requestAssetPick2(postToParent2) {
19816
19953
  postToParent2({ type: "ow:asset-pick", id });
19817
19954
  });
19818
19955
  }
19819
- function Pill3({ label, onClick, disabled }) {
19820
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
19956
+ function Pill2({ label, onClick, disabled }) {
19957
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
19821
19958
  "button",
19822
19959
  {
19823
19960
  type: "button",
@@ -19833,7 +19970,7 @@ function Pill3({ label, onClick, disabled }) {
19833
19970
  border: "none",
19834
19971
  cursor: disabled ? "default" : "pointer",
19835
19972
  background: "#ffffff",
19836
- color: OHW_BLUE_DARK3,
19973
+ color: OHW_BLUE_DARK2,
19837
19974
  opacity: disabled ? 0.4 : 1,
19838
19975
  fontSize: 12,
19839
19976
  lineHeight: "16px",
@@ -19851,7 +19988,7 @@ function TogglePill({
19851
19988
  onToggle,
19852
19989
  disabled
19853
19990
  }) {
19854
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
19991
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
19855
19992
  "button",
19856
19993
  {
19857
19994
  type: "button",
@@ -19870,7 +20007,7 @@ function TogglePill({
19870
20007
  border: "none",
19871
20008
  cursor: disabled ? "default" : "pointer",
19872
20009
  background: "#ffffff",
19873
- color: OHW_BLUE_DARK3,
20010
+ color: OHW_BLUE_DARK2,
19874
20011
  opacity: disabled ? 0.4 : 1,
19875
20012
  fontSize: 12,
19876
20013
  lineHeight: "16px",
@@ -19880,7 +20017,7 @@ function TogglePill({
19880
20017
  },
19881
20018
  children: [
19882
20019
  label,
19883
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20020
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
19884
20021
  "span",
19885
20022
  {
19886
20023
  "aria-hidden": true,
@@ -19893,10 +20030,10 @@ function TogglePill({
19893
20030
  // Off is a grey track, not a washed-out blue: the pill's own white background already
19894
20031
  // carries the brand colour in the text, and a pale blue track next to it read as
19895
20032
  // "disabled control" rather than "switch that is off".
19896
- background: on ? OHW_BLUE_DARK3 : "#CBD5E1",
20033
+ background: on ? OHW_BLUE_DARK2 : "#CBD5E1",
19897
20034
  transition: "background 120ms ease"
19898
20035
  },
19899
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20036
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
19900
20037
  "span",
19901
20038
  {
19902
20039
  style: {
@@ -19925,7 +20062,7 @@ function CarouselSlideToolbar({
19925
20062
  onChangeImage,
19926
20063
  onToggleAutoplay
19927
20064
  }) {
19928
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
20065
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
19929
20066
  "div",
19930
20067
  {
19931
20068
  "data-ohw-bridge": "",
@@ -19936,7 +20073,7 @@ function CarouselSlideToolbar({
19936
20073
  flexDirection: "column",
19937
20074
  gap: 6,
19938
20075
  alignItems: "center",
19939
- background: OHW_BLUE3,
20076
+ background: OHW_BLUE2,
19940
20077
  padding: 8,
19941
20078
  borderRadius: 12,
19942
20079
  boxShadow: "0 8px 24px rgba(0,0,0,0.25)",
@@ -19948,11 +20085,11 @@ function CarouselSlideToolbar({
19948
20085
  pointerEvents: pending ? "none" : "auto"
19949
20086
  },
19950
20087
  children: [
19951
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
19952
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Pill3, { label: "Change Image", onClick: onChangeImage }),
19953
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
20088
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center" }, children: [
20089
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Pill2, { label: "Change Image", onClick: onChangeImage }),
20090
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(TogglePill, { label: "Autoplay", on: autoplay, onToggle: onToggleAutoplay })
19954
20091
  ] }),
19955
- error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
20092
+ error && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { color: "#FCA5A5", fontSize: 11, maxWidth: 220, textAlign: "center" }, children: error })
19956
20093
  ]
19957
20094
  }
19958
20095
  );
@@ -20092,8 +20229,8 @@ function AiFadeCarouselOverlay({
20092
20229
  const activeItemRect = useLiveItemRect2(active);
20093
20230
  const TOOLBAR_APPROX_H = 90;
20094
20231
  const toolbarState = activeItemRect && activeItemRect.top < TOOLBAR_APPROX_H ? "active-bottom" : "active-top";
20095
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
20096
- hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20232
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
20233
+ hoverHandleRect && hover && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20097
20234
  "button",
20098
20235
  {
20099
20236
  type: "button",
@@ -20122,10 +20259,10 @@ function AiFadeCarouselOverlay({
20122
20259
  fontSize: 14,
20123
20260
  fontWeight: 700
20124
20261
  },
20125
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react11.Star, { size: 14, style: { pointerEvents: "none" } })
20262
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react12.Star, { size: 14, style: { pointerEvents: "none" } })
20126
20263
  }
20127
20264
  ),
20128
- swapping && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20265
+ swapping && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20129
20266
  "div",
20130
20267
  {
20131
20268
  ref: skeletonRef,
@@ -20143,15 +20280,15 @@ function AiFadeCarouselOverlay({
20143
20280
  zIndex: 2147483646,
20144
20281
  pointerEvents: "none"
20145
20282
  },
20146
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("style", { children: MEDIA_SKELETON_CSS })
20283
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("style", { children: MEDIA_SKELETON_CSS })
20147
20284
  }
20148
20285
  ),
20149
- activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20286
+ activeItemRect && active && activeEntry && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20150
20287
  ItemInteractionLayer,
20151
20288
  {
20152
20289
  rect: activeItemRect,
20153
20290
  state: toolbarState,
20154
- toolbar: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
20291
+ toolbar: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20155
20292
  CarouselSlideToolbar,
20156
20293
  {
20157
20294
  pending,
@@ -20504,113 +20641,6 @@ function scrollToHashSectionWhenReady(behavior = "smooth") {
20504
20641
  // src/ui/link-modal/LinkPopover.tsx
20505
20642
  var import_react17 = require("react");
20506
20643
 
20507
- // src/ui/dialog.tsx
20508
- var React9 = __toESM(require("react"), 1);
20509
- var import_radix_ui6 = require("radix-ui");
20510
- var import_lucide_react12 = require("lucide-react");
20511
- var import_jsx_runtime23 = require("react/jsx-runtime");
20512
- function Dialog2({
20513
- ...props
20514
- }) {
20515
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_radix_ui6.Dialog.Root, { "data-slot": "dialog", ...props });
20516
- }
20517
- function DialogPortal({
20518
- ...props
20519
- }) {
20520
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_radix_ui6.Dialog.Portal, { ...props });
20521
- }
20522
- function DialogOverlay({
20523
- className,
20524
- ...props
20525
- }) {
20526
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20527
- import_radix_ui6.Dialog.Overlay,
20528
- {
20529
- "data-slot": "dialog-overlay",
20530
- "data-ohw-link-modal-root": "",
20531
- className: cn("fixed inset-0 z-[2147483646] bg-black/50", className),
20532
- ...props
20533
- }
20534
- );
20535
- }
20536
- var DialogContent = React9.forwardRef(
20537
- ({ className, children, showCloseButton = true, container, ...props }, ref) => {
20538
- const positionMode = container ? "absolute" : "fixed";
20539
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(DialogPortal, { container: container ?? void 0, children: [
20540
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DialogOverlay, { className: cn(positionMode, "inset-0") }),
20541
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
20542
- import_radix_ui6.Dialog.Content,
20543
- {
20544
- ref,
20545
- "data-slot": "dialog-content",
20546
- className: cn(
20547
- positionMode,
20548
- "left-1/2 top-1/2 z-[2147483647] flex w-full max-w-[448px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-visible",
20549
- "rounded-xl border border-border bg-background font-sans shadow-lg outline-none",
20550
- container ? "max-h-[calc(100%-32px)]" : "max-h-[calc(100vh-32px)]",
20551
- className
20552
- ),
20553
- onMouseDown: (e) => e.stopPropagation(),
20554
- ...props,
20555
- children: [
20556
- children,
20557
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20558
- import_radix_ui6.Dialog.Close,
20559
- {
20560
- type: "button",
20561
- className: "absolute right-[9px] top-[9px] rounded-sm p-1.5 text-foreground hover:bg-muted/50",
20562
- "aria-label": "Close",
20563
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react12.X, { size: 16, "aria-hidden": true })
20564
- }
20565
- ) : null
20566
- ]
20567
- }
20568
- )
20569
- ] });
20570
- }
20571
- );
20572
- DialogContent.displayName = import_radix_ui6.Dialog.Content.displayName;
20573
- function DialogHeader({
20574
- className,
20575
- ...props
20576
- }) {
20577
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn("flex flex-col gap-1.5", className), ...props });
20578
- }
20579
- function DialogFooter({
20580
- className,
20581
- ...props
20582
- }) {
20583
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20584
- "div",
20585
- {
20586
- className: cn("flex items-center justify-end gap-2", className),
20587
- ...props
20588
- }
20589
- );
20590
- }
20591
- var DialogTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20592
- import_radix_ui6.Dialog.Title,
20593
- {
20594
- ref,
20595
- className: cn(
20596
- "text-lg font-semibold leading-none tracking-tight text-card-foreground",
20597
- className
20598
- ),
20599
- ...props
20600
- }
20601
- ));
20602
- DialogTitle.displayName = import_radix_ui6.Dialog.Title.displayName;
20603
- var DialogDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
20604
- import_radix_ui6.Dialog.Description,
20605
- {
20606
- ref,
20607
- className: cn("text-sm text-muted-foreground", className),
20608
- ...props
20609
- }
20610
- ));
20611
- DialogDescription.displayName = import_radix_ui6.Dialog.Description.displayName;
20612
- var DialogClose = import_radix_ui6.Dialog.Close;
20613
-
20614
20644
  // src/ui/link-modal/LinkEditorPanel.tsx
20615
20645
  var import_lucide_react16 = require("lucide-react");
20616
20646
 
@@ -24614,7 +24644,7 @@ function applyVisibleViewport(el, parentScroll) {
24614
24644
  el.style.top = `${top}px`;
24615
24645
  el.style.height = `${height}px`;
24616
24646
  }
24617
- var TOOLBAR_EDGE_MARGIN3 = 4;
24647
+ var TOOLBAR_EDGE_MARGIN4 = 4;
24618
24648
  function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
24619
24649
  const isAbove = transform.includes("translateY(-100%)");
24620
24650
  let visualTop = isAbove ? top - approxH : top;
@@ -24641,8 +24671,8 @@ function clampToolbarToClip(top, transform, rect, clip, approxH, gap) {
24641
24671
  function clampToolbarLeft(centerX, toolbarWidth) {
24642
24672
  const half = toolbarWidth / 2;
24643
24673
  return Math.max(
24644
- TOOLBAR_EDGE_MARGIN3 + half,
24645
- Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN3 - half)
24674
+ TOOLBAR_EDGE_MARGIN4 + half,
24675
+ Math.min(centerX, window.innerWidth - TOOLBAR_EDGE_MARGIN4 - half)
24646
24676
  );
24647
24677
  }
24648
24678
  function calcToolbarPos(rect, parentScroll, toolbarW = 306) {
@@ -29497,12 +29527,16 @@ function OhhwellsBridge() {
29497
29527
  };
29498
29528
  const handleIconName = (e) => {
29499
29529
  if (e.data?.type !== "ow:icon-name") return;
29500
- const { key, icon } = e.data;
29501
- if (!key || typeof icon !== "string" || !/^[a-z0-9-]+$/.test(icon)) return;
29530
+ const { key, icon, url } = e.data;
29531
+ const isName = typeof icon === "string" && /^[a-z0-9-]+$/.test(icon);
29532
+ const isUpload = !isName && typeof url === "string" && /^https?:\/\/\S+$/i.test(url);
29533
+ if (!key || !isName && !isUpload) return;
29502
29534
  const state = parseAiSectionsState(aiSectionsRef.current);
29503
29535
  const entry = state.sections.find((s) => key.startsWith(aiSlotKeyPrefixFor(s.id)));
29504
29536
  if (!entry) return;
29505
- const nextTree = applyIconNameToTree(entry.tree, key.slice(aiSlotKeyPrefixFor(entry.id).length), icon);
29537
+ const path = key.slice(aiSlotKeyPrefixFor(entry.id).length);
29538
+ const uploadRef = isUpload ? `icon-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}` : null;
29539
+ const nextTree = uploadRef ? applyIconUploadToTree(entry.tree, path, uploadRef) : applyIconNameToTree(entry.tree, path, icon);
29506
29540
  if (!nextTree) return;
29507
29541
  void requestValidateTree5(postToParentRef.current, nextTree).then(({ ok }) => {
29508
29542
  if (!ok) return;
@@ -29512,7 +29546,7 @@ function OhhwellsBridge() {
29512
29546
  targetSectionId: entry.id,
29513
29547
  tree: nextTree,
29514
29548
  label: entry.label,
29515
- media: entry.media,
29549
+ media: uploadRef ? { ...entry.media, [uploadRef]: url } : entry.media,
29516
29550
  ...entry.brand ? { brand: entry.brand } : {},
29517
29551
  // The user is looking at the icon they just changed — no need to recenter on it.
29518
29552
  skipScrollIntoView: true