@ohhwells/bridge 0.1.117-next.325 → 0.1.117-next.328

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
@@ -2439,7 +2439,11 @@ function MediaStripBlock({ node, ctx, path }) {
2439
2439
  const justify = align === "left" ? "flex-start" : align === "right" ? "flex-end" : "center";
2440
2440
  const label = str(slots.label);
2441
2441
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-ohw-media-strip": "", style: { display: "flex", flexDirection: "column", gap: AI_TREE_TOKENS.spacing6 }, children: [
2442
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: '[data-ohw-media-strip-item]{transition:transform 0.2s ease, opacity 0.2s ease}[data-ohw-media-strip-hover="lift"]:hover{transform:translateY(-4px)}[data-ohw-media-strip-hover="zoom"]:hover{transform:scale(1.05)}[data-ohw-media-strip-hover="fade"]:hover{opacity:0.75}' }),
2442
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", {
2443
+ // Host sites often style `a:hover{opacity}` globally — that would fade every linked item
2444
+ // whatever preset is chosen, so the anchors here opt out and only the preset applies.
2445
+ children: '[data-ohw-media-strip] a,[data-ohw-media-strip] a:hover{opacity:1}[data-ohw-media-strip-hover]{transition:transform 0.2s ease, opacity 0.2s ease}[data-ohw-media-strip-item]:hover>[data-ohw-media-strip-hover="lift"]{transform:translateY(-4px)}[data-ohw-media-strip-item]:hover>[data-ohw-media-strip-hover="zoom"]{transform:scale(1.05)}[data-ohw-media-strip-item]:hover>[data-ohw-media-strip-hover="fade"]{opacity:0.75}'
2446
+ }),
2443
2447
  label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2444
2448
  "div",
2445
2449
  {
@@ -2464,28 +2468,34 @@ function MediaStripBlock({ node, ctx, path }) {
2464
2468
  },
2465
2469
  children: items.map((item, i) => {
2466
2470
  const hasLink = typeof item.href === "string" && item.href.length > 0;
2467
- const hoverPreset = slots.hover === "none" || slots.hover === "lift" || slots.hover === "zoom" || slots.hover === "fade" ? slots.hover : hasLink ? "lift" : "none";
2471
+ const hoverPreset = !hasLink ? "none" : slots.hover === "none" || slots.hover === "lift" || slots.hover === "zoom" || slots.hover === "fade" ? slots.hover : "lift";
2468
2472
  const box = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2469
2473
  "div",
2470
2474
  {
2471
2475
  "data-ohw-media-strip-item": "",
2472
2476
  "data-ohw-media-strip-index": i,
2473
- "data-ohw-media-strip-hover": hoverPreset === "none" ? void 0 : hoverPreset,
2474
2477
  style: variant === "logos" ? { height: logoMaxHeight, width: "auto" } : { width: cardWidth, flexShrink: 0 },
2475
2478
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2476
- MediaBox,
2479
+ "div",
2477
2480
  {
2478
- refValue: item.assetId,
2479
- ctx,
2480
- aspect: variant === "reel" ? "9:16" : void 0,
2481
- radius: variant === "reel" ? AI_TREE_TOKENS.radiusCard : 4,
2482
- height: variant === "logos" ? logoMaxHeight : void 0,
2483
- editPath: `${path}.items.${i}.assetId`,
2484
- alt: item.alt,
2485
- fit: variant === "logos" ? "contain" : "cover",
2486
- grayscale: treatment === "grayscale",
2487
- fixedSize: variant === "logos",
2488
- genericImageEdit: false
2481
+ "data-ohw-media-strip-hover": hoverPreset === "none" ? void 0 : hoverPreset,
2482
+ style: { height: "100%" },
2483
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2484
+ MediaBox,
2485
+ {
2486
+ refValue: item.assetId,
2487
+ ctx,
2488
+ aspect: variant === "reel" ? "9:16" : void 0,
2489
+ radius: variant === "reel" ? AI_TREE_TOKENS.radiusCard : 4,
2490
+ height: variant === "logos" ? logoMaxHeight : void 0,
2491
+ editPath: `${path}.items.${i}.assetId`,
2492
+ alt: item.alt,
2493
+ fit: variant === "logos" ? "contain" : "cover",
2494
+ grayscale: treatment === "grayscale",
2495
+ fixedSize: variant === "logos",
2496
+ genericImageEdit: false
2497
+ }
2498
+ )
2489
2499
  }
2490
2500
  )
2491
2501
  }
@@ -2494,8 +2504,8 @@ function MediaStripBlock({ node, ctx, path }) {
2494
2504
  "a",
2495
2505
  {
2496
2506
  href: item.href,
2497
- target: item.linkTarget === "new-tab" ? "_blank" : void 0,
2498
- rel: item.linkTarget === "new-tab" ? "noopener noreferrer" : void 0,
2507
+ target: item.linkTarget === "same-tab" ? void 0 : "_blank",
2508
+ rel: item.linkTarget === "same-tab" ? void 0 : "noopener noreferrer",
2499
2509
  style: { display: "block", textDecoration: "none" },
2500
2510
  children: box
2501
2511
  },
@@ -10197,6 +10207,22 @@ function setMediaStripItemAlt(tree, index, alt) {
10197
10207
  return true;
10198
10208
  });
10199
10209
  }
10210
+ function setMediaStripItemLink(tree, index, link) {
10211
+ return withMediaStrip(tree, (block) => {
10212
+ const items = block.items;
10213
+ if (index < 0 || index >= items.length) return false;
10214
+ const item = { ...items[index] };
10215
+ if (link.href) {
10216
+ item.href = link.href;
10217
+ if (link.linkTarget) item.linkTarget = link.linkTarget;
10218
+ } else {
10219
+ delete item.href;
10220
+ delete item.linkTarget;
10221
+ }
10222
+ items[index] = item;
10223
+ return true;
10224
+ });
10225
+ }
10200
10226
 
10201
10227
  // src/ui/ai-section/AiMediaStripOverlay.tsx
10202
10228
  var import_jsx_runtime18 = require("react/jsx-runtime");
@@ -10402,6 +10428,88 @@ var TREATMENTS = [
10402
10428
  { value: "color", label: "Color" },
10403
10429
  { value: "grayscale", label: "Grayscale" }
10404
10430
  ];
10431
+ var HTTP_URL_RE = /^https?:\/\/\S+$/i;
10432
+ function LinkInput({ value, onCommit }) {
10433
+ const [draft, setDraft] = (0, import_react9.useState)(value);
10434
+ const [invalid, setInvalid] = (0, import_react9.useState)(false);
10435
+ (0, import_react9.useEffect)(() => {
10436
+ setDraft(value);
10437
+ setInvalid(false);
10438
+ }, [value]);
10439
+ const commit = () => {
10440
+ const next = draft.trim();
10441
+ if (next === value) return setInvalid(false);
10442
+ if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
10443
+ setInvalid(false);
10444
+ onCommit(next);
10445
+ };
10446
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
10447
+ "div",
10448
+ {
10449
+ style: {
10450
+ display: "flex",
10451
+ alignItems: "center",
10452
+ gap: 6,
10453
+ height: 28,
10454
+ padding: "0 12px",
10455
+ borderRadius: 999,
10456
+ background: "#ffffff",
10457
+ width: "100%",
10458
+ maxWidth: 260,
10459
+ boxSizing: "border-box",
10460
+ boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
10461
+ },
10462
+ children: [
10463
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
10464
+ "span",
10465
+ {
10466
+ style: {
10467
+ flex: "0 0 auto",
10468
+ color: OHW_BLUE_DARK,
10469
+ fontSize: 10,
10470
+ fontWeight: 700,
10471
+ textTransform: "uppercase",
10472
+ letterSpacing: 0.4
10473
+ },
10474
+ children: "Link"
10475
+ }
10476
+ ),
10477
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
10478
+ "input",
10479
+ {
10480
+ type: "text",
10481
+ inputMode: "url",
10482
+ value: draft,
10483
+ onChange: (e) => setDraft(e.target.value),
10484
+ onBlur: commit,
10485
+ onKeyDown: (e) => {
10486
+ if (e.key === "Enter") e.currentTarget.blur();
10487
+ if (e.key === "Escape") {
10488
+ setDraft(value);
10489
+ setInvalid(false);
10490
+ e.currentTarget.blur();
10491
+ }
10492
+ },
10493
+ placeholder: "https://example.com",
10494
+ "aria-label": "Image link URL",
10495
+ "aria-invalid": invalid,
10496
+ style: {
10497
+ flex: 1,
10498
+ minWidth: 0,
10499
+ border: "none",
10500
+ outline: "none",
10501
+ background: "transparent",
10502
+ fontSize: 12,
10503
+ lineHeight: "16px",
10504
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
10505
+ color: "#1f2937"
10506
+ }
10507
+ }
10508
+ )
10509
+ ]
10510
+ }
10511
+ );
10512
+ }
10405
10513
  function MediaStripToolbar({
10406
10514
  entry,
10407
10515
  index,
@@ -10413,6 +10521,7 @@ function MediaStripToolbar({
10413
10521
  onSetTreatment,
10414
10522
  onResize,
10415
10523
  onSetAlt,
10524
+ onSetLink,
10416
10525
  onAddItem,
10417
10526
  onRemoveItem,
10418
10527
  onChangeImage,
@@ -10422,10 +10531,12 @@ function MediaStripToolbar({
10422
10531
  const items = mediaStripItems(entry.tree);
10423
10532
  const itemCount = items.length;
10424
10533
  const currentAlt = items[index]?.alt ?? "";
10534
+ const currentHref = items[index]?.href ?? "";
10535
+ const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
10425
10536
  const slots = findMediaStripSlots(entry.tree);
10426
10537
  const variant = slots?.variant === "reel" ? "reel" : "logos";
10427
10538
  const align = slots?.align === "left" || slots?.align === "right" ? slots.align : "center";
10428
- const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "none";
10539
+ const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
10429
10540
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
10430
10541
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
10431
10542
  const isMobile = window.innerWidth <= 480;
@@ -10476,6 +10587,11 @@ function MediaStripToolbar({
10476
10587
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "+", onClick: () => onResize(8) })
10477
10588
  ] }),
10478
10589
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AltInput, { value: currentAlt, onCommit: onSetAlt }) }),
10590
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { display: "flex", justifyContent: "center", width: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LinkInput, { value: currentHref, onCommit: (href) => onSetLink(href, currentTarget) }) }),
10591
+ currentHref && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: rowStyle, children: [
10592
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
10593
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
10594
+ ] }),
10479
10595
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: rowStyle, children: [
10480
10596
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "Change Image", onClick: onChangeImage }),
10481
10597
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "+ Item", onClick: onAddItem }),
@@ -10671,6 +10787,12 @@ function AiMediaStripOverlay({
10671
10787
  onSetAlt: (alt) => {
10672
10788
  void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
10673
10789
  },
10790
+ onSetLink: (href, linkTarget) => {
10791
+ void runMutation(
10792
+ active.sectionId,
10793
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
10794
+ );
10795
+ },
10674
10796
  onAddItem: () => {
10675
10797
  void requestAssetPick(postToParent2).then((picked) => {
10676
10798
  if (!picked) return;