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

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-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}'
2446
+ }),
2443
2447
  label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
2444
2448
  "div",
2445
2449
  {
@@ -2464,7 +2468,7 @@ 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
  {
@@ -2494,8 +2498,8 @@ function MediaStripBlock({ node, ctx, path }) {
2494
2498
  "a",
2495
2499
  {
2496
2500
  href: item.href,
2497
- target: item.linkTarget === "new-tab" ? "_blank" : void 0,
2498
- rel: item.linkTarget === "new-tab" ? "noopener noreferrer" : void 0,
2501
+ target: item.linkTarget === "same-tab" ? void 0 : "_blank",
2502
+ rel: item.linkTarget === "same-tab" ? void 0 : "noopener noreferrer",
2499
2503
  style: { display: "block", textDecoration: "none" },
2500
2504
  children: box
2501
2505
  },
@@ -10197,6 +10201,22 @@ function setMediaStripItemAlt(tree, index, alt) {
10197
10201
  return true;
10198
10202
  });
10199
10203
  }
10204
+ function setMediaStripItemLink(tree, index, link) {
10205
+ return withMediaStrip(tree, (block) => {
10206
+ const items = block.items;
10207
+ if (index < 0 || index >= items.length) return false;
10208
+ const item = { ...items[index] };
10209
+ if (link.href) {
10210
+ item.href = link.href;
10211
+ if (link.linkTarget) item.linkTarget = link.linkTarget;
10212
+ } else {
10213
+ delete item.href;
10214
+ delete item.linkTarget;
10215
+ }
10216
+ items[index] = item;
10217
+ return true;
10218
+ });
10219
+ }
10200
10220
 
10201
10221
  // src/ui/ai-section/AiMediaStripOverlay.tsx
10202
10222
  var import_jsx_runtime18 = require("react/jsx-runtime");
@@ -10402,6 +10422,88 @@ var TREATMENTS = [
10402
10422
  { value: "color", label: "Color" },
10403
10423
  { value: "grayscale", label: "Grayscale" }
10404
10424
  ];
10425
+ var HTTP_URL_RE = /^https?:\/\/\S+$/i;
10426
+ function LinkInput({ value, onCommit }) {
10427
+ const [draft, setDraft] = (0, import_react9.useState)(value);
10428
+ const [invalid, setInvalid] = (0, import_react9.useState)(false);
10429
+ (0, import_react9.useEffect)(() => {
10430
+ setDraft(value);
10431
+ setInvalid(false);
10432
+ }, [value]);
10433
+ const commit = () => {
10434
+ const next = draft.trim();
10435
+ if (next === value) return setInvalid(false);
10436
+ if (next && !HTTP_URL_RE.test(next)) return setInvalid(true);
10437
+ setInvalid(false);
10438
+ onCommit(next);
10439
+ };
10440
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
10441
+ "div",
10442
+ {
10443
+ style: {
10444
+ display: "flex",
10445
+ alignItems: "center",
10446
+ gap: 6,
10447
+ height: 28,
10448
+ padding: "0 12px",
10449
+ borderRadius: 999,
10450
+ background: "#ffffff",
10451
+ width: "100%",
10452
+ maxWidth: 260,
10453
+ boxSizing: "border-box",
10454
+ boxShadow: invalid ? "inset 0 0 0 1.5px #EF4444" : "none"
10455
+ },
10456
+ children: [
10457
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
10458
+ "span",
10459
+ {
10460
+ style: {
10461
+ flex: "0 0 auto",
10462
+ color: OHW_BLUE_DARK,
10463
+ fontSize: 10,
10464
+ fontWeight: 700,
10465
+ textTransform: "uppercase",
10466
+ letterSpacing: 0.4
10467
+ },
10468
+ children: "Link"
10469
+ }
10470
+ ),
10471
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
10472
+ "input",
10473
+ {
10474
+ type: "text",
10475
+ inputMode: "url",
10476
+ value: draft,
10477
+ onChange: (e) => setDraft(e.target.value),
10478
+ onBlur: commit,
10479
+ onKeyDown: (e) => {
10480
+ if (e.key === "Enter") e.currentTarget.blur();
10481
+ if (e.key === "Escape") {
10482
+ setDraft(value);
10483
+ setInvalid(false);
10484
+ e.currentTarget.blur();
10485
+ }
10486
+ },
10487
+ placeholder: "https://example.com",
10488
+ "aria-label": "Image link URL",
10489
+ "aria-invalid": invalid,
10490
+ style: {
10491
+ flex: 1,
10492
+ minWidth: 0,
10493
+ border: "none",
10494
+ outline: "none",
10495
+ background: "transparent",
10496
+ fontSize: 12,
10497
+ lineHeight: "16px",
10498
+ fontFamily: "Figtree, ui-sans-serif, system-ui, sans-serif",
10499
+ color: "#1f2937"
10500
+ }
10501
+ }
10502
+ )
10503
+ ]
10504
+ }
10505
+ );
10506
+ }
10405
10507
  function MediaStripToolbar({
10406
10508
  entry,
10407
10509
  index,
@@ -10413,6 +10515,7 @@ function MediaStripToolbar({
10413
10515
  onSetTreatment,
10414
10516
  onResize,
10415
10517
  onSetAlt,
10518
+ onSetLink,
10416
10519
  onAddItem,
10417
10520
  onRemoveItem,
10418
10521
  onChangeImage,
@@ -10422,10 +10525,12 @@ function MediaStripToolbar({
10422
10525
  const items = mediaStripItems(entry.tree);
10423
10526
  const itemCount = items.length;
10424
10527
  const currentAlt = items[index]?.alt ?? "";
10528
+ const currentHref = items[index]?.href ?? "";
10529
+ const currentTarget = items[index]?.linkTarget === "same-tab" ? "same-tab" : "new-tab";
10425
10530
  const slots = findMediaStripSlots(entry.tree);
10426
10531
  const variant = slots?.variant === "reel" ? "reel" : "logos";
10427
10532
  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";
10533
+ const hover = slots?.hover === "none" || slots?.hover === "lift" || slots?.hover === "zoom" || slots?.hover === "fade" ? slots.hover : "lift";
10429
10534
  const treatment = slots?.treatment === "color" || slots?.treatment === "grayscale" ? slots.treatment : variant === "logos" ? "grayscale" : "color";
10430
10535
  const sizeValue = variant === "logos" ? typeof slots?.logoMaxHeight === "number" ? slots.logoMaxHeight : 48 : typeof slots?.cardWidth === "number" ? slots.cardWidth : 240;
10431
10536
  const isMobile = window.innerWidth <= 480;
@@ -10476,6 +10581,11 @@ function MediaStripToolbar({
10476
10581
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "+", onClick: () => onResize(8) })
10477
10582
  ] }),
10478
10583
  /* @__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 }) }),
10584
+ /* @__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) }) }),
10585
+ currentHref && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: rowStyle, children: [
10586
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "New tab", active: currentTarget === "new-tab", onClick: () => onSetLink(currentHref, "new-tab") }),
10587
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "Same tab", active: currentTarget === "same-tab", onClick: () => onSetLink(currentHref, "same-tab") })
10588
+ ] }),
10479
10589
  /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: rowStyle, children: [
10480
10590
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "Change Image", onClick: onChangeImage }),
10481
10591
  /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Pill, { label: "+ Item", onClick: onAddItem }),
@@ -10671,6 +10781,12 @@ function AiMediaStripOverlay({
10671
10781
  onSetAlt: (alt) => {
10672
10782
  void runMutation(active.sectionId, (tree) => setMediaStripItemAlt(tree, active.index, alt));
10673
10783
  },
10784
+ onSetLink: (href, linkTarget) => {
10785
+ void runMutation(
10786
+ active.sectionId,
10787
+ (tree) => setMediaStripItemLink(tree, active.index, href ? { href, linkTarget } : {})
10788
+ );
10789
+ },
10674
10790
  onAddItem: () => {
10675
10791
  void requestAssetPick(postToParent2).then((picked) => {
10676
10792
  if (!picked) return;