@sesionario/blocks 1.22.3 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -10,12 +10,12 @@ var jsxRuntime = require('react/jsx-runtime');
10
10
  var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
11
11
  var reactSlot = require('@radix-ui/react-slot');
12
12
  var reactDom = require('react-dom');
13
+ var DialogPrimitive = require('@radix-ui/react-dialog');
13
14
  var nextThemes = require('next-themes');
14
15
  var framerMotion = require('framer-motion');
15
16
  var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
16
17
  var SliderPrimitive = require('@radix-ui/react-slider');
17
18
  var TogglePrimitive = require('@radix-ui/react-toggle');
18
- var DialogPrimitive = require('@radix-ui/react-dialog');
19
19
  var vaul = require('vaul');
20
20
  var PopoverPrimitive = require('@radix-ui/react-popover');
21
21
  var cmdk = require('cmdk');
@@ -46,10 +46,10 @@ function _interopNamespace(e) {
46
46
 
47
47
  var React7__namespace = /*#__PURE__*/_interopNamespace(React7);
48
48
  var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
49
+ var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
49
50
  var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
50
51
  var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
51
52
  var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespace(TogglePrimitive);
52
- var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
53
53
  var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
54
54
  var RPNInput__namespace = /*#__PURE__*/_interopNamespace(RPNInput);
55
55
  var flags__default = /*#__PURE__*/_interopDefault(flags);
@@ -860,19 +860,19 @@ function ExpandableText({
860
860
  ) : null
861
861
  ] });
862
862
  }
863
- var MIN_SCALE = 1;
864
- var MAX_SCALE = 4;
865
- var DOUBLE_TAP_MS = 300;
866
- var SWIPE_LOCK_PX = 8;
867
- var SWIPE_COMMIT_PX = 56;
868
- var SWIPE_SNAP_MS = 180;
863
+ var ZOOM_PAN_MIN_SCALE = 1;
864
+ var ZOOM_PAN_MAX_SCALE = 4;
865
+ var ZOOM_PAN_DOUBLE_TAP_MS = 300;
866
+ var ZOOM_PAN_SWIPE_LOCK_PX = 8;
867
+ var ZOOM_PAN_SWIPE_COMMIT_PX = 56;
868
+ var ZOOM_PAN_SWIPE_SNAP_MS = 180;
869
869
  var IDENTITY = { scale: 1, tx: 0, ty: 0 };
870
870
  function clamp(value, min, max) {
871
871
  return Math.min(max, Math.max(min, value));
872
872
  }
873
- function zoomToward(prev, nextScale, originX, originY) {
874
- const scale = clamp(nextScale, MIN_SCALE, MAX_SCALE);
875
- if (scale === MIN_SCALE) return IDENTITY;
873
+ function zoomToward(prev, nextScale, originX, originY, minScale = ZOOM_PAN_MIN_SCALE, maxScale = ZOOM_PAN_MAX_SCALE) {
874
+ const scale = clamp(nextScale, minScale, maxScale);
875
+ if (scale === minScale) return { ...IDENTITY, scale: minScale };
876
876
  const ratio = scale / prev.scale;
877
877
  return {
878
878
  scale,
@@ -887,19 +887,19 @@ function prefersReducedMotion() {
887
887
  if (typeof window === "undefined" || !window.matchMedia) return false;
888
888
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
889
889
  }
890
- function ImageLightbox({
891
- images,
892
- index,
893
- onIndexChange,
894
- onClose,
895
- labels
896
- }) {
897
- const ariaLabel = labels?.ariaLabel ?? "Visor de im\xE1genes";
898
- const closeLabel = labels?.close ?? "Cerrar";
899
- const previousLabel = labels?.previous ?? "Anterior";
900
- const nextLabel = labels?.next ?? "Siguiente";
901
- const hasMultiple = images.length > 1;
902
- const [transform, setTransform] = React7.useState(IDENTITY);
890
+ function useZoomPanGestures(options = {}) {
891
+ const {
892
+ minScale = ZOOM_PAN_MIN_SCALE,
893
+ maxScale = ZOOM_PAN_MAX_SCALE,
894
+ swipeEnabled = true,
895
+ onSwipeCommit,
896
+ wheelZoom = true,
897
+ doubleTap = "reset"
898
+ } = options;
899
+ const [transform, setTransform] = React7.useState({
900
+ ...IDENTITY,
901
+ scale: minScale
902
+ });
903
903
  const transformRef = React7.useRef(transform);
904
904
  transformRef.current = transform;
905
905
  const [isSwipeDragging, setIsSwipeDragging] = React7.useState(false);
@@ -912,46 +912,28 @@ function ImageLightbox({
912
912
  const lastTapRef = React7.useRef(
913
913
  null
914
914
  );
915
- const indexRef = React7.useRef(index);
916
- indexRef.current = index;
917
- const imagesLengthRef = React7.useRef(images.length);
918
- imagesLengthRef.current = images.length;
919
- const resetZoom = React7.useCallback(() => {
920
- setTransform(IDENTITY);
915
+ const onSwipeCommitRef = React7.useRef(onSwipeCommit);
916
+ onSwipeCommitRef.current = onSwipeCommit;
917
+ const swipeEnabledRef = React7.useRef(swipeEnabled);
918
+ swipeEnabledRef.current = swipeEnabled;
919
+ const minScaleRef = React7.useRef(minScale);
920
+ minScaleRef.current = minScale;
921
+ const maxScaleRef = React7.useRef(maxScale);
922
+ maxScaleRef.current = maxScale;
923
+ const doubleTapRef = React7.useRef(doubleTap);
924
+ doubleTapRef.current = doubleTap;
925
+ const reset = React7.useCallback(() => {
926
+ setTransform({ ...IDENTITY, scale: minScaleRef.current });
921
927
  setIsSwipeDragging(false);
922
928
  setSnapBack(false);
923
929
  }, []);
924
- React7.useEffect(() => {
925
- resetZoom();
926
- }, [index, images[index], resetZoom]);
927
- function goPrev() {
928
- onIndexChange((index - 1 + images.length) % images.length);
929
- }
930
- function goNext() {
931
- onIndexChange((index + 1) % images.length);
932
- }
933
- React7.useEffect(() => {
934
- function handleKeyDown(e) {
935
- if (e.key === "Escape") {
936
- onClose();
937
- return;
938
- }
939
- if (!hasMultiple) return;
940
- if (e.key === "ArrowLeft") {
941
- onIndexChange((index - 1 + images.length) % images.length);
942
- } else if (e.key === "ArrowRight") {
943
- onIndexChange((index + 1) % images.length);
944
- }
945
- }
946
- window.addEventListener("keydown", handleKeyDown);
947
- return () => window.removeEventListener("keydown", handleKeyDown);
948
- }, [index, images.length, hasMultiple, onClose, onIndexChange]);
949
- React7.useEffect(() => {
950
- const previousOverflow = document.body.style.overflow;
951
- document.body.style.overflow = "hidden";
952
- return () => {
953
- document.body.style.overflow = previousOverflow;
954
- };
930
+ const setScale = React7.useCallback((next) => {
931
+ setTransform(
932
+ (prev) => zoomToward(prev, next, 0, 0, minScaleRef.current, maxScaleRef.current)
933
+ );
934
+ }, []);
935
+ const clearSnapBack = React7.useCallback(() => {
936
+ setSnapBack(false);
955
937
  }, []);
956
938
  const stageOrigin = React7.useCallback((clientX, clientY) => {
957
939
  const stage = stageRef.current;
@@ -963,6 +945,7 @@ function ImageLightbox({
963
945
  };
964
946
  }, []);
965
947
  React7.useEffect(() => {
948
+ if (!wheelZoom) return;
966
949
  const stage = stageRef.current;
967
950
  if (!stage) return;
968
951
  const handleWheel = (e) => {
@@ -971,11 +954,20 @@ function ImageLightbox({
971
954
  const prev = transformRef.current;
972
955
  const factor = e.deltaY > 0 ? 0.9 : 1.1;
973
956
  const { x, y } = stageOrigin(e.clientX, e.clientY);
974
- setTransform(zoomToward(prev, prev.scale * factor, x, y));
957
+ setTransform(
958
+ zoomToward(
959
+ prev,
960
+ prev.scale * factor,
961
+ x,
962
+ y,
963
+ minScaleRef.current,
964
+ maxScaleRef.current
965
+ )
966
+ );
975
967
  };
976
968
  stage.addEventListener("wheel", handleWheel, { passive: false });
977
969
  return () => stage.removeEventListener("wheel", handleWheel);
978
- }, [stageOrigin]);
970
+ }, [stageOrigin, wheelZoom]);
979
971
  function clearSwipe() {
980
972
  swipeRef.current = null;
981
973
  setIsSwipeDragging(false);
@@ -1010,7 +1002,7 @@ function ImageLightbox({
1010
1002
  beginPinch();
1011
1003
  return;
1012
1004
  }
1013
- if (transformRef.current.scale > MIN_SCALE) {
1005
+ if (transformRef.current.scale > minScaleRef.current) {
1014
1006
  panRef.current = {
1015
1007
  pointerId: e.pointerId,
1016
1008
  startX: e.clientX,
@@ -1021,7 +1013,7 @@ function ImageLightbox({
1021
1013
  };
1022
1014
  return;
1023
1015
  }
1024
- if (hasMultiple) {
1016
+ if (swipeEnabledRef.current) {
1025
1017
  swipeRef.current = {
1026
1018
  pointerId: e.pointerId,
1027
1019
  startX: e.clientX,
@@ -1047,7 +1039,9 @@ function ImageLightbox({
1047
1039
  pinchStart.transform,
1048
1040
  nextScale,
1049
1041
  pinchStart.originX,
1050
- pinchStart.originY
1042
+ pinchStart.originY,
1043
+ minScaleRef.current,
1044
+ maxScaleRef.current
1051
1045
  )
1052
1046
  );
1053
1047
  return;
@@ -1072,16 +1066,22 @@ function ImageLightbox({
1072
1066
  if (swipe.axis === null) {
1073
1067
  const absX = Math.abs(dx);
1074
1068
  const absY = Math.abs(dy);
1075
- if (absX < SWIPE_LOCK_PX && absY < SWIPE_LOCK_PX) return;
1069
+ if (absX < ZOOM_PAN_SWIPE_LOCK_PX && absY < ZOOM_PAN_SWIPE_LOCK_PX) {
1070
+ return;
1071
+ }
1076
1072
  swipe.axis = absX >= absY ? "x" : "y";
1077
1073
  if (swipe.axis === "y") {
1078
1074
  clearSwipe();
1079
- setTransform(IDENTITY);
1075
+ setTransform({ ...IDENTITY, scale: minScaleRef.current });
1080
1076
  return;
1081
1077
  }
1082
1078
  }
1083
1079
  if (swipe.axis === "x") {
1084
- setTransform({ scale: MIN_SCALE, tx: dx, ty: 0 });
1080
+ setTransform({
1081
+ scale: minScaleRef.current,
1082
+ tx: dx,
1083
+ ty: 0
1084
+ });
1085
1085
  }
1086
1086
  }
1087
1087
  function finishSwipe(e) {
@@ -1091,19 +1091,13 @@ function ImageLightbox({
1091
1091
  const wasMoved = swipe.moved;
1092
1092
  const axis = swipe.axis;
1093
1093
  clearSwipe();
1094
- if (axis === "x" && Math.abs(dx) >= SWIPE_COMMIT_PX) {
1095
- const length = imagesLengthRef.current;
1096
- const current = indexRef.current;
1097
- if (dx < 0) {
1098
- onIndexChange((current + 1) % length);
1099
- } else {
1100
- onIndexChange((current - 1 + length) % length);
1101
- }
1094
+ if (axis === "x" && Math.abs(dx) >= ZOOM_PAN_SWIPE_COMMIT_PX) {
1095
+ onSwipeCommitRef.current?.(dx < 0 ? "next" : "prev");
1102
1096
  return true;
1103
1097
  }
1104
1098
  if (wasMoved || transformRef.current.tx !== 0) {
1105
1099
  if (!prefersReducedMotion()) setSnapBack(true);
1106
- setTransform(IDENTITY);
1100
+ setTransform({ ...IDENTITY, scale: minScaleRef.current });
1107
1101
  }
1108
1102
  return wasMoved;
1109
1103
  }
@@ -1118,7 +1112,7 @@ function ImageLightbox({
1118
1112
  }
1119
1113
  if (pointersRef.current.size === 1) {
1120
1114
  const remaining = [...pointersRef.current.entries()][0];
1121
- if (remaining && transformRef.current.scale > MIN_SCALE) {
1115
+ if (remaining && transformRef.current.scale > minScaleRef.current) {
1122
1116
  const [pointerId, point] = remaining;
1123
1117
  panRef.current = {
1124
1118
  pointerId,
@@ -1141,19 +1135,121 @@ function ImageLightbox({
1141
1135
  if (pointersRef.current.size === 0 && e.button === 0) {
1142
1136
  const now = Date.now();
1143
1137
  const last = lastTapRef.current;
1144
- if (last && now - last.time < DOUBLE_TAP_MS && Math.hypot(e.clientX - last.x, e.clientY - last.y) < 24) {
1138
+ if (last && now - last.time < ZOOM_PAN_DOUBLE_TAP_MS && Math.hypot(e.clientX - last.x, e.clientY - last.y) < 24) {
1145
1139
  lastTapRef.current = null;
1146
- resetZoom();
1140
+ if (doubleTapRef.current === "toggle" && transformRef.current.scale <= minScaleRef.current) {
1141
+ const { x, y } = stageOrigin(e.clientX, e.clientY);
1142
+ setTransform(
1143
+ zoomToward(
1144
+ transformRef.current,
1145
+ Math.min(2, maxScaleRef.current),
1146
+ x,
1147
+ y,
1148
+ minScaleRef.current,
1149
+ maxScaleRef.current
1150
+ )
1151
+ );
1152
+ } else {
1153
+ reset();
1154
+ }
1147
1155
  return;
1148
1156
  }
1149
1157
  lastTapRef.current = { time: now, x: e.clientX, y: e.clientY };
1150
1158
  }
1151
1159
  }
1160
+ return {
1161
+ stageRef,
1162
+ transform,
1163
+ isDragging: isSwipeDragging,
1164
+ snapBack,
1165
+ handlers: {
1166
+ onPointerDown,
1167
+ onPointerMove,
1168
+ onPointerUp,
1169
+ onPointerCancel: onPointerUp
1170
+ },
1171
+ reset,
1172
+ setScale,
1173
+ clearSnapBack
1174
+ };
1175
+ }
1176
+ function ImageLightbox({
1177
+ images,
1178
+ index,
1179
+ onIndexChange,
1180
+ onClose,
1181
+ labels
1182
+ }) {
1183
+ const ariaLabel = labels?.ariaLabel ?? "Visor de im\xE1genes";
1184
+ const closeLabel = labels?.close ?? "Cerrar";
1185
+ const previousLabel = labels?.previous ?? "Anterior";
1186
+ const nextLabel = labels?.next ?? "Siguiente";
1187
+ const hasMultiple = images.length > 1;
1188
+ const indexRef = React7.useRef(index);
1189
+ indexRef.current = index;
1190
+ const imagesLengthRef = React7.useRef(images.length);
1191
+ imagesLengthRef.current = images.length;
1192
+ const onIndexChangeRef = React7.useRef(onIndexChange);
1193
+ onIndexChangeRef.current = onIndexChange;
1194
+ const onSwipeCommit = React7.useCallback((direction) => {
1195
+ const length = imagesLengthRef.current;
1196
+ const current = indexRef.current;
1197
+ if (direction === "next") {
1198
+ onIndexChangeRef.current((current + 1) % length);
1199
+ } else {
1200
+ onIndexChangeRef.current((current - 1 + length) % length);
1201
+ }
1202
+ }, []);
1203
+ const {
1204
+ stageRef,
1205
+ transform,
1206
+ isDragging,
1207
+ snapBack,
1208
+ handlers,
1209
+ reset,
1210
+ clearSnapBack
1211
+ } = useZoomPanGestures({
1212
+ swipeEnabled: hasMultiple,
1213
+ onSwipeCommit,
1214
+ doubleTap: "reset"
1215
+ });
1216
+ React7.useEffect(() => {
1217
+ reset();
1218
+ }, [index, images[index], reset]);
1219
+ function goPrev() {
1220
+ onIndexChange((index - 1 + images.length) % images.length);
1221
+ }
1222
+ function goNext() {
1223
+ onIndexChange((index + 1) % images.length);
1224
+ }
1225
+ React7.useEffect(() => {
1226
+ function handleKeyDown(e) {
1227
+ if (e.key === "Escape") {
1228
+ onClose();
1229
+ return;
1230
+ }
1231
+ if (!hasMultiple) return;
1232
+ if (e.key === "ArrowLeft") {
1233
+ onIndexChange((index - 1 + images.length) % images.length);
1234
+ } else if (e.key === "ArrowRight") {
1235
+ onIndexChange((index + 1) % images.length);
1236
+ }
1237
+ }
1238
+ window.addEventListener("keydown", handleKeyDown);
1239
+ return () => window.removeEventListener("keydown", handleKeyDown);
1240
+ }, [index, images.length, hasMultiple, onClose, onIndexChange]);
1241
+ React7.useEffect(() => {
1242
+ const previousOverflow = document.body.style.overflow;
1243
+ document.body.style.overflow = "hidden";
1244
+ return () => {
1245
+ document.body.style.overflow = previousOverflow;
1246
+ };
1247
+ }, []);
1152
1248
  function stopDialogClose(e) {
1153
1249
  e.stopPropagation();
1154
1250
  }
1155
1251
  const { scale, tx, ty } = transform;
1156
- const transition = snapBack && !isSwipeDragging && !prefersReducedMotion() ? `transform ${SWIPE_SNAP_MS}ms ease-out` : void 0;
1252
+ const transition = snapBack && !isDragging && !prefersReducedMotion() ? `transform ${ZOOM_PAN_SWIPE_SNAP_MS}ms ease-out` : void 0;
1157
1253
  return reactDom.createPortal(
1158
1254
  /* @__PURE__ */ jsxRuntime.jsxs(
1159
1255
  "div",
@@ -1193,12 +1289,12 @@ function ImageLightbox({
1193
1289
  ref: stageRef,
1194
1290
  className: "relative flex max-h-full max-w-full touch-none items-center justify-center",
1195
1291
  "data-scale": scale,
1196
- "data-swipe-dragging": isSwipeDragging ? "true" : "false",
1292
+ "data-swipe-dragging": isDragging ? "true" : "false",
1197
1293
  onClick: stopDialogClose,
1198
- onPointerDown,
1199
- onPointerMove,
1200
- onPointerUp,
1201
- onPointerCancel: onPointerUp,
1294
+ onPointerDown: handlers.onPointerDown,
1295
+ onPointerMove: handlers.onPointerMove,
1296
+ onPointerUp: handlers.onPointerUp,
1297
+ onPointerCancel: handlers.onPointerCancel,
1202
1298
  children: /* @__PURE__ */ jsxRuntime.jsx(
1203
1299
  "img",
1204
1300
  {
@@ -1209,9 +1305,9 @@ function ImageLightbox({
1209
1305
  style: {
1210
1306
  transform: `translate(${tx}px, ${ty}px) scale(${scale})`,
1211
1307
  transition,
1212
- cursor: scale > MIN_SCALE ? "grab" : "default"
1308
+ cursor: scale > ZOOM_PAN_MIN_SCALE ? "grab" : "default"
1213
1309
  },
1214
- onTransitionEnd: () => setSnapBack(false)
1310
+ onTransitionEnd: clearSnapBack
1215
1311
  }
1216
1312
  )
1217
1313
  }
@@ -1240,6 +1336,321 @@ function ImageLightbox({
1240
1336
  document.body
1241
1337
  );
1242
1338
  }
1339
+ function MediaCarousel({
1340
+ items,
1341
+ index,
1342
+ onIndexChange,
1343
+ labels,
1344
+ className,
1345
+ renderPdf
1346
+ }) {
1347
+ const previousLabel = labels?.previous ?? "Anterior";
1348
+ const nextLabel = labels?.next ?? "Siguiente";
1349
+ const safeIndex = Math.min(Math.max(index, 0), Math.max(items.length - 1, 0));
1350
+ const item = items[safeIndex];
1351
+ const hasMultiple = items.length > 1;
1352
+ const indexRef = React7.useRef(safeIndex);
1353
+ indexRef.current = safeIndex;
1354
+ const lengthRef = React7.useRef(items.length);
1355
+ lengthRef.current = items.length;
1356
+ const onIndexChangeRef = React7.useRef(onIndexChange);
1357
+ onIndexChangeRef.current = onIndexChange;
1358
+ const onSwipeCommit = React7.useCallback((direction) => {
1359
+ const length = lengthRef.current;
1360
+ if (length <= 1) return;
1361
+ const current = indexRef.current;
1362
+ if (direction === "next") {
1363
+ onIndexChangeRef.current((current + 1) % length);
1364
+ } else {
1365
+ onIndexChangeRef.current((current - 1 + length) % length);
1366
+ }
1367
+ }, []);
1368
+ const isImage = item?.kind === "image";
1369
+ const {
1370
+ stageRef,
1371
+ transform,
1372
+ isDragging,
1373
+ snapBack,
1374
+ handlers,
1375
+ reset,
1376
+ clearSnapBack
1377
+ } = useZoomPanGestures({
1378
+ swipeEnabled: hasMultiple && isImage,
1379
+ onSwipeCommit,
1380
+ doubleTap: "toggle",
1381
+ wheelZoom: isImage
1382
+ });
1383
+ React7.useEffect(() => {
1384
+ reset();
1385
+ }, [safeIndex, item?.kind === "image" ? item.src : null, reset]);
1386
+ React7.useEffect(() => {
1387
+ if (!hasMultiple) return;
1388
+ function handleKeyDown(e) {
1389
+ if (e.key === "ArrowLeft") {
1390
+ onIndexChangeRef.current(
1391
+ (indexRef.current - 1 + lengthRef.current) % lengthRef.current
1392
+ );
1393
+ } else if (e.key === "ArrowRight") {
1394
+ onIndexChangeRef.current((indexRef.current + 1) % lengthRef.current);
1395
+ }
1396
+ }
1397
+ window.addEventListener("keydown", handleKeyDown);
1398
+ return () => window.removeEventListener("keydown", handleKeyDown);
1399
+ }, [hasMultiple]);
1400
+ function stopBubble(e) {
1401
+ e.stopPropagation();
1402
+ }
1403
+ if (!item) {
1404
+ return null;
1405
+ }
1406
+ const { scale, tx, ty } = transform;
1407
+ const transition = snapBack && !isDragging && !prefersReducedMotion() ? `transform ${ZOOM_PAN_SWIPE_SNAP_MS}ms ease-out` : void 0;
1408
+ let body;
1409
+ switch (item.kind) {
1410
+ case "image":
1411
+ body = /* @__PURE__ */ jsxRuntime.jsx(
1412
+ "div",
1413
+ {
1414
+ ref: stageRef,
1415
+ className: "relative flex h-full w-full touch-none items-center justify-center",
1416
+ "data-scale": scale,
1417
+ "data-swipe-dragging": isDragging ? "true" : "false",
1418
+ onClick: stopBubble,
1419
+ onPointerDown: handlers.onPointerDown,
1420
+ onPointerMove: handlers.onPointerMove,
1421
+ onPointerUp: handlers.onPointerUp,
1422
+ onPointerCancel: handlers.onPointerCancel,
1423
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1424
+ "img",
1425
+ {
1426
+ src: item.src,
1427
+ alt: item.alt ?? "",
1428
+ draggable: false,
1429
+ className: "max-h-full max-w-full select-none object-contain",
1430
+ style: {
1431
+ transform: `translate(${tx}px, ${ty}px) scale(${scale})`,
1432
+ transition,
1433
+ cursor: scale > ZOOM_PAN_MIN_SCALE ? "grab" : "default"
1434
+ },
1435
+ onTransitionEnd: clearSnapBack
1436
+ }
1437
+ )
1438
+ }
1439
+ );
1440
+ break;
1441
+ case "video":
1442
+ body = /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center justify-center p-2", children: item.node });
1443
+ break;
1444
+ case "pdf":
1445
+ body = renderPdf ? renderPdf({
1446
+ fileUrl: item.fileUrl,
1447
+ fileName: item.fileName,
1448
+ downloadUrl: item.downloadUrl
1449
+ }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center p-6 text-sm text-muted-foreground", children: item.fileName });
1450
+ break;
1451
+ default: {
1452
+ const _exhaustive = item;
1453
+ return _exhaustive;
1454
+ }
1455
+ }
1456
+ const counterText = labels?.counter ? labels.counter(safeIndex + 1, items.length) : `${safeIndex + 1} / ${items.length}`;
1457
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1458
+ "div",
1459
+ {
1460
+ className: cn(
1461
+ "relative flex h-full min-h-0 w-full flex-col bg-black",
1462
+ item.kind === "pdf" && "bg-muted",
1463
+ className
1464
+ ),
1465
+ children: [
1466
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative min-h-0 flex-1", children: body }),
1467
+ hasMultiple && item.kind !== "pdf" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1468
+ /* @__PURE__ */ jsxRuntime.jsx(
1469
+ "button",
1470
+ {
1471
+ type: "button",
1472
+ onClick: (e) => {
1473
+ e.stopPropagation();
1474
+ onIndexChange((safeIndex - 1 + items.length) % items.length);
1475
+ },
1476
+ "aria-label": previousLabel,
1477
+ className: "absolute left-3 top-1/2 z-10 hidden -translate-y-1/2 rounded-full bg-black/50 p-2 text-white transition-colors hover:bg-black/70 sm:inline-flex",
1478
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "h-6 w-6" })
1479
+ }
1480
+ ),
1481
+ /* @__PURE__ */ jsxRuntime.jsx(
1482
+ "button",
1483
+ {
1484
+ type: "button",
1485
+ onClick: (e) => {
1486
+ e.stopPropagation();
1487
+ onIndexChange((safeIndex + 1) % items.length);
1488
+ },
1489
+ "aria-label": nextLabel,
1490
+ className: "absolute right-3 top-1/2 z-10 hidden -translate-y-1/2 rounded-full bg-black/50 p-2 text-white transition-colors hover:bg-black/70 sm:inline-flex",
1491
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-6 w-6" })
1492
+ }
1493
+ ),
1494
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-3 left-1/2 z-10 -translate-x-1/2 rounded-full bg-black/50 px-3 py-1 text-xs text-white", children: counterText })
1495
+ ] })
1496
+ ]
1497
+ }
1498
+ );
1499
+ }
1500
+ function Dialog({
1501
+ ...props
1502
+ }) {
1503
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
1504
+ }
1505
+ function DialogPortal({
1506
+ ...props
1507
+ }) {
1508
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
1509
+ }
1510
+ function DialogClose({
1511
+ ...props
1512
+ }) {
1513
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "dialog-close", ...props });
1514
+ }
1515
+ function DialogOverlay({
1516
+ className,
1517
+ ...props
1518
+ }) {
1519
+ return /* @__PURE__ */ jsxRuntime.jsx(
1520
+ DialogPrimitive__namespace.Overlay,
1521
+ {
1522
+ "data-slot": "dialog-overlay",
1523
+ className: cn(
1524
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
1525
+ className
1526
+ ),
1527
+ ...props
1528
+ }
1529
+ );
1530
+ }
1531
+ function DialogContent({
1532
+ className,
1533
+ children,
1534
+ showCloseButton = true,
1535
+ ...props
1536
+ }) {
1537
+ return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
1538
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1539
+ /* @__PURE__ */ jsxRuntime.jsxs(
1540
+ DialogPrimitive__namespace.Content,
1541
+ {
1542
+ "data-slot": "dialog-content",
1543
+ className: cn(
1544
+ "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
1545
+ className
1546
+ ),
1547
+ ...props,
1548
+ children: [
1549
+ children,
1550
+ showCloseButton && /* @__PURE__ */ jsxRuntime.jsxs(
1551
+ DialogPrimitive__namespace.Close,
1552
+ {
1553
+ "data-slot": "dialog-close",
1554
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1555
+ children: [
1556
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
1557
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
1558
+ ]
1559
+ }
1560
+ )
1561
+ ]
1562
+ }
1563
+ )
1564
+ ] });
1565
+ }
1566
+ function DialogHeader({ className, ...props }) {
1567
+ return /* @__PURE__ */ jsxRuntime.jsx(
1568
+ "div",
1569
+ {
1570
+ "data-slot": "dialog-header",
1571
+ className: cn("flex flex-col gap-2 text-center sm:text-left", className),
1572
+ ...props
1573
+ }
1574
+ );
1575
+ }
1576
+ function DialogFooter({ className, ...props }) {
1577
+ return /* @__PURE__ */ jsxRuntime.jsx(
1578
+ "div",
1579
+ {
1580
+ "data-slot": "dialog-footer",
1581
+ className: cn(
1582
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
1583
+ className
1584
+ ),
1585
+ ...props
1586
+ }
1587
+ );
1588
+ }
1589
+ function DialogTitle({
1590
+ className,
1591
+ ...props
1592
+ }) {
1593
+ return /* @__PURE__ */ jsxRuntime.jsx(
1594
+ DialogPrimitive__namespace.Title,
1595
+ {
1596
+ "data-slot": "dialog-title",
1597
+ className: cn("text-lg leading-none font-semibold", className),
1598
+ ...props
1599
+ }
1600
+ );
1601
+ }
1602
+ function DialogDescription({
1603
+ className,
1604
+ ...props
1605
+ }) {
1606
+ return /* @__PURE__ */ jsxRuntime.jsx(
1607
+ DialogPrimitive__namespace.Description,
1608
+ {
1609
+ "data-slot": "dialog-description",
1610
+ className: cn("text-muted-foreground text-sm", className),
1611
+ ...props
1612
+ }
1613
+ );
1614
+ }
1615
+ function MediaViewerDialog({
1616
+ open,
1617
+ onOpenChange,
1618
+ children,
1619
+ labels,
1620
+ className,
1621
+ contentClassName,
1622
+ showCloseButton = true
1623
+ }) {
1624
+ const closeLabel = labels?.close ?? "Cerrar";
1625
+ const title = labels?.title ?? "Visor";
1626
+ const description = labels?.description ?? title;
1627
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
1628
+ DialogContent,
1629
+ {
1630
+ showCloseButton: false,
1631
+ className: cn(
1632
+ "inset-0 flex h-dvh max-h-dvh w-screen max-w-none translate-x-0 translate-y-0 top-0 left-0 gap-0 overflow-hidden rounded-none border-0 p-0 shadow-none sm:max-w-none",
1633
+ contentClassName,
1634
+ className
1635
+ ),
1636
+ children: [
1637
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "sr-only", children: title }),
1638
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "sr-only", children: description }),
1639
+ showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(
1640
+ "button",
1641
+ {
1642
+ type: "button",
1643
+ onClick: () => onOpenChange(false),
1644
+ "aria-label": closeLabel,
1645
+ className: "absolute top-3 right-3 z-20 rounded-full bg-black/50 p-2 text-white transition-colors hover:bg-black/70",
1646
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-5 w-5" })
1647
+ }
1648
+ ),
1649
+ children
1650
+ ]
1651
+ }
1652
+ ) });
1653
+ }
1243
1654
  var miniMenuContentClassName = "max-h-none overflow-x-visible overflow-y-visible";
1244
1655
  var miniMenuContentDefaults = {
1245
1656
  sideOffset: 8,
@@ -3145,121 +3556,6 @@ function AvatarEditor({
3145
3556
  }
3146
3557
  );
3147
3558
  }
3148
- function Dialog({
3149
- ...props
3150
- }) {
3151
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Root, { "data-slot": "dialog", ...props });
3152
- }
3153
- function DialogPortal({
3154
- ...props
3155
- }) {
3156
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { "data-slot": "dialog-portal", ...props });
3157
- }
3158
- function DialogClose({
3159
- ...props
3160
- }) {
3161
- return /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Close, { "data-slot": "dialog-close", ...props });
3162
- }
3163
- function DialogOverlay({
3164
- className,
3165
- ...props
3166
- }) {
3167
- return /* @__PURE__ */ jsxRuntime.jsx(
3168
- DialogPrimitive__namespace.Overlay,
3169
- {
3170
- "data-slot": "dialog-overlay",
3171
- className: cn(
3172
- "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
3173
- className
3174
- ),
3175
- ...props
3176
- }
3177
- );
3178
- }
3179
- function DialogContent({
3180
- className,
3181
- children,
3182
- showCloseButton = true,
3183
- ...props
3184
- }) {
3185
- return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
3186
- /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
3187
- /* @__PURE__ */ jsxRuntime.jsxs(
3188
- DialogPrimitive__namespace.Content,
3189
- {
3190
- "data-slot": "dialog-content",
3191
- className: cn(
3192
- "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
3193
- className
3194
- ),
3195
- ...props,
3196
- children: [
3197
- children,
3198
- showCloseButton && /* @__PURE__ */ jsxRuntime.jsxs(
3199
- DialogPrimitive__namespace.Close,
3200
- {
3201
- "data-slot": "dialog-close",
3202
- className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
3203
- children: [
3204
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
3205
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
3206
- ]
3207
- }
3208
- )
3209
- ]
3210
- }
3211
- )
3212
- ] });
3213
- }
3214
- function DialogHeader({ className, ...props }) {
3215
- return /* @__PURE__ */ jsxRuntime.jsx(
3216
- "div",
3217
- {
3218
- "data-slot": "dialog-header",
3219
- className: cn("flex flex-col gap-2 text-center sm:text-left", className),
3220
- ...props
3221
- }
3222
- );
3223
- }
3224
- function DialogFooter({ className, ...props }) {
3225
- return /* @__PURE__ */ jsxRuntime.jsx(
3226
- "div",
3227
- {
3228
- "data-slot": "dialog-footer",
3229
- className: cn(
3230
- "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
3231
- className
3232
- ),
3233
- ...props
3234
- }
3235
- );
3236
- }
3237
- function DialogTitle({
3238
- className,
3239
- ...props
3240
- }) {
3241
- return /* @__PURE__ */ jsxRuntime.jsx(
3242
- DialogPrimitive__namespace.Title,
3243
- {
3244
- "data-slot": "dialog-title",
3245
- className: cn("text-lg leading-none font-semibold", className),
3246
- ...props
3247
- }
3248
- );
3249
- }
3250
- function DialogDescription({
3251
- className,
3252
- ...props
3253
- }) {
3254
- return /* @__PURE__ */ jsxRuntime.jsx(
3255
- DialogPrimitive__namespace.Description,
3256
- {
3257
- "data-slot": "dialog-description",
3258
- className: cn("text-muted-foreground text-sm", className),
3259
- ...props
3260
- }
3261
- );
3262
- }
3263
3559
  function Drawer({
3264
3560
  ...props
3265
3561
  }) {
@@ -5646,6 +5942,340 @@ function useSearchHotkey(options = {}) {
5646
5942
  return { open, setOpen, toggle };
5647
5943
  }
5648
5944
 
5945
+ // src/lib/scroll-restoration/store.ts
5946
+ var MAX_MARKS = 30;
5947
+ var MAX_SNAPSHOT_ROUTES = 3;
5948
+ var PENDING_TRAVERSAL_TTL_MS = 1e3;
5949
+ var scrollMarks = /* @__PURE__ */ new Map();
5950
+ var snapshotsByRoute = /* @__PURE__ */ new Map();
5951
+ var pendingTraversalKey = null;
5952
+ var pendingTraversalTimeout = null;
5953
+ var popstateInstalled = false;
5954
+ function touchMapEntry(map, key, value, max) {
5955
+ if (map.has(key)) map.delete(key);
5956
+ map.set(key, value);
5957
+ while (map.size > max) {
5958
+ const oldest = map.keys().next().value;
5959
+ if (oldest === void 0) break;
5960
+ map.delete(oldest);
5961
+ }
5962
+ }
5963
+ function getScrollMark(routeKey) {
5964
+ const mark = scrollMarks.get(routeKey);
5965
+ if (!mark) return void 0;
5966
+ scrollMarks.delete(routeKey);
5967
+ scrollMarks.set(routeKey, mark);
5968
+ return mark;
5969
+ }
5970
+ function setScrollMark(routeKey, mark) {
5971
+ touchMapEntry(scrollMarks, routeKey, mark, MAX_MARKS);
5972
+ }
5973
+ function deleteScrollMark(routeKey) {
5974
+ scrollMarks.delete(routeKey);
5975
+ }
5976
+ function getSnapshot(routeKey, subKey) {
5977
+ const route = snapshotsByRoute.get(routeKey);
5978
+ if (!route) return void 0;
5979
+ snapshotsByRoute.delete(routeKey);
5980
+ snapshotsByRoute.set(routeKey, route);
5981
+ return route.get(subKey);
5982
+ }
5983
+ function setSnapshot(routeKey, subKey, value) {
5984
+ let route = snapshotsByRoute.get(routeKey);
5985
+ if (route) {
5986
+ snapshotsByRoute.delete(routeKey);
5987
+ } else {
5988
+ route = /* @__PURE__ */ new Map();
5989
+ }
5990
+ route.set(subKey, value);
5991
+ snapshotsByRoute.set(routeKey, route);
5992
+ while (snapshotsByRoute.size > MAX_SNAPSHOT_ROUTES) {
5993
+ const oldest = snapshotsByRoute.keys().next().value;
5994
+ if (oldest === void 0) break;
5995
+ snapshotsByRoute.delete(oldest);
5996
+ }
5997
+ }
5998
+ function deleteSnapshotsForRoute(routeKey) {
5999
+ snapshotsByRoute.delete(routeKey);
6000
+ }
6001
+ function clearRoute(routeKey) {
6002
+ deleteScrollMark(routeKey);
6003
+ deleteSnapshotsForRoute(routeKey);
6004
+ }
6005
+ function clearPendingTraversalTimer() {
6006
+ if (pendingTraversalTimeout !== null) {
6007
+ clearTimeout(pendingTraversalTimeout);
6008
+ pendingTraversalTimeout = null;
6009
+ }
6010
+ }
6011
+ function schedulePendingTraversalClear() {
6012
+ clearPendingTraversalTimer();
6013
+ pendingTraversalTimeout = setTimeout(() => {
6014
+ pendingTraversalKey = null;
6015
+ pendingTraversalTimeout = null;
6016
+ }, PENDING_TRAVERSAL_TTL_MS);
6017
+ }
6018
+ function ensurePopstateListener() {
6019
+ if (popstateInstalled || typeof window === "undefined") return;
6020
+ popstateInstalled = true;
6021
+ window.addEventListener("popstate", () => {
6022
+ pendingTraversalKey = window.location.pathname + window.location.search;
6023
+ schedulePendingTraversalClear();
6024
+ });
6025
+ }
6026
+ function isPendingTraversal(routeKey) {
6027
+ ensurePopstateListener();
6028
+ return pendingTraversalKey === routeKey;
6029
+ }
6030
+ function consumePendingTraversal(routeKey) {
6031
+ ensurePopstateListener();
6032
+ if (pendingTraversalKey !== routeKey) return false;
6033
+ pendingTraversalKey = null;
6034
+ clearPendingTraversalTimer();
6035
+ return true;
6036
+ }
6037
+ function getScrollTop(container) {
6038
+ if (!container) {
6039
+ return window.scrollY || document.documentElement.scrollTop || 0;
6040
+ }
6041
+ return container.scrollTop;
6042
+ }
6043
+ function setScrollTop(container, top) {
6044
+ if (!container) {
6045
+ window.scrollTo(0, top);
6046
+ return;
6047
+ }
6048
+ container.scrollTop = top;
6049
+ }
6050
+ function scrollportTop(container) {
6051
+ return container ? container.getBoundingClientRect().top : 0;
6052
+ }
6053
+ function scrollportBottom(container) {
6054
+ if (!container) return window.innerHeight;
6055
+ return container.getBoundingClientRect().bottom;
6056
+ }
6057
+ function escapeAttrValue(value) {
6058
+ if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
6059
+ return CSS.escape(value);
6060
+ }
6061
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
6062
+ }
6063
+ function resolveAnchor(container, attribute) {
6064
+ const scope = container ?? document;
6065
+ const nodes = scope.querySelectorAll(`[${attribute}]`);
6066
+ if (nodes.length === 0) return null;
6067
+ const portTop = scrollportTop(container);
6068
+ const portBottom = scrollportBottom(container);
6069
+ let bestId = null;
6070
+ let bestTop = 0;
6071
+ let bestScore = Infinity;
6072
+ for (const node of nodes) {
6073
+ if (!(node instanceof HTMLElement)) continue;
6074
+ const id = node.getAttribute(attribute);
6075
+ if (!id) continue;
6076
+ const rect = node.getBoundingClientRect();
6077
+ if (rect.bottom <= portTop || rect.top >= portBottom) continue;
6078
+ const relativeTop = rect.top - portTop;
6079
+ const score = Math.abs(relativeTop);
6080
+ if (score < bestScore) {
6081
+ bestScore = score;
6082
+ bestId = id;
6083
+ bestTop = relativeTop;
6084
+ }
6085
+ }
6086
+ if (!bestId) return null;
6087
+ return { id: bestId, top: bestTop };
6088
+ }
6089
+ function captureMark(container, attribute) {
6090
+ const anchor = resolveAnchor(container, attribute);
6091
+ return {
6092
+ top: getScrollTop(container),
6093
+ anchorId: anchor?.id ?? null,
6094
+ anchorTop: anchor?.top ?? 0
6095
+ };
6096
+ }
6097
+ function applyMark(container, mark, attribute) {
6098
+ if (mark.anchorId) {
6099
+ const scope = container ?? document;
6100
+ const el = scope.querySelector(
6101
+ `[${attribute}="${escapeAttrValue(mark.anchorId)}"]`
6102
+ );
6103
+ if (el instanceof HTMLElement) {
6104
+ const portTop = scrollportTop(container);
6105
+ const currentRelativeTop = el.getBoundingClientRect().top - portTop;
6106
+ const delta = currentRelativeTop - mark.anchorTop;
6107
+ setScrollTop(container, getScrollTop(container) + delta);
6108
+ return true;
6109
+ }
6110
+ }
6111
+ setScrollTop(container, mark.top);
6112
+ return false;
6113
+ }
6114
+ function getScrollHeight(container) {
6115
+ if (!container) {
6116
+ return Math.max(
6117
+ document.documentElement.scrollHeight,
6118
+ document.body?.scrollHeight ?? 0
6119
+ );
6120
+ }
6121
+ return container.scrollHeight;
6122
+ }
6123
+ var DEFAULT_ANCHOR_ATTRIBUTE = "data-scroll-anchor";
6124
+ var STABILIZE_MS = 600;
6125
+ var ScrollRestorationContext = React7.createContext(null);
6126
+ function useScrollRestorationContext() {
6127
+ return React7.useContext(ScrollRestorationContext);
6128
+ }
6129
+ function readContainer(containerRef) {
6130
+ return containerRef?.current ?? null;
6131
+ }
6132
+ function ScrollRestorationProvider({
6133
+ routeKey,
6134
+ containerRef,
6135
+ anchorAttribute = DEFAULT_ANCHOR_ATTRIBUTE,
6136
+ children
6137
+ }) {
6138
+ ensurePopstateListener();
6139
+ const traversalForRouteRef = React7.useRef({ routeKey: "", isTraversal: false });
6140
+ if (traversalForRouteRef.current.routeKey !== routeKey) {
6141
+ traversalForRouteRef.current = {
6142
+ routeKey,
6143
+ isTraversal: isPendingTraversal(routeKey)
6144
+ };
6145
+ }
6146
+ const isTraversal = traversalForRouteRef.current.isTraversal;
6147
+ const value = React7.useMemo(
6148
+ () => ({
6149
+ routeKey,
6150
+ isTraversal,
6151
+ anchorAttribute
6152
+ }),
6153
+ [routeKey, isTraversal, anchorAttribute]
6154
+ );
6155
+ React7.useEffect(() => {
6156
+ if (typeof window === "undefined" || !("scrollRestoration" in history)) {
6157
+ return;
6158
+ }
6159
+ const previous = history.scrollRestoration;
6160
+ history.scrollRestoration = "manual";
6161
+ return () => {
6162
+ history.scrollRestoration = previous;
6163
+ };
6164
+ }, []);
6165
+ const prevRouteKeyRef = React7.useRef(routeKey);
6166
+ const anchorAttributeRef = React7.useRef(anchorAttribute);
6167
+ anchorAttributeRef.current = anchorAttribute;
6168
+ React7.useEffect(() => {
6169
+ const container = readContainer(containerRef);
6170
+ const target = container ?? window;
6171
+ let rafId = 0;
6172
+ const onScroll = () => {
6173
+ if (rafId) return;
6174
+ rafId = requestAnimationFrame(() => {
6175
+ rafId = 0;
6176
+ setScrollMark(
6177
+ routeKey,
6178
+ captureMark(readContainer(containerRef), anchorAttribute)
6179
+ );
6180
+ });
6181
+ };
6182
+ target.addEventListener("scroll", onScroll, { passive: true });
6183
+ return () => {
6184
+ target.removeEventListener("scroll", onScroll);
6185
+ if (rafId) cancelAnimationFrame(rafId);
6186
+ };
6187
+ }, [routeKey, containerRef, anchorAttribute]);
6188
+ React7.useLayoutEffect(() => {
6189
+ const container = readContainer(containerRef);
6190
+ const prevKey = prevRouteKeyRef.current;
6191
+ if (prevKey !== routeKey) {
6192
+ setScrollMark(
6193
+ prevKey,
6194
+ captureMark(container, anchorAttributeRef.current)
6195
+ );
6196
+ prevRouteKeyRef.current = routeKey;
6197
+ }
6198
+ const hasHash = typeof window !== "undefined" && window.location.hash.length > 1;
6199
+ if (isTraversal) {
6200
+ consumePendingTraversal(routeKey);
6201
+ const mark = getScrollMark(routeKey);
6202
+ if (!mark) return void 0;
6203
+ applyMark(container, mark, anchorAttribute);
6204
+ return startStabilizationLoop(container, mark, anchorAttribute);
6205
+ }
6206
+ clearRoute(routeKey);
6207
+ if (!hasHash) {
6208
+ setScrollTop(container, 0);
6209
+ }
6210
+ return void 0;
6211
+ }, [routeKey, isTraversal, containerRef, anchorAttribute]);
6212
+ return /* @__PURE__ */ jsxRuntime.jsx(ScrollRestorationContext.Provider, { value, children });
6213
+ }
6214
+ function startStabilizationLoop(container, mark, attribute) {
6215
+ const startedAt = performance.now();
6216
+ let lastHeight = getScrollHeight(container);
6217
+ let rafId = 0;
6218
+ let aborted = false;
6219
+ const abort = () => {
6220
+ aborted = true;
6221
+ };
6222
+ const onUserIntent = () => {
6223
+ abort();
6224
+ };
6225
+ window.addEventListener("wheel", onUserIntent, {
6226
+ passive: true,
6227
+ once: true
6228
+ });
6229
+ window.addEventListener("touchstart", onUserIntent, {
6230
+ passive: true,
6231
+ once: true
6232
+ });
6233
+ window.addEventListener("keydown", onUserIntent, {
6234
+ passive: true,
6235
+ once: true
6236
+ });
6237
+ window.addEventListener("pointerdown", onUserIntent, {
6238
+ passive: true,
6239
+ once: true
6240
+ });
6241
+ const tick = () => {
6242
+ if (aborted) return;
6243
+ if (performance.now() - startedAt > STABILIZE_MS) return;
6244
+ const height = getScrollHeight(container);
6245
+ if (height !== lastHeight) {
6246
+ lastHeight = height;
6247
+ applyMark(container, mark, attribute);
6248
+ }
6249
+ rafId = requestAnimationFrame(tick);
6250
+ };
6251
+ rafId = requestAnimationFrame(tick);
6252
+ return () => {
6253
+ abort();
6254
+ if (rafId) cancelAnimationFrame(rafId);
6255
+ window.removeEventListener("wheel", onUserIntent);
6256
+ window.removeEventListener("touchstart", onUserIntent);
6257
+ window.removeEventListener("keydown", onUserIntent);
6258
+ window.removeEventListener("pointerdown", onUserIntent);
6259
+ };
6260
+ }
6261
+
6262
+ // src/hooks/useRestorableState.ts
6263
+ function useRestorableState(subKey, initializer) {
6264
+ const ctx = useScrollRestorationContext();
6265
+ const [state, setState] = React7.useState(() => {
6266
+ if (!ctx) return initializer();
6267
+ const traversal = ctx.isTraversal || isPendingTraversal(ctx.routeKey);
6268
+ if (!traversal) return initializer();
6269
+ const snap = getSnapshot(ctx.routeKey, subKey);
6270
+ return snap !== void 0 ? snap : initializer();
6271
+ });
6272
+ React7.useEffect(() => {
6273
+ if (!ctx) return;
6274
+ setSnapshot(ctx.routeKey, subKey, state);
6275
+ }, [ctx, subKey, state]);
6276
+ return [state, setState];
6277
+ }
6278
+
5649
6279
  // src/components/search/fuzzy.ts
5650
6280
  function normalize(value) {
5651
6281
  return value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
@@ -8747,6 +9377,8 @@ exports.MEXICO_STATE_PATHS = MEXICO_STATE_PATHS;
8747
9377
  exports.Marker = Marker;
8748
9378
  exports.MarkerContent = MarkerContent;
8749
9379
  exports.MarkerIcon = MarkerIcon;
9380
+ exports.MediaCarousel = MediaCarousel;
9381
+ exports.MediaViewerDialog = MediaViewerDialog;
8750
9382
  exports.Message = Message;
8751
9383
  exports.MessageAvatar = MessageAvatar;
8752
9384
  exports.MessageComposer = MessageComposer;
@@ -8767,12 +9399,17 @@ exports.PaymentIcon = PaymentIcon;
8767
9399
  exports.PhoneInput = PhoneInput;
8768
9400
  exports.PlatformAccountMenu = PlatformAccountMenu;
8769
9401
  exports.PlatformNavbar = PlatformNavbar;
9402
+ exports.ScrollRestorationProvider = ScrollRestorationProvider;
8770
9403
  exports.SearchCommand = SearchCommand;
8771
9404
  exports.SearchablePicker = SearchablePicker;
8772
9405
  exports.SupportMessengerProvider = SupportMessengerProvider;
8773
9406
  exports.ThemeSwitcher = ThemeSwitcher;
8774
9407
  exports.VerifiedProfessionalBadge = VerifiedProfessionalBadge;
8775
9408
  exports.VideoPlayer = VideoPlayer;
9409
+ exports.ZOOM_PAN_MAX_SCALE = ZOOM_PAN_MAX_SCALE;
9410
+ exports.ZOOM_PAN_MIN_SCALE = ZOOM_PAN_MIN_SCALE;
9411
+ exports.ZOOM_PAN_SWIPE_COMMIT_PX = ZOOM_PAN_SWIPE_COMMIT_PX;
9412
+ exports.ZOOM_PAN_SWIPE_SNAP_MS = ZOOM_PAN_SWIPE_SNAP_MS;
8776
9413
  exports.avatarFallbackStyle = avatarFallbackStyle;
8777
9414
  exports.bubbleVariants = bubbleVariants;
8778
9415
  exports.cn = cn;
@@ -8793,6 +9430,7 @@ exports.normalizeEmojiQuery = normalizeEmojiQuery;
8793
9430
  exports.normalizePaymentCardBrand = normalizePaymentCardBrand;
8794
9431
  exports.paymentIconBrandFromStripe = paymentIconBrandFromStripe;
8795
9432
  exports.paymentTypeFromStripeBrand = paymentTypeFromStripeBrand;
9433
+ exports.prefersReducedMotion = prefersReducedMotion;
8796
9434
  exports.shouldRetryLiveEdge404 = shouldRetryLiveEdge404;
8797
9435
  exports.useDebouncedValue = useDebouncedValue;
8798
9436
  exports.useDebouncedValueStrict = useDebouncedValueStrict;
@@ -8803,10 +9441,14 @@ exports.useLanguageContext = useLanguageContext;
8803
9441
  exports.useMediaQuery = useMediaQuery2;
8804
9442
  exports.usePlaybackStats = usePlaybackStats;
8805
9443
  exports.useRealtimeChannel = useRealtimeChannel;
9444
+ exports.useRestorableState = useRestorableState;
8806
9445
  exports.useScrollFadeXEdges = useScrollFadeXEdges;
9446
+ exports.useScrollRestorationContext = useScrollRestorationContext;
8807
9447
  exports.useSearchHotkey = useSearchHotkey;
8808
9448
  exports.useSupportConversation = useSupportConversation;
8809
9449
  exports.useSupportMessenger = useSupportMessenger;
8810
9450
  exports.useSupportMessengerOptional = useSupportMessengerOptional;
9451
+ exports.useZoomPanGestures = useZoomPanGestures;
9452
+ exports.zoomToward = zoomToward;
8811
9453
  //# sourceMappingURL=index.cjs.map
8812
9454
  //# sourceMappingURL=index.cjs.map