@flamingo-stack/openframe-frontend-core 0.0.388 → 0.0.389

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.
Files changed (95) hide show
  1. package/dist/{chunk-B4JRV4FB.cjs → chunk-2JCSORCJ.cjs} +26 -26
  2. package/dist/{chunk-B4JRV4FB.cjs.map → chunk-2JCSORCJ.cjs.map} +1 -1
  3. package/dist/{chunk-HIODHJCJ.cjs → chunk-3JQUNKWY.cjs} +15 -15
  4. package/dist/{chunk-HIODHJCJ.cjs.map → chunk-3JQUNKWY.cjs.map} +1 -1
  5. package/dist/{chunk-SENYQRPF.js → chunk-44Q3IXZM.js} +2 -2
  6. package/dist/{chunk-7CEJO3FE.js → chunk-4OLIDOLO.js} +2 -2
  7. package/dist/{chunk-YKPQINSZ.cjs → chunk-7MKU2EB4.cjs} +26 -26
  8. package/dist/{chunk-YKPQINSZ.cjs.map → chunk-7MKU2EB4.cjs.map} +1 -1
  9. package/dist/{chunk-ATKRYY4U.js → chunk-BJPQJNSC.js} +4 -4
  10. package/dist/{chunk-EQKTBIKH.js → chunk-CQXHHVMR.js} +2 -2
  11. package/dist/{chunk-ZVFDJ35S.cjs → chunk-EHTE3CTT.cjs} +37 -37
  12. package/dist/{chunk-ZVFDJ35S.cjs.map → chunk-EHTE3CTT.cjs.map} +1 -1
  13. package/dist/{chunk-VOPTCR5I.cjs → chunk-GNB5ERZP.cjs} +1011 -735
  14. package/dist/chunk-GNB5ERZP.cjs.map +1 -0
  15. package/dist/{chunk-VCRUAKOJ.js → chunk-IDWKP5H5.js} +521 -245
  16. package/dist/chunk-IDWKP5H5.js.map +1 -0
  17. package/dist/{chunk-UCQWQ7LM.js → chunk-JSFHTIKA.js} +2 -2
  18. package/dist/{chunk-BGYWTU2E.js → chunk-KA4WXCN3.js} +4 -4
  19. package/dist/{chunk-23BJ64AY.js → chunk-LFLFQ422.js} +2 -2
  20. package/dist/{chunk-FS4FVNOU.js → chunk-M6ODI2F5.js} +2 -2
  21. package/dist/{chunk-WIKFWION.cjs → chunk-MIEODAAV.cjs} +9 -9
  22. package/dist/{chunk-WIKFWION.cjs.map → chunk-MIEODAAV.cjs.map} +1 -1
  23. package/dist/{chunk-HQG5AY64.cjs → chunk-MPOP47ME.cjs} +12 -12
  24. package/dist/{chunk-HQG5AY64.cjs.map → chunk-MPOP47ME.cjs.map} +1 -1
  25. package/dist/{chunk-7UQ74ZJN.js → chunk-NULFIYK2.js} +2 -2
  26. package/dist/{chunk-ONXN77KP.cjs → chunk-OBKCQ7LA.cjs} +62 -62
  27. package/dist/{chunk-ONXN77KP.cjs.map → chunk-OBKCQ7LA.cjs.map} +1 -1
  28. package/dist/{chunk-KYN2GYUI.cjs → chunk-Q4YGG3CL.cjs} +31 -31
  29. package/dist/{chunk-KYN2GYUI.cjs.map → chunk-Q4YGG3CL.cjs.map} +1 -1
  30. package/dist/{chunk-SNFSLYVA.cjs → chunk-TQZLC3BQ.cjs} +5 -5
  31. package/dist/{chunk-SNFSLYVA.cjs.map → chunk-TQZLC3BQ.cjs.map} +1 -1
  32. package/dist/{chunk-6ZAQOYW4.cjs → chunk-VXJBE5NX.cjs} +59 -59
  33. package/dist/{chunk-6ZAQOYW4.cjs.map → chunk-VXJBE5NX.cjs.map} +1 -1
  34. package/dist/{chunk-35C3PUUN.js → chunk-WIMXB5EU.js} +4 -4
  35. package/dist/{chunk-DM3JIOFA.js → chunk-XGOX5UQ2.js} +4 -4
  36. package/dist/{chunk-EYQESL6X.cjs → chunk-ZFZAHLI4.cjs} +7 -7
  37. package/dist/{chunk-EYQESL6X.cjs.map → chunk-ZFZAHLI4.cjs.map} +1 -1
  38. package/dist/components/case-studies/index.cjs +8 -8
  39. package/dist/components/case-studies/index.js +2 -2
  40. package/dist/components/chat/index.cjs +2 -2
  41. package/dist/components/chat/index.js +1 -1
  42. package/dist/components/contact/index.cjs +3 -3
  43. package/dist/components/contact/index.js +2 -2
  44. package/dist/components/docs/index.cjs +5 -5
  45. package/dist/components/docs/index.js +4 -4
  46. package/dist/components/embeds/index.cjs +3 -3
  47. package/dist/components/embeds/index.js +2 -2
  48. package/dist/components/faq/index.cjs +3 -3
  49. package/dist/components/faq/index.js +2 -2
  50. package/dist/components/features/index.cjs +4 -2
  51. package/dist/components/features/index.cjs.map +1 -1
  52. package/dist/components/features/index.js +3 -1
  53. package/dist/components/features/video-bites-strip.d.ts +43 -4
  54. package/dist/components/features/video-bites-strip.d.ts.map +1 -1
  55. package/dist/components/features/video.d.ts +6 -0
  56. package/dist/components/features/video.d.ts.map +1 -1
  57. package/dist/components/help-center-pages/index.cjs +20 -20
  58. package/dist/components/help-center-pages/index.js +11 -11
  59. package/dist/components/index.cjs +122 -120
  60. package/dist/components/index.cjs.map +1 -1
  61. package/dist/components/index.js +11 -9
  62. package/dist/components/index.js.map +1 -1
  63. package/dist/components/navigation/index.cjs +2 -2
  64. package/dist/components/navigation/index.js +1 -1
  65. package/dist/components/onboarding-guides/index.cjs +5 -5
  66. package/dist/components/onboarding-guides/index.js +4 -4
  67. package/dist/components/related-content/index.cjs +3 -3
  68. package/dist/components/related-content/index.js +2 -2
  69. package/dist/components/tickets/index.cjs +5 -5
  70. package/dist/components/tickets/index.js +4 -4
  71. package/dist/components/ui/index.cjs +2 -2
  72. package/dist/components/ui/index.js +1 -1
  73. package/dist/index.cjs +4 -2
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.js +3 -1
  76. package/dist/types/case-study.d.ts +1 -1
  77. package/dist/types/case-study.d.ts.map +1 -1
  78. package/package.json +1 -1
  79. package/src/components/features/video-bites-strip.tsx +317 -72
  80. package/src/components/features/video.tsx +167 -37
  81. package/src/components/user-display.tsx +2 -2
  82. package/src/types/case-study.ts +1 -1
  83. package/dist/chunk-VCRUAKOJ.js.map +0 -1
  84. package/dist/chunk-VOPTCR5I.cjs.map +0 -1
  85. /package/dist/{chunk-SENYQRPF.js.map → chunk-44Q3IXZM.js.map} +0 -0
  86. /package/dist/{chunk-7CEJO3FE.js.map → chunk-4OLIDOLO.js.map} +0 -0
  87. /package/dist/{chunk-ATKRYY4U.js.map → chunk-BJPQJNSC.js.map} +0 -0
  88. /package/dist/{chunk-EQKTBIKH.js.map → chunk-CQXHHVMR.js.map} +0 -0
  89. /package/dist/{chunk-UCQWQ7LM.js.map → chunk-JSFHTIKA.js.map} +0 -0
  90. /package/dist/{chunk-BGYWTU2E.js.map → chunk-KA4WXCN3.js.map} +0 -0
  91. /package/dist/{chunk-23BJ64AY.js.map → chunk-LFLFQ422.js.map} +0 -0
  92. /package/dist/{chunk-FS4FVNOU.js.map → chunk-M6ODI2F5.js.map} +0 -0
  93. /package/dist/{chunk-7UQ74ZJN.js.map → chunk-NULFIYK2.js.map} +0 -0
  94. /package/dist/{chunk-35C3PUUN.js.map → chunk-WIMXB5EU.js.map} +0 -0
  95. /package/dist/{chunk-DM3JIOFA.js.map → chunk-XGOX5UQ2.js.map} +0 -0
@@ -139,6 +139,7 @@ import {
139
139
  UserPlusIcon,
140
140
  UserSearchIcon,
141
141
  VideoRecorderIcon,
142
+ VolumeXmarkIcon,
142
143
  WindowsLogoGreyIcon,
143
144
  WrenchIcon,
144
145
  XmarkAltIcon,
@@ -9396,7 +9397,7 @@ var TabsContent = React28.forwardRef(({ className, ...props }, ref) => /* @__PUR
9396
9397
  TabsContent.displayName = TabsPrimitive.Content.displayName;
9397
9398
 
9398
9399
  // src/components/features/video.tsx
9399
- import { useEffect as useEffect16, useMemo as useMemo12, useRef as useRef14, useState as useState21 } from "react";
9400
+ import { useCallback as useCallback13, useEffect as useEffect16, useMemo as useMemo12, useRef as useRef14, useState as useState21 } from "react";
9400
9401
  import MuxPlayer from "@mux/mux-player-react";
9401
9402
 
9402
9403
  // src/utils/fetch-priority.ts
@@ -9430,6 +9431,28 @@ if (typeof window !== "undefined" && typeof console !== "undefined") {
9430
9431
  };
9431
9432
  }
9432
9433
  }
9434
+ var userHasInteracted = false;
9435
+ var activationWaiters = /* @__PURE__ */ new Set();
9436
+ if (typeof window !== "undefined") {
9437
+ const w = window;
9438
+ if (!w.__VIDEO_ACTIVATION_TRACKED__) {
9439
+ w.__VIDEO_ACTIVATION_TRACKED__ = true;
9440
+ const markActivated = () => {
9441
+ userHasInteracted = true;
9442
+ activationWaiters.forEach((fn) => {
9443
+ try {
9444
+ fn();
9445
+ } catch {
9446
+ }
9447
+ });
9448
+ activationWaiters.clear();
9449
+ window.removeEventListener("pointerdown", markActivated, true);
9450
+ window.removeEventListener("keydown", markActivated, true);
9451
+ };
9452
+ window.addEventListener("pointerdown", markActivated, true);
9453
+ window.addEventListener("keydown", markActivated, true);
9454
+ }
9455
+ }
9433
9456
  var YT_HOSTS = /* @__PURE__ */ new Set([
9434
9457
  "youtube.com",
9435
9458
  "www.youtube.com",
@@ -9491,6 +9514,7 @@ function Video2(props) {
9491
9514
  loop: "loop" in props ? props.loop : void 0,
9492
9515
  chromeless: "chromeless" in props ? props.chromeless : void 0,
9493
9516
  playOnHover: "playOnHover" in props ? props.playOnHover : void 0,
9517
+ playWhenHovered: "playWhenHovered" in props ? props.playWhenHovered : void 0,
9494
9518
  centerControlsOnly: "centerControlsOnly" in props ? props.centerControlsOnly : void 0,
9495
9519
  className: props.className
9496
9520
  }
@@ -9526,45 +9550,99 @@ function FilePlayer({
9526
9550
  loop,
9527
9551
  chromeless,
9528
9552
  playOnHover,
9553
+ playWhenHovered,
9529
9554
  centerControlsOnly,
9530
9555
  className
9531
9556
  }) {
9532
9557
  const [isPlaying, setIsPlaying] = useState21(false);
9558
+ const [hoverMutedFallback, setHoverMutedFallback] = useState21(false);
9533
9559
  const hoverPlayerRef = useRef14(null);
9534
9560
  const hoverActiveRef = useRef14(false);
9535
9561
  const hoverGenerationRef = useRef14(0);
9536
- const handleHoverEnter = playOnHover ? () => {
9562
+ const activationWaiterRef = useRef14(null);
9563
+ const clearActivationWaiter = useCallback13(() => {
9564
+ if (activationWaiterRef.current) {
9565
+ activationWaiters.delete(activationWaiterRef.current);
9566
+ activationWaiterRef.current = null;
9567
+ }
9568
+ }, []);
9569
+ useEffect16(() => clearActivationWaiter, [clearActivationWaiter]);
9570
+ const startHoverPlayback = useCallback13(() => {
9537
9571
  hoverActiveRef.current = true;
9538
9572
  const generation = ++hoverGenerationRef.current;
9539
9573
  const el = hoverPlayerRef.current;
9540
9574
  if (!el) return;
9541
9575
  try {
9542
9576
  el.volume = 0.5;
9543
- el.muted = false;
9544
- const attempt = el.play?.();
9545
- if (attempt && typeof attempt.catch === "function") {
9546
- attempt.catch((err) => {
9577
+ if (userHasInteracted) {
9578
+ el.muted = false;
9579
+ el.play?.()?.catch?.((err) => {
9547
9580
  const name = err?.name;
9548
9581
  if (name === "NotAllowedError" && hoverActiveRef.current && generation === hoverGenerationRef.current) {
9549
9582
  try {
9550
9583
  el.muted = true;
9551
9584
  el.play?.()?.catch?.(() => {
9552
9585
  });
9586
+ setHoverMutedFallback(true);
9553
9587
  } catch {
9554
9588
  }
9555
9589
  }
9556
9590
  });
9591
+ } else {
9592
+ el.muted = true;
9593
+ el.play?.()?.catch?.(() => {
9594
+ });
9595
+ setHoverMutedFallback(true);
9596
+ clearActivationWaiter();
9597
+ const waiter = () => {
9598
+ activationWaiterRef.current = null;
9599
+ if (hoverActiveRef.current && generation === hoverGenerationRef.current) {
9600
+ try {
9601
+ el.muted = false;
9602
+ el.volume = 0.5;
9603
+ } catch {
9604
+ }
9605
+ setHoverMutedFallback(false);
9606
+ }
9607
+ };
9608
+ activationWaiterRef.current = waiter;
9609
+ activationWaiters.add(waiter);
9557
9610
  }
9558
9611
  } catch {
9559
9612
  }
9560
- } : void 0;
9561
- const handleHoverLeave = playOnHover ? () => {
9613
+ }, []);
9614
+ const stopHoverPlayback = useCallback13(() => {
9562
9615
  hoverActiveRef.current = false;
9616
+ setHoverMutedFallback(false);
9617
+ clearActivationWaiter();
9563
9618
  try {
9564
9619
  hoverPlayerRef.current?.pause?.();
9565
9620
  } catch {
9566
9621
  }
9567
- } : void 0;
9622
+ }, [clearActivationWaiter]);
9623
+ const unmuteNow = useCallback13((e) => {
9624
+ e.stopPropagation();
9625
+ e.preventDefault();
9626
+ const el = hoverPlayerRef.current;
9627
+ try {
9628
+ if (el) {
9629
+ el.muted = false;
9630
+ el.volume = 0.5;
9631
+ el.play?.()?.catch?.(() => {
9632
+ });
9633
+ }
9634
+ } catch {
9635
+ }
9636
+ setHoverMutedFallback(false);
9637
+ }, []);
9638
+ const hoverControlled = typeof playWhenHovered === "boolean";
9639
+ useEffect16(() => {
9640
+ if (!hoverControlled) return;
9641
+ if (playWhenHovered) startHoverPlayback();
9642
+ else stopHoverPlayback();
9643
+ }, [hoverControlled, playWhenHovered, startHoverPlayback, stopHoverPlayback]);
9644
+ const handleHoverEnter = playOnHover && !hoverControlled ? startHoverPlayback : void 0;
9645
+ const handleHoverLeave = playOnHover && !hoverControlled ? stopHoverPlayback : void 0;
9568
9646
  if (process.env.NODE_ENV !== "production" && srtContent && !captionsUrl) {
9569
9647
  console.warn(
9570
9648
  "[Video] srtContent supplied without captionsUrl \u2014 captions will not render. Pass captionsUrl (the VTT URL) instead; raw SRT text overlays are no longer supported."
@@ -9610,17 +9688,37 @@ function FilePlayer({
9610
9688
  ) : null
9611
9689
  }
9612
9690
  );
9613
- if (playOnHover) {
9614
- return /* @__PURE__ */ jsx67(
9691
+ const unmuteBadge = hoverMutedFallback ? /* @__PURE__ */ jsx67(
9692
+ "button",
9693
+ {
9694
+ type: "button",
9695
+ "aria-label": "Unmute",
9696
+ title: "Unmute",
9697
+ onClick: unmuteNow,
9698
+ className: "absolute inset-0 z-10 m-auto flex h-14 w-14 items-center justify-center text-ods-text-primary transition-opacity hover:opacity-75",
9699
+ children: /* @__PURE__ */ jsx67(VolumeXmarkIcon, { size: 56 })
9700
+ }
9701
+ ) : null;
9702
+ if (playOnHover && !hoverControlled) {
9703
+ return /* @__PURE__ */ jsxs52(
9615
9704
  "div",
9616
9705
  {
9617
- className: "w-full h-full",
9706
+ className: "relative w-full h-full",
9618
9707
  onPointerEnter: handleHoverEnter,
9619
9708
  onPointerLeave: handleHoverLeave,
9620
- children: player
9709
+ children: [
9710
+ player,
9711
+ unmuteBadge
9712
+ ]
9621
9713
  }
9622
9714
  );
9623
9715
  }
9716
+ if (hoverControlled) {
9717
+ return /* @__PURE__ */ jsxs52("div", { className: "relative w-full h-full", children: [
9718
+ player,
9719
+ unmuteBadge
9720
+ ] });
9721
+ }
9624
9722
  return player;
9625
9723
  }
9626
9724
  function YouTubeFacade({
@@ -9760,7 +9858,7 @@ function YouTubeFacadeInner({
9760
9858
 
9761
9859
  // src/components/features/video-bites-strip.tsx
9762
9860
  init_cn();
9763
- import { useCallback as useCallback13, useEffect as useEffect18, useMemo as useMemo13, useRef as useRef15, useState as useState22 } from "react";
9861
+ import { useCallback as useCallback14, useEffect as useEffect18, useMemo as useMemo13, useRef as useRef15, useState as useState22 } from "react";
9764
9862
 
9765
9863
  // src/components/features/use-video-warmup.ts
9766
9864
  import { useEffect as useEffect17 } from "react";
@@ -9961,11 +10059,11 @@ function UserDisplay({ name, avatarUrl, subtitle, size: size2 = 32, shape = "squ
9961
10059
  /* @__PURE__ */ jsxs54("div", { className: "min-w-0 flex-1", children: [
9962
10060
  /* @__PURE__ */ jsx70("p", { className: cn(
9963
10061
  "font-['DM_Sans'] text-ods-text-primary truncate",
9964
- compact ? "text-sm leading-5 font-medium" : "text-lg leading-[22px]"
10062
+ compact ? "text-xs leading-4 font-medium" : "text-lg leading-[22px]"
9965
10063
  ), children: name }),
9966
10064
  subtitle && /* @__PURE__ */ jsx70("span", { className: cn(
9967
10065
  "font-['DM_Sans'] text-ods-text-secondary truncate block",
9968
- compact ? "text-sm leading-5 font-medium" : "text-md leading-[16px]"
10066
+ compact ? "text-xs leading-4 font-medium" : "text-md leading-[16px]"
9969
10067
  ), children: subtitle })
9970
10068
  ] })
9971
10069
  ] });
@@ -10006,7 +10104,7 @@ function VideoBitesStrip({
10006
10104
  href,
10007
10105
  headerSlot,
10008
10106
  autoScroll = true,
10009
- autoScrollSpeed = 28,
10107
+ autoScrollSpeed = 60,
10010
10108
  pauseOnHover = true,
10011
10109
  cardHeightDesktop = 416,
10012
10110
  cardHeightMobile = 300,
@@ -10041,7 +10139,7 @@ function VideoBitesStrip({
10041
10139
  const [overflows, setOverflows] = useState22(false);
10042
10140
  const singleCopyWidthRef = useRef15(0);
10043
10141
  const marqueeActive = autoScroll && !reducedMotion && overflows && items.length > 0;
10044
- const measure = useCallback13(() => {
10142
+ const measure = useCallback14(() => {
10045
10143
  const scroller = scrollerRef.current;
10046
10144
  const track = trackRef.current;
10047
10145
  if (!scroller || !track) return;
@@ -10060,7 +10158,6 @@ function VideoBitesStrip({
10060
10158
  ro.observe(track);
10061
10159
  return () => ro.disconnect();
10062
10160
  }, [measure, items.length, marqueeActive, isMobile]);
10063
- const hoveredRef = useRef15(false);
10064
10161
  const nearViewportRef = useRef15(true);
10065
10162
  const chevronSuppressUntilRef = useRef15(0);
10066
10163
  const userScrollSuppressUntilRef = useRef15(0);
@@ -10076,22 +10173,44 @@ function VideoBitesStrip({
10076
10173
  io.observe(el);
10077
10174
  return () => io.disconnect();
10078
10175
  }, []);
10176
+ const marqueePosRef = useRef15(0);
10177
+ const glideRemainingRef = useRef15(0);
10079
10178
  useEffect18(() => {
10080
10179
  if (!marqueeActive) return;
10081
10180
  const scroller = scrollerRef.current;
10082
10181
  if (!scroller) return;
10083
10182
  let raf = 0;
10084
10183
  let last = performance.now();
10184
+ marqueePosRef.current = scroller.scrollLeft;
10185
+ const wrap = (pos) => {
10186
+ const half = singleCopyWidthRef.current;
10187
+ if (half <= 0) return pos;
10188
+ while (pos >= half) pos -= half;
10189
+ while (pos < 0) pos += half;
10190
+ return pos;
10191
+ };
10085
10192
  const tick = (now) => {
10086
10193
  const dt = Math.min(now - last, 100) / 1e3;
10087
10194
  last = now;
10088
- const paused = pauseOnHover && hoveredRef.current || !nearViewportRef.current || document.visibilityState === "hidden" || now < Math.max(chevronSuppressUntilRef.current, userScrollSuppressUntilRef.current);
10089
- if (!paused) {
10090
- scroller.scrollLeft += autoScrollSpeed * dt;
10091
- const half = singleCopyWidthRef.current;
10092
- if (half > 0 && scroller.scrollLeft >= half) {
10093
- scroller.scrollLeft -= half;
10094
- }
10195
+ const paused = pauseOnHover && activeKeyRef.current !== null || !nearViewportRef.current || document.visibilityState === "hidden" || now < Math.max(chevronSuppressUntilRef.current, userScrollSuppressUntilRef.current);
10196
+ const glide = glideRemainingRef.current;
10197
+ if (glide !== 0) {
10198
+ if (Math.abs(scroller.scrollLeft - marqueePosRef.current) > 1.5) {
10199
+ marqueePosRef.current = scroller.scrollLeft;
10200
+ }
10201
+ const speed = Math.max(Math.abs(glide) * 6, 240);
10202
+ const step = Math.sign(glide) * Math.min(Math.abs(glide), speed * dt);
10203
+ glideRemainingRef.current = Math.abs(glide - step) < 0.5 ? 0 : glide - step;
10204
+ marqueePosRef.current = wrap(marqueePosRef.current + step);
10205
+ scroller.scrollLeft = marqueePosRef.current;
10206
+ } else if (!paused) {
10207
+ if (Math.abs(scroller.scrollLeft - marqueePosRef.current) > 1.5) {
10208
+ marqueePosRef.current = scroller.scrollLeft;
10209
+ }
10210
+ marqueePosRef.current = wrap(marqueePosRef.current + autoScrollSpeed * dt);
10211
+ scroller.scrollLeft = marqueePosRef.current;
10212
+ } else {
10213
+ marqueePosRef.current = scroller.scrollLeft;
10095
10214
  }
10096
10215
  raf = requestAnimationFrame(tick);
10097
10216
  };
@@ -10099,23 +10218,105 @@ function VideoBitesStrip({
10099
10218
  return () => cancelAnimationFrame(raf);
10100
10219
  }, [marqueeActive, autoScrollSpeed, pauseOnHover]);
10101
10220
  const [activeKey, setActiveKey] = useState22(null);
10102
- const activate = useCallback13((key) => setActiveKey(key), []);
10103
- const deactivate = useCallback13((key) => {
10104
- setActiveKey((current) => current === key ? null : current);
10221
+ const activeKeyRef = useRef15(null);
10222
+ const activate = useCallback14((key) => {
10223
+ activeKeyRef.current = key;
10224
+ setActiveKey(key);
10225
+ }, []);
10226
+ const deactivate = useCallback14((key) => {
10227
+ setActiveKey((current) => {
10228
+ const next = current === key ? null : current;
10229
+ activeKeyRef.current = next;
10230
+ return next;
10231
+ });
10105
10232
  }, []);
10106
10233
  const warmup = useVideoWarmup({ videoUrl: items[0]?.url || null });
10107
- const scrollByCard = useCallback13((dir) => {
10234
+ const [mountedIdx, setMountedIdx] = useState22(() => /* @__PURE__ */ new Set());
10235
+ const cardObserverRef = useRef15(null);
10236
+ const cardElIdxRef = useRef15(/* @__PURE__ */ new Map());
10237
+ const cardElNearRef = useRef15(/* @__PURE__ */ new Map());
10238
+ useEffect18(() => {
10239
+ if (typeof IntersectionObserver === "undefined") return;
10240
+ const io = new IntersectionObserver((entries) => {
10241
+ for (const e of entries) cardElNearRef.current.set(e.target, e.isIntersecting);
10242
+ const next = /* @__PURE__ */ new Set();
10243
+ cardElNearRef.current.forEach((near, el) => {
10244
+ if (!near) return;
10245
+ const idx = cardElIdxRef.current.get(el);
10246
+ if (idx !== void 0) next.add(idx);
10247
+ });
10248
+ setMountedIdx((prev) => {
10249
+ if (prev.size === next.size) {
10250
+ let same = true;
10251
+ next.forEach((i) => {
10252
+ if (!prev.has(i)) same = false;
10253
+ });
10254
+ if (same) return prev;
10255
+ }
10256
+ return next;
10257
+ });
10258
+ }, { rootMargin: "500px" });
10259
+ cardObserverRef.current = io;
10260
+ cardElIdxRef.current.forEach((_idx, el) => io.observe(el));
10261
+ return () => {
10262
+ io.disconnect();
10263
+ cardObserverRef.current = null;
10264
+ };
10265
+ }, []);
10266
+ const cardRefFnsRef = useRef15(/* @__PURE__ */ new Map());
10267
+ const getCardRef = useCallback14((idx) => {
10268
+ let fn = cardRefFnsRef.current.get(idx);
10269
+ if (!fn) {
10270
+ fn = (el) => {
10271
+ if (!el) return void 0;
10272
+ cardElIdxRef.current.set(el, idx);
10273
+ cardObserverRef.current?.observe(el);
10274
+ return () => {
10275
+ cardElIdxRef.current.delete(el);
10276
+ cardElNearRef.current.delete(el);
10277
+ cardObserverRef.current?.unobserve(el);
10278
+ };
10279
+ };
10280
+ cardRefFnsRef.current.set(idx, fn);
10281
+ }
10282
+ return fn;
10283
+ }, []);
10284
+ const scrollByCard = useCallback14((dir) => {
10108
10285
  const scroller = scrollerRef.current;
10109
10286
  const track = trackRef.current;
10110
10287
  if (!scroller || !track) return;
10111
10288
  const firstCard = track.firstElementChild;
10112
10289
  const step = (firstCard?.offsetWidth ?? 320) + TRACK_GAP_PX;
10113
10290
  chevronSuppressUntilRef.current = performance.now() + CHEVRON_SUPPRESS_MS;
10114
- scroller.scrollBy({ left: dir * step, behavior: "smooth" });
10291
+ if (marqueeActiveRef.current) {
10292
+ glideRemainingRef.current += dir * step;
10293
+ } else {
10294
+ scroller.scrollBy({ left: dir * step, behavior: "smooth" });
10295
+ }
10115
10296
  }, []);
10116
- const onUserScrollIntent = useCallback13(() => {
10297
+ const onUserScrollIntent = useCallback14(() => {
10117
10298
  userScrollSuppressUntilRef.current = performance.now() + USER_SCROLL_SUPPRESS_MS;
10118
10299
  }, []);
10300
+ const lastScrollLeftRef = useRef15(0);
10301
+ const marqueeActiveRef = useRef15(false);
10302
+ marqueeActiveRef.current = marqueeActive;
10303
+ const onSeamWarp = useCallback14(() => {
10304
+ const scroller = scrollerRef.current;
10305
+ if (!scroller || !marqueeActiveRef.current) return;
10306
+ const half = singleCopyWidthRef.current;
10307
+ if (half <= 0) return;
10308
+ let sl = scroller.scrollLeft;
10309
+ if (sl >= half) {
10310
+ sl -= half;
10311
+ scroller.scrollLeft = sl;
10312
+ marqueePosRef.current = sl;
10313
+ } else if (sl <= 0 && lastScrollLeftRef.current > 0.5) {
10314
+ sl += half;
10315
+ scroller.scrollLeft = sl;
10316
+ marqueePosRef.current = sl;
10317
+ }
10318
+ lastScrollLeftRef.current = sl;
10319
+ }, []);
10119
10320
  if (items.length === 0) return null;
10120
10321
  const cardHeight = isMobile ? cardHeightMobile : cardHeightDesktop;
10121
10322
  const copies = marqueeActive ? 2 : 1;
@@ -10127,12 +10328,6 @@ function VideoBitesStrip({
10127
10328
  warmup.ref(node);
10128
10329
  },
10129
10330
  className: cn("flex flex-col gap-6 w-full min-w-0", className),
10130
- onPointerEnter: () => {
10131
- hoveredRef.current = true;
10132
- },
10133
- onPointerLeave: () => {
10134
- hoveredRef.current = false;
10135
- },
10136
10331
  children: [
10137
10332
  showTitle && /* @__PURE__ */ jsx72("h2", { className: `${SECTION_HEADING_CLASS} break-words`, children: title }),
10138
10333
  headerSlot,
@@ -10145,6 +10340,7 @@ function VideoBitesStrip({
10145
10340
  onWheel: onUserScrollIntent,
10146
10341
  onTouchStart: onUserScrollIntent,
10147
10342
  onPointerDown: onUserScrollIntent,
10343
+ onScroll: onSeamWarp,
10148
10344
  children: /* @__PURE__ */ jsx72("div", { ref: trackRef, "data-copies": copies, className: "flex w-max items-stretch gap-4", children: Array.from(
10149
10345
  { length: copies },
10150
10346
  (_, copyIndex) => items.map((bite, i) => {
@@ -10155,7 +10351,7 @@ function VideoBitesStrip({
10155
10351
  // same rule as quick-action-marquee). Clones stay pointer-
10156
10352
  // interactive (briefly visible near the wrap seam).
10157
10353
  /* @__PURE__ */ jsx72(
10158
- BiteStripCard,
10354
+ VideoBiteCard,
10159
10355
  {
10160
10356
  bite,
10161
10357
  index: i,
@@ -10166,6 +10362,8 @@ function VideoBitesStrip({
10166
10362
  active: activeKey === key,
10167
10363
  onActivate: activate,
10168
10364
  onDeactivate: deactivate,
10365
+ playerMounted: mountedIdx.has(i),
10366
+ rootRef: getCardRef(i),
10169
10367
  profile: bite.profile ?? profile ?? null,
10170
10368
  sectionHref: href,
10171
10369
  onBiteNavigate
@@ -10204,27 +10402,42 @@ function VideoBitesStrip({
10204
10402
  }
10205
10403
  );
10206
10404
  }
10207
- function BiteStripCard({
10405
+ function VideoBiteCard({
10208
10406
  bite,
10209
10407
  index,
10210
- cardKey,
10211
- isClone,
10212
- isTouch,
10408
+ profile = null,
10409
+ sectionHref,
10410
+ onBiteNavigate,
10213
10411
  height,
10214
10412
  active,
10215
10413
  onActivate,
10216
10414
  onDeactivate,
10217
- profile,
10218
- sectionHref,
10219
- onBiteNavigate
10415
+ cardKey,
10416
+ isClone = false,
10417
+ isTouch = false,
10418
+ playerMounted,
10419
+ rootRef,
10420
+ toolbar,
10421
+ titleEditable = false,
10422
+ onTitleChange,
10423
+ onTitleCommit,
10424
+ className
10220
10425
  }) {
10221
10426
  const cssAspect = RATIO_TO_CSS_ASPECT[ratioToCategory(detectAspectRatio(bite.aspect_ratio))];
10222
10427
  const targetHref = bite.href ?? sectionHref;
10223
10428
  const hasTarget = !!(targetHref || bite.onNavigate || onBiteNavigate);
10224
- const nearRef = useRef15(null);
10429
+ const key = cardKey ?? `${bite.url}__${index}`;
10430
+ const controlled = active !== void 0;
10431
+ const [selfActive, setSelfActive] = useState22(false);
10432
+ const isActive = controlled ? !!active : selfActive;
10433
+ const activate = () => controlled ? onActivate?.(key) : setSelfActive(true);
10434
+ const deactivate = () => controlled ? onDeactivate?.(key) : setSelfActive(false);
10435
+ const gateControlled = playerMounted !== void 0;
10436
+ const rootElRef = useRef15(null);
10225
10437
  const [isNear, setIsNear] = useState22(false);
10226
10438
  useEffect18(() => {
10227
- const el = nearRef.current;
10439
+ if (gateControlled) return;
10440
+ const el = rootElRef.current;
10228
10441
  if (!el || typeof IntersectionObserver === "undefined") return;
10229
10442
  const io = new IntersectionObserver(
10230
10443
  (entries) => setIsNear(entries[0]?.isIntersecting ?? false),
@@ -10232,22 +10445,56 @@ function BiteStripCard({
10232
10445
  );
10233
10446
  io.observe(el);
10234
10447
  return () => io.disconnect();
10235
- }, []);
10448
+ }, [gateControlled]);
10449
+ const showPlayer = gateControlled ? playerMounted : isNear;
10236
10450
  const navigate = () => {
10237
10451
  if (bite.onNavigate) bite.onNavigate();
10238
10452
  else onBiteNavigate?.(bite, index);
10239
10453
  };
10240
10454
  const handlePointerEnter = () => {
10241
- if (!isTouch) onActivate(cardKey);
10455
+ if (!isTouch) activate();
10242
10456
  };
10243
10457
  const handlePointerLeave = () => {
10244
- if (!isTouch) onDeactivate(cardKey);
10458
+ if (!isTouch) deactivate();
10245
10459
  };
10246
10460
  const handleClick = () => {
10247
- if (isTouch && !active) onActivate(cardKey);
10461
+ if (isTouch && !isActive) activate();
10248
10462
  };
10463
+ const titleClass = "font-['DM_Sans'] text-sm font-medium leading-5 text-ods-text-primary";
10249
10464
  const overlayContent = /* @__PURE__ */ jsxs56(Fragment18, { children: [
10250
- bite.title && /* @__PURE__ */ jsx72("p", { className: "font-['DM_Sans'] text-sm font-medium leading-5 text-ods-text-primary line-clamp-1", children: bite.title }),
10465
+ titleEditable ? (
10466
+ // Textarea, not input: the public title wraps to two lines
10467
+ // (line-clamp-2) and the editor must render identically. rows=1 +
10468
+ // auto-grow keeps short titles single-line; max-height caps at the
10469
+ // same two lines the clamp allows.
10470
+ /* @__PURE__ */ jsx72(
10471
+ "textarea",
10472
+ {
10473
+ value: bite.title || "",
10474
+ placeholder: "Title (optional)",
10475
+ "aria-label": "Bite title",
10476
+ rows: 1,
10477
+ onChange: (e) => {
10478
+ e.target.style.height = "auto";
10479
+ e.target.style.height = `${Math.min(e.target.scrollHeight, 40)}px`;
10480
+ onTitleChange?.(e.target.value);
10481
+ },
10482
+ ref: (el) => {
10483
+ if (el) {
10484
+ el.style.height = "auto";
10485
+ el.style.height = `${Math.min(el.scrollHeight, 40)}px`;
10486
+ }
10487
+ },
10488
+ onBlur: (e) => onTitleCommit?.(e.target.value),
10489
+ onClick: (e) => e.stopPropagation(),
10490
+ className: cn(
10491
+ titleClass,
10492
+ "w-full max-h-10 resize-none overflow-hidden bg-transparent outline-none",
10493
+ "placeholder:text-ods-text-secondary border-b border-transparent focus:border-ods-border"
10494
+ )
10495
+ }
10496
+ )
10497
+ ) : bite.title && /* @__PURE__ */ jsx72("p", { className: cn(titleClass, "line-clamp-2"), children: bite.title }),
10251
10498
  (profile || hasTarget) && /* @__PURE__ */ jsxs56("div", { className: "flex items-center gap-2 min-w-0", children: [
10252
10499
  profile && /* @__PURE__ */ jsx72(
10253
10500
  UserDisplay,
@@ -10255,7 +10502,7 @@ function BiteStripCard({
10255
10502
  name: profile.name,
10256
10503
  avatarUrl: profile.avatarUrl,
10257
10504
  subtitle: profile.subtitle,
10258
- size: 28,
10505
+ size: 22,
10259
10506
  shape: "round",
10260
10507
  compact: true,
10261
10508
  className: "flex-1"
@@ -10267,39 +10514,67 @@ function BiteStripCard({
10267
10514
  const overlayClass = cn(
10268
10515
  "absolute inset-x-0 bottom-0 p-3 gap-2 bg-black/75 border border-ods-border shadow-2xl",
10269
10516
  "flex flex-col transition-opacity duration-200",
10270
- active ? "opacity-100" : "opacity-0 group-hover/card:opacity-100 group-focus-within/card:opacity-100",
10517
+ isActive ? "opacity-100" : "opacity-0 group-hover/card:opacity-100 group-focus-within/card:opacity-100",
10271
10518
  // Non-interactive while invisible so it never swallows clicks on the
10272
10519
  // resting card / player controls.
10273
- active ? "pointer-events-auto" : "pointer-events-none group-hover/card:pointer-events-auto"
10520
+ isActive ? "pointer-events-auto" : "pointer-events-none group-hover/card:pointer-events-auto group-focus-within/card:pointer-events-auto"
10521
+ );
10522
+ const media = /* @__PURE__ */ jsxs56(
10523
+ "div",
10524
+ {
10525
+ className: "relative w-full",
10526
+ style: { aspectRatio: cssAspect, ...height !== void 0 ? { height, maxWidth: "90vw" } : {} },
10527
+ children: [
10528
+ showPlayer ? (
10529
+ // Clones: `inert` (not just the wrapper's aria-hidden) — the player's
10530
+ // shadow-DOM center control is otherwise still tab-reachable inside a
10531
+ // hidden subtree (axe aria-hidden-focus). Hover preview on clones
10532
+ // keeps working: playback is driven imperatively from the CARD's own
10533
+ // pointer handlers, never from focus/clicks on the player chrome.
10534
+ /* @__PURE__ */ jsx72("div", { className: "absolute inset-0", inert: isClone || void 0, children: /* @__PURE__ */ jsx72(
10535
+ Video2,
10536
+ {
10537
+ kind: "file",
10538
+ url: bite.url,
10539
+ poster: bite.thumbnail_url,
10540
+ playWhenHovered: isActive,
10541
+ centerControlsOnly: true,
10542
+ layout: "fill"
10543
+ }
10544
+ ) })
10545
+ ) : (
10546
+ // Aspect-matched placeholder until the card nears the viewport (CLS-free).
10547
+ /* @__PURE__ */ jsx72("div", { className: "absolute inset-0 bg-ods-card" })
10548
+ ),
10549
+ hasTarget && !isClone && !titleEditable ? targetHref ? /* @__PURE__ */ jsx72("a", { href: targetHref, "aria-label": `Open ${bite.title || "source content"}`, className: overlayClass, children: overlayContent }) : /* @__PURE__ */ jsx72("button", { type: "button", onClick: navigate, "aria-label": `Open ${bite.title || "source content"}`, className: cn(overlayClass, "text-left w-full"), children: overlayContent }) : /* @__PURE__ */ jsx72("div", { className: overlayClass, children: overlayContent })
10550
+ ]
10551
+ }
10274
10552
  );
10275
10553
  return /* @__PURE__ */ jsxs56(
10276
10554
  "div",
10277
10555
  {
10278
- ref: nearRef,
10556
+ ref: (node) => {
10557
+ rootElRef.current = node;
10558
+ return rootRef?.(node);
10559
+ },
10279
10560
  "aria-hidden": isClone || void 0,
10280
- className: "relative shrink-0 rounded-md border border-ods-border bg-ods-card overflow-hidden group/card",
10281
- style: { height, aspectRatio: cssAspect, maxWidth: "90vw" },
10561
+ className: cn(
10562
+ "relative rounded-md border border-ods-border bg-ods-card overflow-hidden group/card",
10563
+ height !== void 0 ? "shrink-0" : "w-full",
10564
+ className
10565
+ ),
10566
+ style: height !== void 0 ? { maxWidth: "90vw" } : void 0,
10282
10567
  onPointerEnter: handlePointerEnter,
10283
10568
  onPointerLeave: handlePointerLeave,
10284
10569
  onClick: handleClick,
10285
- onFocus: () => onActivate(cardKey),
10286
- onBlur: () => onDeactivate(cardKey),
10570
+ onFocus: activate,
10571
+ onBlur: deactivate,
10287
10572
  children: [
10288
- isNear ? /* @__PURE__ */ jsx72("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx72(
10289
- Video2,
10290
- {
10291
- kind: "file",
10292
- url: bite.url,
10293
- poster: bite.thumbnail_url,
10294
- playOnHover: true,
10295
- centerControlsOnly: true,
10296
- layout: "fill"
10297
- }
10298
- ) }) : (
10299
- // Aspect-matched placeholder until the card nears the viewport (CLS-free).
10300
- /* @__PURE__ */ jsx72("div", { className: "absolute inset-0 bg-ods-card" })
10301
- ),
10302
- hasTarget && !isClone ? targetHref ? /* @__PURE__ */ jsx72("a", { href: targetHref, "aria-label": `Open ${bite.title || "source content"}`, className: overlayClass, children: overlayContent }) : /* @__PURE__ */ jsx72("button", { type: "button", onClick: navigate, "aria-label": `Open ${bite.title || "source content"}`, className: cn(overlayClass, "text-left w-full"), children: overlayContent }) : /* @__PURE__ */ jsx72("div", { className: overlayClass, children: overlayContent })
10573
+ media,
10574
+ toolbar && // Solid-surface action row UNDER the media (WCAG non-text contrast —
10575
+ // see the `toolbar` prop doc). Part of the card, so hovering it keeps
10576
+ // hover playback alive.
10577
+ /* @__PURE__ */ jsx72("div", { className: "flex items-center justify-between gap-1 border-t border-ods-border bg-ods-card px-2 py-1.5", children: toolbar })
10303
10578
  ]
10304
10579
  }
10305
10580
  );
@@ -17010,7 +17285,7 @@ function TabContent({
17010
17285
  // src/components/ui/tab-navigation.tsx
17011
17286
  init_next_navigation();
17012
17287
  init_cn();
17013
- import { useState as useState36, useEffect as useEffect28, useMemo as useMemo19, useRef as useRef22, useCallback as useCallback18 } from "react";
17288
+ import { useState as useState36, useEffect as useEffect28, useMemo as useMemo19, useRef as useRef22, useCallback as useCallback19 } from "react";
17014
17289
  import { Fragment as Fragment26, jsx as jsx125, jsxs as jsxs99 } from "react/jsx-runtime";
17015
17290
  function TabNavigation({
17016
17291
  activeTab: controlledActiveTab,
@@ -17067,7 +17342,7 @@ function TabNavigation({
17067
17342
  const isFirstActiveScrollRef = useRef22(true);
17068
17343
  const [canScrollLeft, setCanScrollLeft] = useState36(false);
17069
17344
  const [canScrollRight, setCanScrollRight] = useState36(false);
17070
- const updateScrollShadows = useCallback18(() => {
17345
+ const updateScrollShadows = useCallback19(() => {
17071
17346
  const el = scrollRef.current;
17072
17347
  if (!el) return;
17073
17348
  setCanScrollLeft(el.scrollLeft > 0);
@@ -17319,7 +17594,7 @@ import { useState as useState47 } from "react";
17319
17594
  import { ChevronDown as ChevronDown5 } from "lucide-react";
17320
17595
 
17321
17596
  // src/components/ui/rich-markdown-renderer.tsx
17322
- import { useEffect as useEffect36, useState as useState46, useRef as useRef28, useMemo as useMemo22, useCallback as useCallback21 } from "react";
17597
+ import { useEffect as useEffect36, useState as useState46, useRef as useRef28, useMemo as useMemo22, useCallback as useCallback22 } from "react";
17323
17598
  import ReactMarkdown2 from "react-markdown";
17324
17599
  import remarkGfm2 from "remark-gfm";
17325
17600
  import remarkBreaks2 from "remark-breaks";
@@ -17609,7 +17884,7 @@ var socialCache = SocialEmbedCache.getInstance();
17609
17884
 
17610
17885
  // src/components/media-carousel.tsx
17611
17886
  init_cn();
17612
- import { useState as useState38, useRef as useRef24, useEffect as useEffect30, memo as memo4, useCallback as useCallback19 } from "react";
17887
+ import { useState as useState38, useRef as useRef24, useEffect as useEffect30, memo as memo4, useCallback as useCallback20 } from "react";
17613
17888
  import { Fragment as Fragment28, jsx as jsx130, jsxs as jsxs102 } from "react/jsx-runtime";
17614
17889
  var ChevronLeftIcon = () => /* @__PURE__ */ jsx130("svg", { width: "24", height: "24", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx130("polyline", { points: "15,18 9,12 15,6" }) });
17615
17890
  var ChevronRightIcon = () => /* @__PURE__ */ jsx130("svg", { width: "24", height: "24", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx130("polyline", { points: "9,18 15,12 9,6" }) });
@@ -17638,17 +17913,17 @@ var MediaCarousel = memo4(function MediaCarousel2({
17638
17913
  if (!currentItem) {
17639
17914
  return null;
17640
17915
  }
17641
- const nextSlide = useCallback19(() => {
17916
+ const nextSlide = useCallback20(() => {
17642
17917
  setCurrentIndex((prev) => (prev + 1) % media.length);
17643
17918
  }, [media.length]);
17644
- const prevSlide = useCallback19(() => {
17919
+ const prevSlide = useCallback20(() => {
17645
17920
  setCurrentIndex((prev) => (prev - 1 + media.length) % media.length);
17646
17921
  }, [media.length]);
17647
- const selectSlide = useCallback19((index) => {
17922
+ const selectSlide = useCallback20((index) => {
17648
17923
  if (index === currentIndex) return;
17649
17924
  setCurrentIndex(index);
17650
17925
  }, [currentIndex]);
17651
- const handleKeyDown = useCallback19((e) => {
17926
+ const handleKeyDown = useCallback20((e) => {
17652
17927
  if (media.length <= 1) return;
17653
17928
  if (e.key === "ArrowLeft") {
17654
17929
  e.preventDefault();
@@ -18900,7 +19175,7 @@ function toFigmaOriginalUrl(url) {
18900
19175
  }
18901
19176
 
18902
19177
  // src/components/embeds/embed-iframe.tsx
18903
- import { useState as useState43, useCallback as useCallback20, useRef as useRef27, useEffect as useEffect34 } from "react";
19178
+ import { useState as useState43, useCallback as useCallback21, useRef as useRef27, useEffect as useEffect34 } from "react";
18904
19179
  import { Fragment as Fragment29, jsx as jsx137, jsxs as jsxs107 } from "react/jsx-runtime";
18905
19180
  function EmbedLoadingSkeleton({ height }) {
18906
19181
  return /* @__PURE__ */ jsx137(
@@ -18923,7 +19198,7 @@ function EmbedIframe({
18923
19198
  }) {
18924
19199
  const [isLoaded, setIsLoaded] = useState43(false);
18925
19200
  const iframeRef = useRef27(null);
18926
- const handleLoad = useCallback20(() => setIsLoaded(true), []);
19201
+ const handleLoad = useCallback21(() => setIsLoaded(true), []);
18927
19202
  useEffect34(() => {
18928
19203
  setIsLoaded(false);
18929
19204
  }, [src]);
@@ -19558,7 +19833,7 @@ var RichMarkdownInner = ({
19558
19833
  return map;
19559
19834
  }, [sectionIds]);
19560
19835
  const isDarkMode = true;
19561
- const generateHeadingId = useCallback21((text, level) => {
19836
+ const generateHeadingId = useCallback22((text, level) => {
19562
19837
  if (sectionIds && (level === 1 || level === 2)) {
19563
19838
  const variations = [
19564
19839
  text,
@@ -20136,7 +20411,7 @@ function StatusIndicator({ status, label, href }) {
20136
20411
  }
20137
20412
 
20138
20413
  // src/components/ui/hover-dropdown.tsx
20139
- import { useState as useState48, useRef as useRef29, useCallback as useCallback22 } from "react";
20414
+ import { useState as useState48, useRef as useRef29, useCallback as useCallback23 } from "react";
20140
20415
  import { Fragment as Fragment31, jsx as jsx145, jsxs as jsxs114 } from "react/jsx-runtime";
20141
20416
  function DefaultAnchor({
20142
20417
  href,
@@ -20156,15 +20431,15 @@ function HoverDropdown({
20156
20431
  const [open, setOpen] = useState48(false);
20157
20432
  const timeoutRef = useRef29(void 0);
20158
20433
  const containerRef = useRef29(null);
20159
- const show = useCallback22(() => {
20434
+ const show = useCallback23(() => {
20160
20435
  clearTimeout(timeoutRef.current);
20161
20436
  setOpen(true);
20162
20437
  }, []);
20163
- const hide = useCallback22(() => {
20438
+ const hide = useCallback23(() => {
20164
20439
  timeoutRef.current = setTimeout(() => setOpen(false), hideDelay);
20165
20440
  }, [hideDelay]);
20166
20441
  if (items.length === 0) return /* @__PURE__ */ jsx145(Fragment31, { children });
20167
- const toggle = useCallback22((e) => {
20442
+ const toggle = useCallback23((e) => {
20168
20443
  e.stopPropagation();
20169
20444
  clearTimeout(timeoutRef.current);
20170
20445
  setOpen((prev) => !prev);
@@ -26174,7 +26449,7 @@ var ErrorBoundary = class extends Component3 {
26174
26449
 
26175
26450
  // src/components/features/figma-prototype-viewer.tsx
26176
26451
  init_cn();
26177
- import { useState as useState59, useRef as useRef32, useEffect as useEffect44, useCallback as useCallback24, useMemo as useMemo25 } from "react";
26452
+ import { useState as useState59, useRef as useRef32, useEffect as useEffect44, useCallback as useCallback25, useMemo as useMemo25 } from "react";
26178
26453
 
26179
26454
  // src/components/features/section-selector.tsx
26180
26455
  init_cn();
@@ -26682,7 +26957,7 @@ var FigmaPrototypeViewer = ({
26682
26957
  window.addEventListener("message", handleMessage);
26683
26958
  return () => window.removeEventListener("message", handleMessage);
26684
26959
  }, [config.sections, activeSection, isNavigating, externalActiveSection, config.onSectionChange, viewMode]);
26685
- const navigateToSection = useCallback24((sectionId) => {
26960
+ const navigateToSection = useCallback25((sectionId) => {
26686
26961
  const section = config.sections.find((s) => s.id === sectionId);
26687
26962
  if (!section || !iframeRef.current?.contentWindow || !isInitialized) {
26688
26963
  return;
@@ -26706,7 +26981,7 @@ var FigmaPrototypeViewer = ({
26706
26981
  if (navTimerRef.current) clearTimeout(navTimerRef.current);
26707
26982
  navTimerRef.current = setTimeout(() => setIsNavigating(false), 500);
26708
26983
  }, [config, isInitialized, viewMode, externalActiveSection]);
26709
- const handleSectionClick = useCallback24((sectionId) => {
26984
+ const handleSectionClick = useCallback25((sectionId) => {
26710
26985
  const sectionsDisabled = iframeState !== "READY" || isNavigating;
26711
26986
  if (sectionId === activeSection || sectionsDisabled) {
26712
26987
  return;
@@ -26717,7 +26992,7 @@ var FigmaPrototypeViewer = ({
26717
26992
  navigateToSection(sectionId);
26718
26993
  }
26719
26994
  }, [activeSection, iframeState, isNavigating, externalOnSectionClick, navigateToSection]);
26720
- const handleTouchStart = useCallback24((e) => {
26995
+ const handleTouchStart = useCallback25((e) => {
26721
26996
  const overlayElement = e.currentTarget;
26722
26997
  console.log("[Touch] Touch detected, allowing iframe interaction");
26723
26998
  overlayElement.style.pointerEvents = "none";
@@ -27281,7 +27556,7 @@ function useLoading() {
27281
27556
  }
27282
27557
 
27283
27558
  // src/components/features/media-gallery-manager.tsx
27284
- import { useState as useState62, useRef as useRef34, useCallback as useCallback25 } from "react";
27559
+ import { useState as useState62, useRef as useRef34, useCallback as useCallback26 } from "react";
27285
27560
  import {
27286
27561
  Upload,
27287
27562
  Image as ImageIcon2,
@@ -27304,7 +27579,7 @@ function MediaGalleryManager({
27304
27579
  const fileInputRef = useRef34(null);
27305
27580
  const [deletingIndex, setDeletingIndex] = useState62(null);
27306
27581
  const [draggedIndex, setDraggedIndex] = useState62(null);
27307
- const handleFileSelect = useCallback25(async (event) => {
27582
+ const handleFileSelect = useCallback26(async (event) => {
27308
27583
  const file = event.target.files?.[0];
27309
27584
  if (!file) return;
27310
27585
  let mediaType;
@@ -27330,18 +27605,18 @@ function MediaGalleryManager({
27330
27605
  console.error("Upload failed:", error);
27331
27606
  }
27332
27607
  }, [media, onChange, onUpload]);
27333
- const handleDeleteMedia = useCallback25((index) => {
27608
+ const handleDeleteMedia = useCallback26((index) => {
27334
27609
  setDeletingIndex(index);
27335
27610
  onChange(media.filter((_, i) => i !== index));
27336
27611
  setDeletingIndex(null);
27337
27612
  }, [media, onChange]);
27338
- const handleDragStart = useCallback25((index) => {
27613
+ const handleDragStart = useCallback26((index) => {
27339
27614
  setDraggedIndex(index);
27340
27615
  }, []);
27341
- const handleDragOver = useCallback25((e) => {
27616
+ const handleDragOver = useCallback26((e) => {
27342
27617
  e.preventDefault();
27343
27618
  }, []);
27344
- const handleDrop = useCallback25((e, targetIndex) => {
27619
+ const handleDrop = useCallback26((e, targetIndex) => {
27345
27620
  e.preventDefault();
27346
27621
  if (draggedIndex === null || draggedIndex === targetIndex) {
27347
27622
  setDraggedIndex(null);
@@ -27353,7 +27628,7 @@ function MediaGalleryManager({
27353
27628
  onChange(newMedia.map((item, i) => ({ ...item, display_order: i })));
27354
27629
  setDraggedIndex(null);
27355
27630
  }, [media, draggedIndex, onChange]);
27356
- const renderMediaItem = useCallback25((mediaItem, index) => {
27631
+ const renderMediaItem = useCallback26((mediaItem, index) => {
27357
27632
  const isDeleting = deletingIndex === index;
27358
27633
  return /* @__PURE__ */ jsxs164(
27359
27634
  Card,
@@ -29074,7 +29349,7 @@ function getCaptionsUrl(entityType, entityId, srtContent) {
29074
29349
  }
29075
29350
 
29076
29351
  // src/components/features/video-source-selector.tsx
29077
- import { useState as useState67, useCallback as useCallback26, useEffect as useEffect48 } from "react";
29352
+ import { useState as useState67, useCallback as useCallback27, useEffect as useEffect48 } from "react";
29078
29353
  import { Upload as Upload4, X as X8, Video as Video7, Loader2 as Loader27 } from "lucide-react";
29079
29354
  init_button2();
29080
29355
  import { jsx as jsx227, jsxs as jsxs177 } from "react/jsx-runtime";
@@ -29105,7 +29380,7 @@ function VideoSourceSelector({
29105
29380
  const [uploadProgress, setUploadProgress] = useState67(0);
29106
29381
  const [uploadMessage, setUploadMessage] = useState67("");
29107
29382
  const [uploadError, setUploadError] = useState67(null);
29108
- const handleUploadClick = useCallback26(() => {
29383
+ const handleUploadClick = useCallback27(() => {
29109
29384
  const input = document.createElement("input");
29110
29385
  input.type = "file";
29111
29386
  input.accept = "video/*";
@@ -29136,7 +29411,7 @@ function VideoSourceSelector({
29136
29411
  };
29137
29412
  input.click();
29138
29413
  }, [onUploadVideo, onMainVideoUrlChange]);
29139
- const handleDeleteVideo = useCallback26(() => {
29414
+ const handleDeleteVideo = useCallback27(() => {
29140
29415
  onMainVideoUrlChange("");
29141
29416
  }, [onMainVideoUrlChange]);
29142
29417
  return /* @__PURE__ */ jsxs177("div", { className: `space-y-4 p-6 bg-ods-card border border-ods-border rounded-lg ${className}`, children: [
@@ -30944,7 +31219,7 @@ PolicyConfigurationPanel.displayName = "PolicyConfigurationPanel";
30944
31219
  init_button2();
30945
31220
 
30946
31221
  // src/components/ui/phone-input.tsx
30947
- import { useCallback as useCallback27, useEffect as useEffect50, useMemo as useMemo26, useRef as useRef38, useState as useState70 } from "react";
31222
+ import { useCallback as useCallback28, useEffect as useEffect50, useMemo as useMemo26, useRef as useRef38, useState as useState70 } from "react";
30948
31223
  import { jsx as jsx247, jsxs as jsxs193 } from "react/jsx-runtime";
30949
31224
  function PhoneInput({
30950
31225
  value,
@@ -30963,8 +31238,8 @@ function PhoneInput({
30963
31238
  );
30964
31239
  const [isInvalid, setIsInvalid] = useState70(false);
30965
31240
  const debounceRef = useRef38(null);
30966
- const digitCount = useCallback27((val) => val.replace(/[^0-9]/g, "").length, []);
30967
- const runValidation = useCallback27((phone) => {
31241
+ const digitCount = useCallback28((val) => val.replace(/[^0-9]/g, "").length, []);
31242
+ const runValidation = useCallback28((phone) => {
30968
31243
  if (!phone || digitCount(phone) === 0) {
30969
31244
  setIsInvalid(false);
30970
31245
  onValidationChange?.(false);
@@ -30974,7 +31249,7 @@ function PhoneInput({
30974
31249
  setIsInvalid(invalid);
30975
31250
  onValidationChange?.(invalid);
30976
31251
  }, [countryCode, digitCount, onValidationChange]);
30977
- const debouncedValidation = useCallback27((phone) => {
31252
+ const debouncedValidation = useCallback28((phone) => {
30978
31253
  if (debounceRef.current) clearTimeout(debounceRef.current);
30979
31254
  debounceRef.current = setTimeout(() => runValidation(phone), 300);
30980
31255
  }, [runValidation]);
@@ -33231,7 +33506,7 @@ function EmptyState2() {
33231
33506
  }
33232
33507
 
33233
33508
  // src/components/features/board/use-board-collapse.ts
33234
- import { useCallback as useCallback31, useState as useState79 } from "react";
33509
+ import { useCallback as useCallback32, useState as useState79 } from "react";
33235
33510
  function useBoardCollapse(storageKey) {
33236
33511
  const [persisted, setPersisted] = useLocalStorage(
33237
33512
  storageKey ?? "__board_collapse_unused__",
@@ -33240,13 +33515,13 @@ function useBoardCollapse(storageKey) {
33240
33515
  const [memory, setMemory] = useState79({});
33241
33516
  const collapsed = storageKey ? persisted : memory;
33242
33517
  const setMap = storageKey ? setPersisted : setMemory;
33243
- const toggle = useCallback31(
33518
+ const toggle = useCallback32(
33244
33519
  (columnId) => {
33245
33520
  setMap((prev) => ({ ...prev, [columnId]: !prev[columnId] }));
33246
33521
  },
33247
33522
  [setMap]
33248
33523
  );
33249
- const setCollapsed = useCallback31(
33524
+ const setCollapsed = useCallback32(
33250
33525
  (columnId, value) => {
33251
33526
  setMap((prev) => ({ ...prev, [columnId]: value }));
33252
33527
  },
@@ -34250,7 +34525,7 @@ function SlidingSidebar({ config }) {
34250
34525
  }
34251
34526
 
34252
34527
  // src/components/navigation/sticky-section-nav.tsx
34253
- import { useEffect as useEffect63, useState as useState84, useCallback as useCallback33, useRef as useRef45 } from "react";
34528
+ import { useEffect as useEffect63, useState as useState84, useCallback as useCallback34, useRef as useRef45 } from "react";
34254
34529
  import { jsx as jsx270, jsxs as jsxs210 } from "react/jsx-runtime";
34255
34530
  function StickySectionNav({
34256
34531
  sections,
@@ -34314,7 +34589,7 @@ function useSectionNavigation(sections, options) {
34314
34589
  const [activeSection, setActiveSection] = useState84(sections[0]?.id || "");
34315
34590
  const isScrollingFromClick = useRef45(false);
34316
34591
  const { offset: offset2 = 100 } = options || {};
34317
- const handleSectionClick = useCallback33((sectionId) => {
34592
+ const handleSectionClick = useCallback34((sectionId) => {
34318
34593
  const targetElement = document.getElementById(sectionId);
34319
34594
  if (!targetElement) return;
34320
34595
  isScrollingFromClick.current = true;
@@ -34364,7 +34639,7 @@ function useSectionNavigation(sections, options) {
34364
34639
  }
34365
34640
 
34366
34641
  // src/components/navigation/navigation-sidebar.tsx
34367
- import { useCallback as useCallback34, useEffect as useEffect64, useLayoutEffect as useLayoutEffect6, useMemo as useMemo33, useState as useState85 } from "react";
34642
+ import { useCallback as useCallback35, useEffect as useEffect64, useLayoutEffect as useLayoutEffect6, useMemo as useMemo33, useState as useState85 } from "react";
34368
34643
 
34369
34644
  // src/components/navigation/navigation-sidebar-header.tsx
34370
34645
  import { jsx as jsx271, jsxs as jsxs211 } from "react/jsx-runtime";
@@ -34520,7 +34795,7 @@ function NavigationSidebar({ config, disabled = false }) {
34520
34795
  const [transitionsEnabled, setTransitionsEnabled] = useState85(false);
34521
34796
  const isOverlayOpen = isTablet && !minimized;
34522
34797
  const showLabel = !minimized;
34523
- const handleToggle = useCallback34(() => {
34798
+ const handleToggle = useCallback35(() => {
34524
34799
  if (isTablet) {
34525
34800
  setTabletMinimized((prev) => !prev);
34526
34801
  } else {
@@ -34528,7 +34803,7 @@ function NavigationSidebar({ config, disabled = false }) {
34528
34803
  }
34529
34804
  config.onToggleMinimized?.();
34530
34805
  }, [isTablet, setDesktopMinimized, config]);
34531
- const closeOverlay = useCallback34(() => {
34806
+ const closeOverlay = useCallback35(() => {
34532
34807
  setTabletMinimized(true);
34533
34808
  }, []);
34534
34809
  useEffect64(() => {
@@ -34539,7 +34814,7 @@ function NavigationSidebar({ config, disabled = false }) {
34539
34814
  document.addEventListener("keydown", handleKeyDown);
34540
34815
  return () => document.removeEventListener("keydown", handleKeyDown);
34541
34816
  }, [isOverlayOpen, closeOverlay]);
34542
- const handleItemClick = useCallback34((item, event) => {
34817
+ const handleItemClick = useCallback35((item, event) => {
34543
34818
  event?.stopPropagation();
34544
34819
  if (item.onClick) {
34545
34820
  item.onClick();
@@ -35012,10 +35287,10 @@ function NotificationsHeaderButton({
35012
35287
  }
35013
35288
 
35014
35289
  // src/components/navigation/app-layout.tsx
35015
- import { createContext as createContext9, Suspense as Suspense2, useCallback as useCallback36, useContext as useContext9, useMemo as useMemo34, useRef as useRef46, useState as useState86 } from "react";
35290
+ import { createContext as createContext9, Suspense as Suspense2, useCallback as useCallback37, useContext as useContext9, useMemo as useMemo34, useRef as useRef46, useState as useState86 } from "react";
35016
35291
 
35017
35292
  // src/components/navigation/mobile-burger-menu.tsx
35018
- import React111, { useCallback as useCallback35, useEffect as useEffect65 } from "react";
35293
+ import React111, { useCallback as useCallback36, useEffect as useEffect65 } from "react";
35019
35294
  import { Fragment as Fragment51, jsx as jsx279, jsxs as jsxs219 } from "react/jsx-runtime";
35020
35295
  var HEADER_HEIGHT = 48;
35021
35296
  var MobileBurgerMenu = React111.memo(function MobileBurgerMenu2({
@@ -35049,7 +35324,7 @@ var MobileBurgerMenu = React111.memo(function MobileBurgerMenu2({
35049
35324
  return () => document.removeEventListener("keydown", handleKeyDown);
35050
35325
  }
35051
35326
  }, [isOpen, onClose]);
35052
- const handleItemClick = useCallback35((item) => {
35327
+ const handleItemClick = useCallback36((item) => {
35053
35328
  if (item.onClick) {
35054
35329
  item.onClick();
35055
35330
  } else if (item.path) {
@@ -35239,14 +35514,14 @@ function AppLayout({
35239
35514
  const mobileMenuOpenRef = useRef46(mobileMenuOpen);
35240
35515
  mobileMenuOpenRef.current = mobileMenuOpen;
35241
35516
  const drawerHandlesRef = useRef46(/* @__PURE__ */ new Set());
35242
- const handleToggleMobileMenu = useCallback36(() => {
35517
+ const handleToggleMobileMenu = useCallback37(() => {
35243
35518
  const opening = !mobileMenuOpenRef.current;
35244
35519
  if (opening) {
35245
35520
  for (const handle of drawerHandlesRef.current) handle.close();
35246
35521
  }
35247
35522
  setMobileMenuOpen(opening);
35248
35523
  }, []);
35249
- const handleCloseMobileMenu = useCallback36(() => {
35524
+ const handleCloseMobileMenu = useCallback37(() => {
35250
35525
  setMobileMenuOpen(false);
35251
35526
  }, []);
35252
35527
  const drawerCoordination = useMemo34(() => ({
@@ -36332,7 +36607,7 @@ ScriptArguments.displayName = "ScriptArguments";
36332
36607
 
36333
36608
  // src/components/shared/onboarding/onboarding-walkthrough.tsx
36334
36609
  init_button2();
36335
- import React114, { useRef as useRef48, useCallback as useCallback38 } from "react";
36610
+ import React114, { useRef as useRef48, useCallback as useCallback39 } from "react";
36336
36611
 
36337
36612
  // src/components/shared/onboarding/onboarding-step-card.tsx
36338
36613
  import React113 from "react";
@@ -36485,7 +36760,7 @@ function OnboardingWalkthrough({
36485
36760
  lastCompletionStatusRef.current = statusKey;
36486
36761
  }
36487
36762
  }, [completionStatus, isLoadingCompletion, state.completedSteps, markMultipleComplete]);
36488
- const handleStepAction = useCallback38(async (step) => {
36763
+ const handleStepAction = useCallback39(async (step) => {
36489
36764
  if (actionInProgressRef.current.has(step.id)) {
36490
36765
  console.log(`\u23F3 Action already in progress for "${step.id}", skipping`);
36491
36766
  return;
@@ -38128,7 +38403,7 @@ import { useMemo as useMemo36 } from "react";
38128
38403
 
38129
38404
  // src/components/ui/query-report-table/query-report-table-header.tsx
38130
38405
  init_cn();
38131
- import { useRef as useRef51, useState as useState90, useCallback as useCallback39 } from "react";
38406
+ import { useRef as useRef51, useState as useState90, useCallback as useCallback40 } from "react";
38132
38407
  import { jsx as jsx311, jsxs as jsxs246 } from "react/jsx-runtime";
38133
38408
  function QueryReportTableHeader({
38134
38409
  columns,
@@ -38159,7 +38434,7 @@ function QueryReportTableHeader({
38159
38434
  function TruncatedHeaderCell({ value, width }) {
38160
38435
  const textRef = useRef51(null);
38161
38436
  const [isTruncated, setIsTruncated] = useState90(false);
38162
- const checkTruncation = useCallback39(() => {
38437
+ const checkTruncation = useCallback40(() => {
38163
38438
  const el = textRef.current;
38164
38439
  if (el) {
38165
38440
  setIsTruncated(el.scrollWidth > el.clientWidth);
@@ -38187,7 +38462,7 @@ function TruncatedHeaderCell({ value, width }) {
38187
38462
 
38188
38463
  // src/components/ui/query-report-table/query-report-table-row.tsx
38189
38464
  init_cn();
38190
- import { useRef as useRef52, useState as useState91, useCallback as useCallback40 } from "react";
38465
+ import { useRef as useRef52, useState as useState91, useCallback as useCallback41 } from "react";
38191
38466
  import { jsx as jsx312, jsxs as jsxs247 } from "react/jsx-runtime";
38192
38467
  function QueryReportTableRow({
38193
38468
  row,
@@ -38235,7 +38510,7 @@ function QueryReportTableRow({
38235
38510
  function TruncatedCell({ value, className }) {
38236
38511
  const textRef = useRef52(null);
38237
38512
  const [isTruncated, setIsTruncated] = useState91(false);
38238
- const checkTruncation = useCallback40(() => {
38513
+ const checkTruncation = useCallback41(() => {
38239
38514
  const el = textRef.current;
38240
38515
  if (el) {
38241
38516
  setIsTruncated(el.scrollWidth > el.clientWidth);
@@ -38498,7 +38773,7 @@ init_cn();
38498
38773
 
38499
38774
  // src/components/ui/data-table/data-table-column-filter.tsx
38500
38775
  init_cn();
38501
- import { useCallback as useCallback41, useMemo as useMemo37 } from "react";
38776
+ import { useCallback as useCallback42, useMemo as useMemo37 } from "react";
38502
38777
 
38503
38778
  // src/components/ui/data-table/utils.ts
38504
38779
  function getHideClasses2(hideAt) {
@@ -38558,14 +38833,14 @@ function DataTableColumnFilter({
38558
38833
  () => ({ [column.id]: currentValue ?? EMPTY_ARRAY }),
38559
38834
  [column.id, currentValue]
38560
38835
  );
38561
- const handleApply = useCallback41(
38836
+ const handleApply = useCallback42(
38562
38837
  (applied) => {
38563
38838
  const next = applied[column.id] ?? [];
38564
38839
  column.setFilterValue(next.length > 0 ? next : void 0);
38565
38840
  },
38566
38841
  [column]
38567
38842
  );
38568
- const handleReset = useCallback41(() => {
38843
+ const handleReset = useCallback42(() => {
38569
38844
  column.setFilterValue(void 0);
38570
38845
  }, [column]);
38571
38846
  return /* @__PURE__ */ jsx316(
@@ -38733,7 +39008,7 @@ function DataTableEmpty({ className, ...props }) {
38733
39008
  // src/components/ui/data-table/data-table-row.tsx
38734
39009
  init_next_link();
38735
39010
  init_cn();
38736
- import { memo as memo5, useCallback as useCallback42, useRef as useRef53 } from "react";
39011
+ import { memo as memo5, useCallback as useCallback43, useRef as useRef53 } from "react";
38737
39012
  import { flexRender as flexRender2 } from "@tanstack/react-table";
38738
39013
 
38739
39014
  // src/components/ui/data-table/data-table-skeleton.tsx
@@ -38819,7 +39094,7 @@ function DataTableRowImpl({
38819
39094
  const isLinkMode = Boolean(href) && !onClick;
38820
39095
  const isWholeCardLink = isLinkMode && !hasSubRow;
38821
39096
  const containerRef = useRef53(null);
38822
- const handleClick = useCallback42(
39097
+ const handleClick = useCallback43(
38823
39098
  (e) => {
38824
39099
  const target = e.target;
38825
39100
  if (!containerRef.current?.contains(target)) {
@@ -39827,7 +40102,7 @@ function TagSearchInput({
39827
40102
  }
39828
40103
 
39829
40104
  // src/components/ui/markdown-editor.tsx
39830
- import { useRef as useRef57, useCallback as useCallback43, useState as useState94, useEffect as useEffect72 } from "react";
40105
+ import { useRef as useRef57, useCallback as useCallback44, useState as useState94, useEffect as useEffect72 } from "react";
39831
40106
  init_cn();
39832
40107
  import { Loader2 as Loader29, Upload as Upload8 } from "lucide-react";
39833
40108
  import { jsx as jsx327, jsxs as jsxs260 } from "react/jsx-runtime";
@@ -39896,7 +40171,7 @@ function MarkdownEditor({
39896
40171
  const handleChange = (val) => {
39897
40172
  onChange(val || "");
39898
40173
  };
39899
- const insertTextAtCursor = useCallback43(
40174
+ const insertTextAtCursor = useCallback44(
39900
40175
  (text) => {
39901
40176
  const textarea = document.querySelector(
39902
40177
  ".w-md-editor-text-textarea"
@@ -39912,7 +40187,7 @@ function MarkdownEditor({
39912
40187
  },
39913
40188
  [value, onChange]
39914
40189
  );
39915
- const handleFileUpload = useCallback43(
40190
+ const handleFileUpload = useCallback44(
39916
40191
  async (file) => {
39917
40192
  if (!onUploadFile) return;
39918
40193
  setIsUploading(true);
@@ -39933,7 +40208,7 @@ function MarkdownEditor({
39933
40208
  },
39934
40209
  [onUploadFile, insertTextAtCursor, onFileUploaded]
39935
40210
  );
39936
- const handleFileInputChange = useCallback43(
40211
+ const handleFileInputChange = useCallback44(
39937
40212
  (e) => {
39938
40213
  const file = e.target.files?.[0];
39939
40214
  if (file) {
@@ -39943,7 +40218,7 @@ function MarkdownEditor({
39943
40218
  },
39944
40219
  [handleFileUpload]
39945
40220
  );
39946
- const handlePaste = useCallback43(
40221
+ const handlePaste = useCallback44(
39947
40222
  (e) => {
39948
40223
  if (!onUploadFile) return;
39949
40224
  const items = e.clipboardData?.items;
@@ -39982,7 +40257,7 @@ function MarkdownEditor({
39982
40257
  const scrollParentRef = useRef57(window);
39983
40258
  const EDGE_ZONE = 60;
39984
40259
  const MAX_SCROLL_SPEED = 15;
39985
- const findScrollParent = useCallback43((el) => {
40260
+ const findScrollParent = useCallback44((el) => {
39986
40261
  let node = el?.parentElement;
39987
40262
  while (node && node !== document.documentElement) {
39988
40263
  const { overflowY } = window.getComputedStyle(node);
@@ -39993,7 +40268,7 @@ function MarkdownEditor({
39993
40268
  }
39994
40269
  return window;
39995
40270
  }, []);
39996
- const scrollLoop = useCallback43(() => {
40271
+ const scrollLoop = useCallback44(() => {
39997
40272
  if (!isDraggingRef.current) return;
39998
40273
  const parent = scrollParentRef.current;
39999
40274
  const isWindow = parent === window;
@@ -45557,7 +45832,7 @@ function renderChatInlineEntityCard(chatRef, options = {}) {
45557
45832
  }
45558
45833
 
45559
45834
  // src/components/chat/hooks/use-chunk-catchup.ts
45560
- import { useCallback as useCallback45, useRef as useRef61 } from "react";
45835
+ import { useCallback as useCallback46, useRef as useRef61 } from "react";
45561
45836
  function makeSeqKey(messageType, chunkType, sequenceId) {
45562
45837
  return `${messageType}:${chunkType}:${sequenceId}`;
45563
45838
  }
@@ -45594,7 +45869,7 @@ function useChunkCatchup({
45594
45869
  fetchChunksRef.current = fetchChunks;
45595
45870
  const onChunkReceivedRef = useRef61(onChunkReceived);
45596
45871
  onChunkReceivedRef.current = onChunkReceived;
45597
- const processChunk = useCallback45((chunk, messageType, forceProcess = false) => {
45872
+ const processChunk = useCallback46((chunk, messageType, forceProcess = false) => {
45598
45873
  if (bufferUntilInitialCatchupComplete.current && !forceProcess) {
45599
45874
  chunkBuffer.current.push({ chunk, messageType });
45600
45875
  return true;
@@ -45607,7 +45882,7 @@ function useChunkCatchup({
45607
45882
  onChunkReceivedRef.current(chunk, messageType);
45608
45883
  return true;
45609
45884
  }, []);
45610
- const flushBufferedRealtimeChunks = useCallback45(() => {
45885
+ const flushBufferedRealtimeChunks = useCallback46(() => {
45611
45886
  if (chunkBuffer.current.length === 0) return;
45612
45887
  const buffered = [...chunkBuffer.current];
45613
45888
  chunkBuffer.current = [];
@@ -45620,7 +45895,7 @@ function useChunkCatchup({
45620
45895
  processChunk(chunk, messageType, true);
45621
45896
  });
45622
45897
  }, [processChunk]);
45623
- const catchUpChunks = useCallback45(async (fromSequenceId) => {
45898
+ const catchUpChunks = useCallback46(async (fromSequenceId) => {
45624
45899
  const dialogId2 = dialogIdRef.current;
45625
45900
  const chatTypes2 = chatTypesRef.current;
45626
45901
  const fetchChunks2 = fetchChunksRef.current;
@@ -45733,7 +46008,7 @@ function useChunkCatchup({
45733
46008
  }
45734
46009
  }
45735
46010
  }, [flushBufferedRealtimeChunks]);
45736
- const resetChunkTracking = useCallback45(() => {
46011
+ const resetChunkTracking = useCallback46(() => {
45737
46012
  processedSequenceKeys.current.clear();
45738
46013
  lastSequenceId.current = null;
45739
46014
  fetchingInProgress.current = false;
@@ -45742,13 +46017,13 @@ function useChunkCatchup({
45742
46017
  bufferUntilInitialCatchupComplete.current = false;
45743
46018
  hasCompletedInitialCatchup.current = false;
45744
46019
  }, []);
45745
- const startInitialBuffering = useCallback45(() => {
46020
+ const startInitialBuffering = useCallback46(() => {
45746
46021
  chunkBuffer.current = [];
45747
46022
  bufferUntilInitialCatchupComplete.current = true;
45748
46023
  hasCompletedInitialCatchup.current = false;
45749
46024
  }, []);
45750
- const isBufferingActive = useCallback45(() => bufferUntilInitialCatchupComplete.current, []);
45751
- const resetAndCatchUp = useCallback45(async () => {
46025
+ const isBufferingActive = useCallback46(() => bufferUntilInitialCatchupComplete.current, []);
46026
+ const resetAndCatchUp = useCallback46(async () => {
45752
46027
  if (!dialogIdRef.current) return;
45753
46028
  const fromSeq = lastSequenceId.current;
45754
46029
  hasCompletedInitialCatchup.current = false;
@@ -46284,7 +46559,7 @@ function buildNatsWsUrl(apiBaseUrl, options) {
46284
46559
  }
46285
46560
 
46286
46561
  // src/components/chat/hooks/use-realtime-chunk-processor.ts
46287
- import { useCallback as useCallback46, useRef as useRef64, useEffect as useEffect78 } from "react";
46562
+ import { useCallback as useCallback47, useRef as useRef64, useEffect as useEffect78 } from "react";
46288
46563
 
46289
46564
  // src/components/chat/utils/chunk-parser.ts
46290
46565
  function normalizeToolCalls(raw) {
@@ -46963,7 +47238,7 @@ function useRealtimeChunkProcessor(options) {
46963
47238
  directModeFlagRef.current = isDirectMode;
46964
47239
  }, [isDirectMode]);
46965
47240
  const pendingEscalatedRef = useRef64(/* @__PURE__ */ new Map());
46966
- const processChunk = useCallback46(
47241
+ const processChunk = useCallback47(
46967
47242
  (chunk) => {
46968
47243
  const action = parseChunkToAction(chunk);
46969
47244
  if (!action) return;
@@ -47192,22 +47467,22 @@ function useRealtimeChunkProcessor(options) {
47192
47467
  },
47193
47468
  [callbacks, displayApprovalTypes, approvalStatuses, initialState]
47194
47469
  );
47195
- const getSegments = useCallback46(() => {
47470
+ const getSegments = useCallback47(() => {
47196
47471
  return accumulatorRef.current.getSegments();
47197
47472
  }, []);
47198
- const reset = useCallback46(() => {
47473
+ const reset = useCallback47(() => {
47199
47474
  accumulatorRef.current.reset();
47200
47475
  pendingEscalatedRef.current.clear();
47201
47476
  hasInitializedWithData.current = false;
47202
47477
  sawDirectMessageRef.current = false;
47203
47478
  }, []);
47204
- const updateApprovalStatus = useCallback46(
47479
+ const updateApprovalStatus = useCallback47(
47205
47480
  (requestId, status, resolvedByName) => {
47206
47481
  return accumulatorRef.current.updateApprovalStatus(requestId, status, resolvedByName);
47207
47482
  },
47208
47483
  []
47209
47484
  );
47210
- const getPendingApprovals = useCallback46(() => {
47485
+ const getPendingApprovals = useCallback47(() => {
47211
47486
  return new Map(pendingEscalatedRef.current);
47212
47487
  }, []);
47213
47488
  return {
@@ -47345,7 +47620,7 @@ function useEmptyStateConfig(emptyStateUrl, options) {
47345
47620
  }
47346
47621
 
47347
47622
  // src/components/chat/hooks/use-chat-attachments.ts
47348
- import { useCallback as useCallback47, useMemo as useMemo40, useRef as useRef65, useState as useState107 } from "react";
47623
+ import { useCallback as useCallback48, useMemo as useMemo40, useRef as useRef65, useState as useState107 } from "react";
47349
47624
  import { fileTypeFromBlob } from "file-type";
47350
47625
  var CHAT_ATTACHMENTS_BUCKET = "chat-attachments";
47351
47626
  var CHAT_ATTACHMENTS_FOLDER = "chat";
@@ -47423,10 +47698,10 @@ function useChatAttachments() {
47423
47698
  const uploadUrlEndpoint = runtime.endpoints.attachmentUploadUrl;
47424
47699
  const [attachments, setAttachments] = useState107([]);
47425
47700
  const controllersRef = useRef65(/* @__PURE__ */ new Map());
47426
- const updateOne = useCallback47((id, patch) => {
47701
+ const updateOne = useCallback48((id, patch) => {
47427
47702
  setAttachments((prev) => prev.map((a) => a.id === id ? { ...a, ...patch } : a));
47428
47703
  }, []);
47429
- const removeAttachment = useCallback47((id) => {
47704
+ const removeAttachment = useCallback48((id) => {
47430
47705
  const ctrl = controllersRef.current.get(id);
47431
47706
  if (ctrl) {
47432
47707
  ctrl.abort();
@@ -47434,12 +47709,12 @@ function useChatAttachments() {
47434
47709
  }
47435
47710
  setAttachments((prev) => prev.filter((a) => a.id !== id));
47436
47711
  }, []);
47437
- const clear = useCallback47(() => {
47712
+ const clear = useCallback48(() => {
47438
47713
  for (const ctrl of controllersRef.current.values()) ctrl.abort();
47439
47714
  controllersRef.current.clear();
47440
47715
  setAttachments([]);
47441
47716
  }, []);
47442
- const uploadOne = useCallback47(
47717
+ const uploadOne = useCallback48(
47443
47718
  async (att) => {
47444
47719
  const ctrl = controllersRef.current.get(att.id);
47445
47720
  try {
@@ -47513,7 +47788,7 @@ function useChatAttachments() {
47513
47788
  );
47514
47789
  const attachmentsRef = useRef65([]);
47515
47790
  attachmentsRef.current = attachments;
47516
- const addFiles = useCallback47(
47791
+ const addFiles = useCallback48(
47517
47792
  (files) => {
47518
47793
  const arr = Array.from(files);
47519
47794
  if (arr.length === 0) return;
@@ -47588,7 +47863,7 @@ function useChatAttachments() {
47588
47863
  }
47589
47864
 
47590
47865
  // src/components/chat/hooks/use-chat-attachment-image-gallery.tsx
47591
- import { useCallback as useCallback48, useEffect as useEffect80, useRef as useRef66, useState as useState108 } from "react";
47866
+ import { useCallback as useCallback49, useEffect as useEffect80, useRef as useRef66, useState as useState108 } from "react";
47592
47867
  import { jsx as jsx351 } from "react/jsx-runtime";
47593
47868
  var CLOSED = { isOpen: false, images: [], initialIndex: 0 };
47594
47869
  function useChatAttachmentImageGallery() {
@@ -47596,7 +47871,7 @@ function useChatAttachmentImageGallery() {
47596
47871
  const viewUrlPrefix = runtime.endpoints.attachmentViewUrlPrefix;
47597
47872
  const panelRef = useRef66(null);
47598
47873
  const [state, setState] = useState108(CLOSED);
47599
- const handleClose = useCallback48(() => setState(CLOSED), []);
47874
+ const handleClose = useCallback49(() => setState(CLOSED), []);
47600
47875
  useEffect80(() => {
47601
47876
  const root = panelRef.current;
47602
47877
  if (!root) return;
@@ -47716,20 +47991,20 @@ function useCloseOnNavigation(close, pathname) {
47716
47991
  }
47717
47992
 
47718
47993
  // src/components/chat/hooks/use-chat.ts
47719
- import { useState as useState111, useCallback as useCallback50, useEffect as useEffect83, useRef as useRef69 } from "react";
47994
+ import { useState as useState111, useCallback as useCallback51, useEffect as useEffect83, useRef as useRef69 } from "react";
47720
47995
 
47721
47996
  // src/components/chat/hooks/use-sse.ts
47722
- import { useState as useState110, useCallback as useCallback49, useRef as useRef68 } from "react";
47997
+ import { useState as useState110, useCallback as useCallback50, useRef as useRef68 } from "react";
47723
47998
  function useSSE({ useMock = true, debugMode = false, streamFn } = {}) {
47724
47999
  const [isStreaming, setIsStreaming] = useState110(false);
47725
48000
  const [error, setError] = useState110(null);
47726
48001
  const abortControllerRef = useRef68(null);
47727
- const fallbackStream = useCallback49(async function* () {
48002
+ const fallbackStream = useCallback50(async function* () {
47728
48003
  throw new Error(
47729
48004
  "[useSSE] No streamFn provided and `useMock: true` is no longer wired into the lib. Supply a `streamFn` (see `createDocStreamFn` in use-embedded-chat) or migrate the mock to your host code."
47730
48005
  );
47731
48006
  }, []);
47732
- const streamMessage = useCallback49(
48007
+ const streamMessage = useCallback50(
47733
48008
  async function* (message2, extra) {
47734
48009
  setIsStreaming(true);
47735
48010
  setError(null);
@@ -47759,13 +48034,13 @@ function useSSE({ useMock = true, debugMode = false, streamFn } = {}) {
47759
48034
  },
47760
48035
  [streamFn, fallbackStream]
47761
48036
  );
47762
- const abort = useCallback49(() => {
48037
+ const abort = useCallback50(() => {
47763
48038
  if (abortControllerRef.current) {
47764
48039
  abortControllerRef.current.abort();
47765
48040
  }
47766
48041
  setIsStreaming(false);
47767
48042
  }, []);
47768
- const reset = useCallback49(() => {
48043
+ const reset = useCallback50(() => {
47769
48044
  }, []);
47770
48045
  return {
47771
48046
  streamMessage,
@@ -47808,10 +48083,10 @@ function useChat({
47808
48083
  debugMode,
47809
48084
  streamFn
47810
48085
  });
47811
- const addMessage = useCallback50((message2) => {
48086
+ const addMessage = useCallback51((message2) => {
47812
48087
  setMessages((prev) => [...prev, message2]);
47813
48088
  }, []);
47814
- const updateLastAssistantMessage = useCallback50((segments) => {
48089
+ const updateLastAssistantMessage = useCallback51((segments) => {
47815
48090
  setMessages((prev) => {
47816
48091
  const newMessages = [...prev];
47817
48092
  const lastMessage = newMessages[newMessages.length - 1];
@@ -47824,7 +48099,7 @@ function useChat({
47824
48099
  return newMessages;
47825
48100
  });
47826
48101
  }, []);
47827
- const sendMessage = useCallback50(
48102
+ const sendMessage = useCallback51(
47828
48103
  async (text, extra, options) => {
47829
48104
  const userMessage = {
47830
48105
  id: `user-${Date.now()}`,
@@ -48054,18 +48329,18 @@ function useChat({
48054
48329
  },
48055
48330
  [streamMessage, addMessage, updateLastAssistantMessage, assistantName, assistantAvatar]
48056
48331
  );
48057
- const handleQuickAction = useCallback50(
48332
+ const handleQuickAction = useCallback51(
48058
48333
  (actionText) => {
48059
48334
  sendMessage(actionText);
48060
48335
  },
48061
48336
  [sendMessage]
48062
48337
  );
48063
- const clearMessages = useCallback50(() => {
48338
+ const clearMessages = useCallback51(() => {
48064
48339
  setMessages([]);
48065
48340
  setIsTyping(false);
48066
48341
  reset();
48067
48342
  }, [reset]);
48068
- const stopMessage = useCallback50(() => {
48343
+ const stopMessage = useCallback51(() => {
48069
48344
  abort();
48070
48345
  setIsTyping(false);
48071
48346
  }, [abort]);
@@ -48083,7 +48358,7 @@ function useChat({
48083
48358
  }
48084
48359
 
48085
48360
  // src/components/chat/hooks/use-sse-chat-adapter.ts
48086
- import { useState as useState112, useEffect as useEffect84, useCallback as useCallback51, useMemo as useMemo41, useRef as useRef70 } from "react";
48361
+ import { useState as useState112, useEffect as useEffect84, useCallback as useCallback52, useMemo as useMemo41, useRef as useRef70 } from "react";
48087
48362
  function createEmptyTurnMeta() {
48088
48363
  return {
48089
48364
  provider: null,
@@ -48420,7 +48695,7 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
48420
48695
  const sendCountRef = useRef70(persistedRef.current.sendCount);
48421
48696
  const [streamingPhase, setStreamingPhase] = useState112("idle");
48422
48697
  const [metaTick, setMetaTick] = useState112(0);
48423
- const bumpMetaTick = useCallback51(() => setMetaTick((t) => t + 1), []);
48698
+ const bumpMetaTick = useCallback52(() => setMetaTick((t) => t + 1), []);
48424
48699
  const streamFn = useMemo41(
48425
48700
  () => createDocStreamFn(
48426
48701
  source,
@@ -48467,7 +48742,7 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
48467
48742
  }
48468
48743
  return map;
48469
48744
  }, [slashCommands]);
48470
- const persist = useCallback51(
48745
+ const persist = useCallback52(
48471
48746
  (nextMessages) => {
48472
48747
  savePersistedChat(source, {
48473
48748
  messages: nextMessages,
@@ -48521,7 +48796,7 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
48521
48796
  ...m.hidden ? { hidden: true } : {}
48522
48797
  };
48523
48798
  });
48524
- const sendMessage = useCallback51(
48799
+ const sendMessage = useCallback52(
48525
48800
  async (text, options2) => {
48526
48801
  const {
48527
48802
  hidden,
@@ -48540,7 +48815,7 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
48540
48815
  },
48541
48816
  [chatSendMessage]
48542
48817
  );
48543
- const displayRef = useCallback51(
48818
+ const displayRef = useCallback52(
48544
48819
  (reference) => {
48545
48820
  const tableId = tableIdForDocumentType(reference.type);
48546
48821
  if (!tableId) {
@@ -48564,7 +48839,7 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
48564
48839
  },
48565
48840
  [sendMessage, source, cmdIdByTableId, tableIdForDocumentType]
48566
48841
  );
48567
- const discussRef = useCallback51(
48842
+ const discussRef = useCallback52(
48568
48843
  (reference) => {
48569
48844
  const tableId = tableIdForDocumentType(reference.type);
48570
48845
  if (!tableId) {
@@ -48588,11 +48863,11 @@ function useSseChatAdapter(options, runtimeOptions = {}) {
48588
48863
  },
48589
48864
  [sendMessage, tableIdForDocumentType]
48590
48865
  );
48591
- const stopMessage = useCallback51(() => {
48866
+ const stopMessage = useCallback52(() => {
48592
48867
  chatStopMessage();
48593
48868
  setStreamingPhase("idle");
48594
48869
  }, [chatStopMessage]);
48595
- const clearMessages = useCallback51(() => {
48870
+ const clearMessages = useCallback52(() => {
48596
48871
  sourcesMapRef.current.clear();
48597
48872
  refsMapRef.current.clear();
48598
48873
  metaMapRef.current.clear();
@@ -48688,7 +48963,7 @@ var noopRejectRequest = async (_id, _reason) => {
48688
48963
 
48689
48964
  // src/components/chat/hooks/use-nats-chat-adapter.ts
48690
48965
  import {
48691
- useCallback as useCallback52,
48966
+ useCallback as useCallback53,
48692
48967
  useEffect as useEffect85,
48693
48968
  useMemo as useMemo42,
48694
48969
  useRef as useRef71,
@@ -49199,7 +49474,7 @@ function useNatsChatAdapter(config, options = {}) {
49199
49474
  );
49200
49475
  const [liveModel, setLiveModel] = useState113(null);
49201
49476
  const [connectionState, setConnectionState] = useState113("connecting");
49202
- const handleApprove = useCallback52(
49477
+ const handleApprove = useCallback53(
49203
49478
  async (requestId) => {
49204
49479
  if (!approveRequestCallback) return;
49205
49480
  setApprovalStatuses((prev) => ({ ...prev, [requestId]: "approved" }));
@@ -49216,7 +49491,7 @@ function useNatsChatAdapter(config, options = {}) {
49216
49491
  },
49217
49492
  [approveRequestCallback]
49218
49493
  );
49219
- const handleReject = useCallback52(
49494
+ const handleReject = useCallback53(
49220
49495
  async (requestId, reason) => {
49221
49496
  if (!rejectRequestCallback) return;
49222
49497
  setApprovalStatuses((prev) => ({ ...prev, [requestId]: "rejected" }));
@@ -49237,11 +49512,11 @@ function useNatsChatAdapter(config, options = {}) {
49237
49512
  handleApproveRef.current = handleApprove;
49238
49513
  const handleRejectRef = useRef71(handleReject);
49239
49514
  handleRejectRef.current = handleReject;
49240
- const accumApprove = useCallback52((requestId) => {
49515
+ const accumApprove = useCallback53((requestId) => {
49241
49516
  if (!requestId) return;
49242
49517
  return handleApproveRef.current(requestId);
49243
49518
  }, []);
49244
- const accumReject = useCallback52((requestId) => {
49519
+ const accumReject = useCallback53((requestId) => {
49245
49520
  if (!requestId) return;
49246
49521
  return handleRejectRef.current(requestId);
49247
49522
  }, []);
@@ -49284,7 +49559,7 @@ function useNatsChatAdapter(config, options = {}) {
49284
49559
  fetchChunks
49285
49560
  });
49286
49561
  const historyLoadSeqRef = useRef71(0);
49287
- const loadDialogHistory = useCallback52(
49562
+ const loadDialogHistory = useCallback53(
49288
49563
  async (id, cursor) => {
49289
49564
  if (!fetchDialogMessages) return;
49290
49565
  historyLoadSeqRef.current += 1;
@@ -49383,7 +49658,7 @@ function useNatsChatAdapter(config, options = {}) {
49383
49658
  setConnectionState("connecting");
49384
49659
  }, [active, dialogId]);
49385
49660
  const initialDialogsLoadedRef = useRef71(false);
49386
- const loadDialogsPage = useCallback52(
49661
+ const loadDialogsPage = useCallback53(
49387
49662
  async (cursor) => {
49388
49663
  if (!fetchDialogs) return;
49389
49664
  setIsDialogsLoading(true);
@@ -49411,7 +49686,7 @@ function useNatsChatAdapter(config, options = {}) {
49411
49686
  },
49412
49687
  [fetchDialogs, dialogsPageSize]
49413
49688
  );
49414
- const reloadDialogs = useCallback52(() => {
49689
+ const reloadDialogs = useCallback53(() => {
49415
49690
  void loadDialogsPage();
49416
49691
  }, [loadDialogsPage]);
49417
49692
  useEffect85(() => {
@@ -49421,7 +49696,7 @@ function useNatsChatAdapter(config, options = {}) {
49421
49696
  initialDialogsLoadedRef.current = true;
49422
49697
  void loadDialogsPage();
49423
49698
  }, [active, fetchDialogs, loadDialogsPage]);
49424
- const sendMessage = useCallback52(
49699
+ const sendMessage = useCallback53(
49425
49700
  async (text, sendOptions) => {
49426
49701
  const hidden = sendOptions?.hidden ?? false;
49427
49702
  setMessages((prev) => [
@@ -49444,7 +49719,7 @@ function useNatsChatAdapter(config, options = {}) {
49444
49719
  },
49445
49720
  [publishUserMessage, dialogId]
49446
49721
  );
49447
- const stopMessage = useCallback52(() => {
49722
+ const stopMessage = useCallback53(() => {
49448
49723
  setStreamingPhase("idle");
49449
49724
  if (stopGenerationCallback && dialogId) {
49450
49725
  void stopGenerationCallback(dialogId).catch((err) => {
@@ -49452,12 +49727,12 @@ function useNatsChatAdapter(config, options = {}) {
49452
49727
  });
49453
49728
  }
49454
49729
  }, [stopGenerationCallback, dialogId]);
49455
- const clearMessages = useCallback52(() => {
49730
+ const clearMessages = useCallback53(() => {
49456
49731
  setMessages([]);
49457
49732
  resetAccumulator();
49458
49733
  setStreamingPhase("idle");
49459
49734
  }, [resetAccumulator]);
49460
- const selectDialog = useCallback52(
49735
+ const selectDialog = useCallback53(
49461
49736
  (id) => {
49462
49737
  if (!isManagedMode) {
49463
49738
  return;
@@ -49466,7 +49741,7 @@ function useNatsChatAdapter(config, options = {}) {
49466
49741
  },
49467
49742
  [isManagedMode]
49468
49743
  );
49469
- const startNewDialog = useCallback52(async () => {
49744
+ const startNewDialog = useCallback53(async () => {
49470
49745
  if (!createDialogCallback) return null;
49471
49746
  if (isCreatingDialog) return null;
49472
49747
  try {
@@ -49491,7 +49766,7 @@ function useNatsChatAdapter(config, options = {}) {
49491
49766
  setIsCreatingDialog(false);
49492
49767
  }
49493
49768
  }, [createDialogCallback, isCreatingDialog, isManagedMode]);
49494
- const deleteDialog = useCallback52(
49769
+ const deleteDialog = useCallback53(
49495
49770
  async (id) => {
49496
49771
  if (!deleteDialogCallback) return;
49497
49772
  try {
@@ -49506,7 +49781,7 @@ function useNatsChatAdapter(config, options = {}) {
49506
49781
  },
49507
49782
  [deleteDialogCallback, internalDialogId, isManagedMode]
49508
49783
  );
49509
- const renameDialog = useCallback52(
49784
+ const renameDialog = useCallback53(
49510
49785
  async (id, title) => {
49511
49786
  if (!renameDialogCallback) return;
49512
49787
  let previous;
@@ -49530,7 +49805,7 @@ function useNatsChatAdapter(config, options = {}) {
49530
49805
  },
49531
49806
  [renameDialogCallback]
49532
49807
  );
49533
- const archiveDialog = useCallback52(
49808
+ const archiveDialog = useCallback53(
49534
49809
  async (id) => {
49535
49810
  if (!archiveDialogCallback) return;
49536
49811
  try {
@@ -49545,29 +49820,29 @@ function useNatsChatAdapter(config, options = {}) {
49545
49820
  },
49546
49821
  [archiveDialogCallback, internalDialogId, isManagedMode]
49547
49822
  );
49548
- const loadMoreDialogs = useCallback52(async () => {
49823
+ const loadMoreDialogs = useCallback53(async () => {
49549
49824
  if (!dialogsNextCursor) return;
49550
49825
  await loadDialogsPage(dialogsNextCursor);
49551
49826
  }, [dialogsNextCursor, loadDialogsPage]);
49552
- const loadMoreMessages = useCallback52(async () => {
49827
+ const loadMoreMessages = useCallback53(async () => {
49553
49828
  if (!dialogId || !messagesNextCursor) return;
49554
49829
  await loadDialogHistory(dialogId, messagesNextCursor);
49555
49830
  }, [dialogId, messagesNextCursor, loadDialogHistory]);
49556
- const approveRequest = useCallback52(
49831
+ const approveRequest = useCallback53(
49557
49832
  async (requestId) => {
49558
49833
  await handleApproveRef.current(requestId);
49559
49834
  },
49560
49835
  []
49561
49836
  );
49562
- const rejectRequest = useCallback52(
49837
+ const rejectRequest = useCallback53(
49563
49838
  async (requestId, reason) => {
49564
49839
  await handleRejectRef.current(requestId, reason);
49565
49840
  },
49566
49841
  []
49567
49842
  );
49568
- const discussRef = useCallback52((_ref) => {
49843
+ const discussRef = useCallback53((_ref) => {
49569
49844
  }, []);
49570
- const displayRef = useCallback52((_ref) => {
49845
+ const displayRef = useCallback53((_ref) => {
49571
49846
  }, []);
49572
49847
  const isLoading = streamingPhase !== "idle";
49573
49848
  const hasMoreDialogs = dialogsNextCursor != null;
@@ -49655,7 +49930,7 @@ function useNatsChatAdapter(config, options = {}) {
49655
49930
  }
49656
49931
 
49657
49932
  // src/components/chat/hooks/use-unified-chat.ts
49658
- import { useCallback as useCallback53, useMemo as useMemo43, useRef as useRef72 } from "react";
49933
+ import { useCallback as useCallback54, useMemo as useMemo43, useRef as useRef72 } from "react";
49659
49934
  var EMPTY_SSE_OPTIONS = {};
49660
49935
  function createDisabledNatsConfig() {
49661
49936
  return {
@@ -49686,60 +49961,60 @@ function useUnifiedChat(options) {
49686
49961
  const activeState = activeMode === "guide" ? sseState : mingoStateOverride ?? natsState;
49687
49962
  const activeStateRef = useRef72(activeState);
49688
49963
  activeStateRef.current = activeState;
49689
- const stopMessage = useCallback53(() => activeStateRef.current.stopMessage(), []);
49690
- const clearMessages = useCallback53(
49964
+ const stopMessage = useCallback54(() => activeStateRef.current.stopMessage(), []);
49965
+ const clearMessages = useCallback54(
49691
49966
  () => activeStateRef.current.clearMessages(),
49692
49967
  []
49693
49968
  );
49694
- const sendMessage = useCallback53(
49969
+ const sendMessage = useCallback54(
49695
49970
  (text, opts) => activeStateRef.current.sendMessage(text, opts),
49696
49971
  []
49697
49972
  );
49698
- const discussRef = useCallback53(
49973
+ const discussRef = useCallback54(
49699
49974
  (ref) => activeStateRef.current.discussRef(ref),
49700
49975
  []
49701
49976
  );
49702
- const displayRef = useCallback53(
49977
+ const displayRef = useCallback54(
49703
49978
  (ref) => activeStateRef.current.displayRef(ref),
49704
49979
  []
49705
49980
  );
49706
- const selectDialog = useCallback53(
49981
+ const selectDialog = useCallback54(
49707
49982
  (id) => activeStateRef.current.selectDialog(id),
49708
49983
  []
49709
49984
  );
49710
- const startNewDialog = useCallback53(
49985
+ const startNewDialog = useCallback54(
49711
49986
  () => activeStateRef.current.startNewDialog(),
49712
49987
  []
49713
49988
  );
49714
- const deleteDialog = useCallback53(
49989
+ const deleteDialog = useCallback54(
49715
49990
  (id) => activeStateRef.current.deleteDialog(id),
49716
49991
  []
49717
49992
  );
49718
- const renameDialog = useCallback53(
49993
+ const renameDialog = useCallback54(
49719
49994
  (id, title) => activeStateRef.current.renameDialog(id, title),
49720
49995
  []
49721
49996
  );
49722
- const archiveDialog = useCallback53(
49997
+ const archiveDialog = useCallback54(
49723
49998
  (id) => activeStateRef.current.archiveDialog(id),
49724
49999
  []
49725
50000
  );
49726
- const loadMoreDialogs = useCallback53(
50001
+ const loadMoreDialogs = useCallback54(
49727
50002
  () => activeStateRef.current.loadMoreDialogs(),
49728
50003
  []
49729
50004
  );
49730
- const reloadDialogs = useCallback53(
50005
+ const reloadDialogs = useCallback54(
49731
50006
  () => activeStateRef.current.reloadDialogs(),
49732
50007
  []
49733
50008
  );
49734
- const loadMoreMessages = useCallback53(
50009
+ const loadMoreMessages = useCallback54(
49735
50010
  () => activeStateRef.current.loadMoreMessages(),
49736
50011
  []
49737
50012
  );
49738
- const approveRequest = useCallback53(
50013
+ const approveRequest = useCallback54(
49739
50014
  (requestId) => activeStateRef.current.approveRequest(requestId),
49740
50015
  []
49741
50016
  );
49742
- const rejectRequest = useCallback53(
50017
+ const rejectRequest = useCallback54(
49743
50018
  (requestId, reason) => activeStateRef.current.rejectRequest(requestId, reason),
49744
50019
  []
49745
50020
  );
@@ -49994,7 +50269,7 @@ function chatChipClass({ tone, density = "chip", extra }) {
49994
50269
  }
49995
50270
 
49996
50271
  // src/components/chat/embeddable-chat.tsx
49997
- import { useCallback as useCallback55, useEffect as useEffect86, useMemo as useMemo45, useRef as useRef73, useState as useState115 } from "react";
50272
+ import { useCallback as useCallback56, useEffect as useEffect86, useMemo as useMemo45, useRef as useRef73, useState as useState115 } from "react";
49998
50273
  import * as DialogPrimitive4 from "@radix-ui/react-dialog";
49999
50274
  import { usePreventScroll } from "@react-aria/overlays";
50000
50275
  import { isIOS } from "@react-aria/utils";
@@ -50075,7 +50350,7 @@ init_button2();
50075
50350
  import { FileText as FileText8, MessageSquare as MessageSquare3 } from "lucide-react";
50076
50351
 
50077
50352
  // src/components/chat/hooks/use-chat-dialog-manager.ts
50078
- import { useCallback as useCallback54, useMemo as useMemo44, useState as useState114 } from "react";
50353
+ import { useCallback as useCallback55, useMemo as useMemo44, useState as useState114 } from "react";
50079
50354
  function useChatDialogManager({
50080
50355
  dialogs,
50081
50356
  activeDialogId,
@@ -50088,14 +50363,14 @@ function useChatDialogManager({
50088
50363
  }) {
50089
50364
  const [renameTarget, setRenameTarget] = useState114(null);
50090
50365
  const [archiveTarget, setArchiveTarget] = useState114(null);
50091
- const handleConfirmRename = useCallback54(
50366
+ const handleConfirmRename = useCallback55(
50092
50367
  (name) => {
50093
50368
  if (renameTarget) void renameDialog(renameTarget.id, name);
50094
50369
  setRenameTarget(null);
50095
50370
  },
50096
50371
  [renameTarget, renameDialog]
50097
50372
  );
50098
- const handleConfirmArchive = useCallback54(async () => {
50373
+ const handleConfirmArchive = useCallback55(async () => {
50099
50374
  if (archiveTarget) {
50100
50375
  try {
50101
50376
  await archiveDialog(archiveTarget.id);
@@ -50114,7 +50389,7 @@ function useChatDialogManager({
50114
50389
  const [archivedDialogs, setArchivedDialogs] = useState114([]);
50115
50390
  const [archivedCursor, setArchivedCursor] = useState114(null);
50116
50391
  const [archivedLoading, setArchivedLoading] = useState114(false);
50117
- const loadArchivedPage = useCallback54(
50392
+ const loadArchivedPage = useCallback55(
50118
50393
  async (cursor) => {
50119
50394
  if (!fetchArchivedDialogs) return;
50120
50395
  setArchivedLoading(true);
@@ -50132,18 +50407,18 @@ function useChatDialogManager({
50132
50407
  },
50133
50408
  [fetchArchivedDialogs]
50134
50409
  );
50135
- const openArchive = useCallback54(() => {
50410
+ const openArchive = useCallback55(() => {
50136
50411
  setArchiveOpen(true);
50137
50412
  setArchivedDialogs([]);
50138
50413
  setArchivedCursor(null);
50139
50414
  void loadArchivedPage();
50140
50415
  }, [loadArchivedPage]);
50141
- const closeArchive = useCallback54(() => setArchiveOpen(false), []);
50416
+ const closeArchive = useCallback55(() => setArchiveOpen(false), []);
50142
50417
  const [viewingArchivedId, setViewingArchivedId] = useState114(
50143
50418
  null
50144
50419
  );
50145
50420
  const [openingDialogId, setOpeningDialogId] = useState114(null);
50146
- const handleSelectDialog = useCallback54(
50421
+ const handleSelectDialog = useCallback55(
50147
50422
  (id) => {
50148
50423
  setViewingArchivedId(null);
50149
50424
  setOpeningDialogId(id);
@@ -50152,7 +50427,7 @@ function useChatDialogManager({
50152
50427
  [selectDialog]
50153
50428
  );
50154
50429
  const isOpeningDialog = openingDialogId != null && openingDialogId === activeDialogId;
50155
- const handleArchivedSelect = useCallback54(
50430
+ const handleArchivedSelect = useCallback55(
50156
50431
  (id) => {
50157
50432
  setArchiveOpen(false);
50158
50433
  setOpeningDialogId(null);
@@ -50162,7 +50437,7 @@ function useChatDialogManager({
50162
50437
  [selectDialog]
50163
50438
  );
50164
50439
  const [restoreTarget, setRestoreTarget] = useState114(null);
50165
- const handleConfirmRestore = useCallback54(async () => {
50440
+ const handleConfirmRestore = useCallback55(async () => {
50166
50441
  if (restoreTarget) {
50167
50442
  try {
50168
50443
  await unarchiveDialog?.(restoreTarget.id);
@@ -50176,7 +50451,7 @@ function useChatDialogManager({
50176
50451
  setRestoreTarget(null);
50177
50452
  }, [restoreTarget, unarchiveDialog]);
50178
50453
  const isViewingArchived = viewingArchivedId != null && viewingArchivedId === activeDialogId;
50179
- const handleBack = useCallback54(() => {
50454
+ const handleBack = useCallback55(() => {
50180
50455
  const wasArchived = isViewingArchived;
50181
50456
  setViewingArchivedId(null);
50182
50457
  setOpeningDialogId(null);
@@ -50612,7 +50887,7 @@ function EmbeddableChatInner({
50612
50887
  const initialActiveMode = controlledActiveMode ?? defaultActiveMode ?? (effectiveModes.guide ? "guide" : "mingo");
50613
50888
  const [uncontrolledActiveMode, setUncontrolledActiveMode] = useState115(initialActiveMode);
50614
50889
  const activeMode = controlledActiveMode ?? uncontrolledActiveMode;
50615
- const handleActiveModeChange = useCallback55(
50890
+ const handleActiveModeChange = useCallback56(
50616
50891
  (next) => {
50617
50892
  if (controlledActiveMode === void 0) {
50618
50893
  setUncontrolledActiveMode(next);
@@ -50716,7 +50991,7 @@ function EmbeddableChatInner({
50716
50991
  for (const t of contextEntityTypes ?? []) byType.set(t.type, t.icon);
50717
50992
  return (item) => byType.get(item.type);
50718
50993
  }, [contextEntityTypes]);
50719
- const toggleContextItem = useCallback55(
50994
+ const toggleContextItem = useCallback56(
50720
50995
  (item) => {
50721
50996
  const key = `${item.type}:${item.id}`;
50722
50997
  if (mentionActiveRef.current) {
@@ -50739,7 +51014,7 @@ function EmbeddableChatInner({
50739
51014
  },
50740
51015
  [contextMaxItems, contextItems, mentionMarkerByType, resolveContextIcon]
50741
51016
  );
50742
- const removeContextItem = useCallback55((item) => {
51017
+ const removeContextItem = useCallback56((item) => {
50743
51018
  const key = `${item.type}:${item.id}`;
50744
51019
  setContextItems((prev) => prev.filter((p) => `${p.type}:${p.id}` !== key));
50745
51020
  if (mentionKeysRef.current.has(key)) {
@@ -50749,7 +51024,7 @@ function EmbeddableChatInner({
50749
51024
  chatInputRef.current?.setValue(next);
50750
51025
  }
50751
51026
  }, [mentionMarkerByType]);
50752
- const handleContextValueChange = useCallback55((value) => {
51027
+ const handleContextValueChange = useCallback56((value) => {
50753
51028
  for (const key of Array.from(mentionKeysRef.current)) {
50754
51029
  if (!value.includes(`@${mentionTokenOf(key, mentionMarkerByType)}`)) {
50755
51030
  mentionKeysRef.current.delete(key);
@@ -50757,24 +51032,24 @@ function EmbeddableChatInner({
50757
51032
  }
50758
51033
  }
50759
51034
  }, [mentionMarkerByType]);
50760
- const openContextPicker = useCallback55(() => {
51035
+ const openContextPicker = useCallback56(() => {
50761
51036
  setMentionQuery(null);
50762
51037
  setContextPickerOpen(true);
50763
51038
  }, []);
50764
- const closeContextPicker = useCallback55(() => {
51039
+ const closeContextPicker = useCallback56(() => {
50765
51040
  if (mentionActiveRef.current) {
50766
51041
  chatInputRef.current?.removeMentionTrigger();
50767
51042
  }
50768
51043
  setContextPickerOpen(false);
50769
51044
  setMentionQuery(null);
50770
51045
  }, []);
50771
- const handleMentionQueryChange = useCallback55((query) => {
51046
+ const handleMentionQueryChange = useCallback56((query) => {
50772
51047
  setMentionQuery(query);
50773
51048
  setContextPickerOpen(query !== null);
50774
51049
  }, []);
50775
51050
  const resolvedBaseRoute = baseRoute || (source === "flamingo" ? "/knowledge-base" : "/data-room");
50776
- const handleClose = useCallback55(() => setIsOpen(false), [setIsOpen]);
50777
- const handleNavigationClose = useCallback55(() => {
51051
+ const handleClose = useCallback56(() => setIsOpen(false), [setIsOpen]);
51052
+ const handleNavigationClose = useCallback56(() => {
50778
51053
  navigatingAwayRef.current = true;
50779
51054
  setIsOpen(false);
50780
51055
  }, [setIsOpen]);
@@ -50782,7 +51057,7 @@ function EmbeddableChatInner({
50782
51057
  () => ({ closeChat: handleNavigationClose }),
50783
51058
  [handleNavigationClose]
50784
51059
  );
50785
- const renderEntityCard = useCallback55(
51060
+ const renderEntityCard = useCallback56(
50786
51061
  (reference) => renderChatInlineEntityCard(reference, {
50787
51062
  onDiscuss: discussRef,
50788
51063
  onDisplay: displayRef,
@@ -50839,7 +51114,7 @@ function EmbeddableChatInner({
50839
51114
  }
50840
51115
  return mapped;
50841
51116
  }, [rawMessages, guideUserName, guideUserAvatar]);
50842
- const handleSend = useCallback55(
51117
+ const handleSend = useCallback56(
50843
51118
  (text) => {
50844
51119
  let augmentedText = text;
50845
51120
  if (readyAttachments.length > 0) {
@@ -50919,7 +51194,7 @@ function EmbeddableChatInner({
50919
51194
  fetchArchivedDialogs: mingoCaps.fetchArchivedDialogs,
50920
51195
  unarchiveDialog: mingoCaps.unarchiveDialog
50921
51196
  });
50922
- const handleOpen = useCallback55(() => setIsOpen(true), [setIsOpen]);
51197
+ const handleOpen = useCallback56(() => setIsOpen(true), [setIsOpen]);
50923
51198
  useCloseOnNavigation(handleNavigationClose, null);
50924
51199
  useEffect86(() => {
50925
51200
  const handler = (e) => {
@@ -51717,6 +51992,7 @@ export {
51717
51992
  SECTION_HEADING_CLASS,
51718
51993
  PageHeading,
51719
51994
  VideoBitesStrip,
51995
+ VideoBiteCard,
51720
51996
  EntityVideoSection,
51721
51997
  ChatVideoEntityCard,
51722
51998
  ProductReleaseCard,
@@ -52255,4 +52531,4 @@ export {
52255
52531
  LogsList,
52256
52532
  assets
52257
52533
  };
52258
- //# sourceMappingURL=chunk-VCRUAKOJ.js.map
52534
+ //# sourceMappingURL=chunk-IDWKP5H5.js.map