@stream-mdx/react 0.5.0 → 1.0.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.
Files changed (99) hide show
  1. package/CHANGELOG.md +371 -0
  2. package/README.md +79 -4
  3. package/dist/blocks-renderer-DAOBFBfi.d.ts +29 -0
  4. package/dist/blocks-renderer-DQEL1kJW.d.cts +29 -0
  5. package/dist/components/bottom-stick-scroll-area.cjs +117 -193
  6. package/dist/components/bottom-stick-scroll-area.mjs +112 -183
  7. package/dist/components/diff-renderer.cjs +86 -0
  8. package/dist/components/diff-renderer.d.cts +11 -0
  9. package/dist/components/diff-renderer.d.ts +11 -0
  10. package/dist/components/diff-renderer.mjs +66 -0
  11. package/dist/components/index.cjs +2761 -1508
  12. package/dist/components/index.d.cts +7 -2
  13. package/dist/components/index.d.ts +7 -2
  14. package/dist/components/index.mjs +2730 -1493
  15. package/dist/components/katex-math.cjs +220 -0
  16. package/dist/components/katex-math.d.cts +10 -0
  17. package/dist/components/katex-math.d.ts +10 -0
  18. package/dist/components/katex-math.mjs +188 -0
  19. package/dist/contexts/math-tracker.cjs +240 -521
  20. package/dist/contexts/math-tracker.mjs +235 -513
  21. package/dist/index-Cmne1yUK.d.cts +723 -0
  22. package/dist/index-D7dyyu3q.d.ts +723 -0
  23. package/dist/index.cjs +13029 -6475
  24. package/dist/index.d.cts +69 -39
  25. package/dist/index.d.ts +69 -39
  26. package/dist/index.mjs +13007 -6442
  27. package/dist/math/display-wrapper.cjs +7 -15
  28. package/dist/math/display-wrapper.d.cts +2 -2
  29. package/dist/math/display-wrapper.d.ts +2 -2
  30. package/dist/math/display-wrapper.mjs +2 -6
  31. package/dist/node-views-Bpc6Gkgl.d.cts +13 -0
  32. package/dist/node-views-DpnYdaAS.d.ts +13 -0
  33. package/dist/renderer/hooks.cjs +35 -20
  34. package/dist/renderer/hooks.d.cts +22 -1
  35. package/dist/renderer/hooks.d.ts +22 -1
  36. package/dist/renderer/hooks.mjs +27 -12
  37. package/dist/renderer/patch-batching.cjs +5 -8
  38. package/dist/renderer/patch-coalescing.cjs +5 -8
  39. package/dist/renderer/patch-commit-scheduler.cjs +138 -356
  40. package/dist/renderer/patch-commit-scheduler.d.cts +13 -1
  41. package/dist/renderer/patch-commit-scheduler.d.ts +13 -1
  42. package/dist/renderer/patch-commit-scheduler.mjs +133 -348
  43. package/dist/renderer/store.cjs +3775 -1373
  44. package/dist/renderer/store.d.cts +108 -3
  45. package/dist/renderer/store.d.ts +108 -3
  46. package/dist/renderer/store.mjs +3778 -1362
  47. package/dist/renderer/virtualized-code.cjs +415 -71
  48. package/dist/renderer/virtualized-code.d.cts +24 -23
  49. package/dist/renderer/virtualized-code.d.ts +24 -23
  50. package/dist/renderer/virtualized-code.mjs +409 -62
  51. package/dist/renderer.cjs +10655 -4334
  52. package/dist/renderer.d.cts +98 -29
  53. package/dist/renderer.d.ts +98 -29
  54. package/dist/renderer.mjs +10582 -4212
  55. package/dist/server-regions-CPLHGli0.d.cts +32 -0
  56. package/dist/server-regions-mUhyoKi7.d.ts +32 -0
  57. package/dist/server.cjs +10195 -3872
  58. package/dist/server.d.cts +17 -252
  59. package/dist/server.d.ts +17 -252
  60. package/dist/server.mjs +9997 -3649
  61. package/dist/{streaming-markdown-CEI9eDZm.d.ts → streaming-markdown-yELbJxyH.d.ts} +49 -55
  62. package/dist/{streaming-markdown-DRisClXb.d.cts → streaming-markdown-zVwFuaJG.d.cts} +49 -55
  63. package/dist/streaming-markdown.cjs +11660 -5378
  64. package/dist/streaming-markdown.d.cts +7 -2
  65. package/dist/streaming-markdown.d.ts +7 -2
  66. package/dist/streaming-markdown.mjs +11679 -5347
  67. package/dist/trusted-mdx/index.cjs +833 -0
  68. package/dist/trusted-mdx/index.d.cts +11 -0
  69. package/dist/trusted-mdx/index.d.ts +11 -0
  70. package/dist/trusted-mdx/index.mjs +807 -0
  71. package/dist/trusted-mdx/native-children-slot.cjs +45 -0
  72. package/dist/trusted-mdx/native-children-slot.d.cts +11 -0
  73. package/dist/trusted-mdx/native-children-slot.d.ts +11 -0
  74. package/dist/trusted-mdx/native-children-slot.mjs +24 -0
  75. package/dist/trusted-mdx/server.cjs +752 -0
  76. package/dist/trusted-mdx/server.d.cts +24 -0
  77. package/dist/trusted-mdx/server.d.ts +24 -0
  78. package/dist/trusted-mdx/server.mjs +724 -0
  79. package/dist/trusted-mdx-contract-ElKpkDI5.d.cts +113 -0
  80. package/dist/trusted-mdx-contract-ElKpkDI5.d.ts +113 -0
  81. package/dist/utils/inline-html.cjs +246 -147
  82. package/dist/utils/inline-html.d.cts +37 -6
  83. package/dist/utils/inline-html.d.ts +37 -6
  84. package/dist/utils/inline-html.mjs +237 -134
  85. package/package.json +41 -18
  86. package/dist/index-BVhp_pcF.d.ts +0 -251
  87. package/dist/index-EaeouYp2.d.cts +0 -251
  88. package/dist/mdx-client.cjs +0 -408
  89. package/dist/mdx-client.d.cts +0 -113
  90. package/dist/mdx-client.d.ts +0 -113
  91. package/dist/mdx-client.mjs +0 -369
  92. package/dist/mdx-coordinator.cjs +0 -584
  93. package/dist/mdx-coordinator.d.cts +0 -21
  94. package/dist/mdx-coordinator.d.ts +0 -21
  95. package/dist/mdx-coordinator.mjs +0 -550
  96. package/dist/renderer/node-views.cjs +0 -1887
  97. package/dist/renderer/node-views.d.cts +0 -14
  98. package/dist/renderer/node-views.d.ts +0 -14
  99. package/dist/renderer/node-views.mjs +0 -1861
@@ -7,17 +7,14 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
8
  var __export = (target, all) => {
9
9
  for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
10
+ __defProp(target, name, { get: all[name], enumerable: !0 });
11
+ }, __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from == "object" || typeof from == "function")
14
13
  for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
14
+ !__hasOwnProp.call(to, key) && key !== except && __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
15
  return to;
19
16
  };
20
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: !0 }), mod);
21
18
 
22
19
  // src/components/bottom-stick-scroll-area.tsx
23
20
  var bottom_stick_scroll_area_exports = {};
@@ -25,19 +22,9 @@ __export(bottom_stick_scroll_area_exports, {
25
22
  BottomStickScrollArea: () => BottomStickScrollArea
26
23
  });
27
24
  module.exports = __toCommonJS(bottom_stick_scroll_area_exports);
28
- var import_react = require("react");
29
- var import_jsx_runtime = require("react/jsx-runtime");
30
- var EPS_BOTTOM_PX = 2;
31
- var EPS_OVERFLOW_PX = 1;
32
- var DETACH_SCROLL_DELTA_PX = 1;
33
- var RETURN_MIN_MS = 180;
34
- var RETURN_MAX_MS = 520;
35
- var RETURN_PX_PER_MS = 2.2;
36
- var RETURN_SETTLE_FRAMES = 2;
25
+ var import_react = require("react"), import_jsx_runtime = require("react/jsx-runtime"), EPS_BOTTOM_PX = 2, EPS_OVERFLOW_PX = 1, DETACH_SCROLL_DELTA_PX = 1, RETURN_MIN_MS = 180, RETURN_MAX_MS = 520, RETURN_PX_PER_MS = 2.2, RETURN_SETTLE_FRAMES = 2;
37
26
  function clamp01(value) {
38
- if (value < 0) return 0;
39
- if (value > 1) return 1;
40
- return value;
27
+ return value < 0 ? 0 : value > 1 ? 1 : value;
41
28
  }
42
29
  function easeOutCubic(value) {
43
30
  return 1 - (1 - value) ** 3;
@@ -46,14 +33,34 @@ function joinClasses(...parts) {
46
33
  return parts.filter(Boolean).join(" ");
47
34
  }
48
35
  function measure(viewport) {
49
- const scrollTop = viewport.scrollTop;
50
- const scrollHeight = viewport.scrollHeight;
51
- const clientHeight = viewport.clientHeight;
52
- const maxScrollTop = Math.max(0, scrollHeight - clientHeight);
53
- const distanceToBottom = Math.max(0, maxScrollTop - scrollTop);
54
- const isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
36
+ let scrollTop = viewport.scrollTop, scrollHeight = viewport.scrollHeight, clientHeight = viewport.clientHeight, maxScrollTop = Math.max(0, scrollHeight - clientHeight), distanceToBottom = Math.max(0, maxScrollTop - scrollTop), isOverflowing = scrollHeight > clientHeight + EPS_OVERFLOW_PX;
55
37
  return { scrollTop, scrollHeight, clientHeight, maxScrollTop, distanceToBottom, isOverflowing };
56
38
  }
39
+ function isEditableTarget(target) {
40
+ if (!(target instanceof Element)) return !1;
41
+ if (target.closest("input, textarea, select, [role='textbox']")) return !0;
42
+ let contentEditable = target.closest("[contenteditable]");
43
+ return contentEditable !== null && contentEditable.getAttribute("contenteditable")?.toLowerCase() !== "false";
44
+ }
45
+ function isScrollKeyIntent(event) {
46
+ if (event.defaultPrevented || isEditableTarget(event.target)) return !1;
47
+ switch (event.key) {
48
+ case "ArrowDown":
49
+ case "ArrowUp":
50
+ case "PageDown":
51
+ case "PageUp":
52
+ case "Home":
53
+ case "End":
54
+ return !0;
55
+ case " ":
56
+ case "Spacebar":
57
+ return event.target instanceof Element ? event.target.closest(
58
+ "button, input, summary, [role='button'], [role='checkbox'], [role='switch'], [role='radio'], [role='menuitem'], [role='menuitemcheckbox'], [role='menuitemradio']"
59
+ ) === null : !0;
60
+ default:
61
+ return !1;
62
+ }
63
+ }
57
64
  function DefaultJumpButton({ canJump, jumpToBottom }) {
58
65
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
59
66
  "button",
@@ -74,7 +81,7 @@ function DefaultJumpButton({ canJump, jumpToBottom }) {
74
81
  color: "var(--foreground, #111)",
75
82
  cursor: canJump ? "pointer" : "default"
76
83
  },
77
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": true, children: "\u2193" })
84
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": !0, children: "\u2193" })
78
85
  }
79
86
  );
80
87
  }
@@ -83,45 +90,23 @@ function BottomStickScrollArea({
83
90
  className,
84
91
  viewportClassName,
85
92
  contentClassName,
86
- showJumpToBottom = true,
93
+ showJumpToBottom = !0,
87
94
  onDebugStateChange,
88
95
  onModeChange,
89
- debugDomAttributes = false,
96
+ debugDomAttributes = !1,
90
97
  renderJumpToBottom,
91
98
  jumpContainerClassName
92
99
  }) {
93
- const viewportRef = (0, import_react.useRef)(null);
94
- const contentRef = (0, import_react.useRef)(null);
95
- const modeRef = (0, import_react.useRef)("STICKY_INSTANT");
96
- const [mode, setMode] = (0, import_react.useState)("STICKY_INSTANT");
97
- const [isOverflowing, setIsOverflowing] = (0, import_react.useState)(false);
98
- const [distanceToBottom, setDistanceToBottom] = (0, import_react.useState)(0);
99
- const prevScrollTopRef = (0, import_react.useRef)(0);
100
- const lastProgrammaticWriteRef = (0, import_react.useRef)(null);
101
- const programmaticWriteCountRef = (0, import_react.useRef)(0);
102
- const pendingStickRafRef = (0, import_react.useRef)(null);
103
- const stickRequestedRef = (0, import_react.useRef)(false);
104
- const returnRafRef = (0, import_react.useRef)(null);
105
- const returnAnimRef = (0, import_react.useRef)(null);
106
- const setModeBoth = (0, import_react.useCallback)(
100
+ let viewportRef = (0, import_react.useRef)(null), contentRef = (0, import_react.useRef)(null), modeRef = (0, import_react.useRef)("STICKY_INSTANT"), [mode, setMode] = (0, import_react.useState)("STICKY_INSTANT"), [isOverflowing, setIsOverflowing] = (0, import_react.useState)(!1), [distanceToBottom, setDistanceToBottom] = (0, import_react.useState)(0), [prefersReducedMotion, setPrefersReducedMotion] = (0, import_react.useState)(!1), prefersReducedMotionRef = (0, import_react.useRef)(!1), prevScrollTopRef = (0, import_react.useRef)(0), lastProgrammaticWriteRef = (0, import_react.useRef)(null), programmaticWriteCountRef = (0, import_react.useRef)(0), pendingStickRafRef = (0, import_react.useRef)(null), stickRequestedRef = (0, import_react.useRef)(!1), returnRafRef = (0, import_react.useRef)(null), returnAnimRef = (0, import_react.useRef)(null), setModeBoth = (0, import_react.useCallback)(
107
101
  (next) => {
108
- modeRef.current = next;
109
- setMode(next);
110
- onModeChange?.(next);
102
+ modeRef.current = next, setMode(next), onModeChange?.(next);
111
103
  },
112
104
  [onModeChange]
113
- );
114
- const updateDebug = (0, import_react.useCallback)(() => {
115
- const viewport = viewportRef.current;
105
+ ), updateDebug = (0, import_react.useCallback)(() => {
106
+ let viewport = viewportRef.current;
116
107
  if (!viewport) return;
117
- const m = measure(viewport);
118
- if (debugDomAttributes) {
119
- viewport.dataset.stickyMode = modeRef.current;
120
- viewport.dataset.distanceToBottom = String(m.distanceToBottom);
121
- viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0";
122
- viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current);
123
- }
124
- onDebugStateChange?.({
108
+ let m = measure(viewport);
109
+ debugDomAttributes && (viewport.dataset.stickyMode = modeRef.current, viewport.dataset.distanceToBottom = String(m.distanceToBottom), viewport.dataset.isOverflowing = m.isOverflowing ? "1" : "0", viewport.dataset.programmaticWrites = String(programmaticWriteCountRef.current)), onDebugStateChange?.({
125
110
  mode: modeRef.current,
126
111
  isOverflowing: m.isOverflowing,
127
112
  distanceToBottom: m.distanceToBottom,
@@ -130,60 +115,54 @@ function BottomStickScrollArea({
130
115
  scrollHeight: m.scrollHeight,
131
116
  clientHeight: m.clientHeight,
132
117
  programmaticWrites: programmaticWriteCountRef.current
133
- });
134
- setDistanceToBottom(
118
+ }), setDistanceToBottom(
135
119
  (previous) => Math.abs(previous - m.distanceToBottom) <= 0.1 ? previous : m.distanceToBottom
136
120
  );
137
- }, [debugDomAttributes, onDebugStateChange]);
138
- const writeScrollTop = (0, import_react.useCallback)((nextTop) => {
139
- const viewport = viewportRef.current;
121
+ }, [debugDomAttributes, onDebugStateChange]), writeScrollTop = (0, import_react.useCallback)((nextTop) => {
122
+ let viewport = viewportRef.current;
123
+ viewport && (viewport.scrollTop = nextTop, programmaticWriteCountRef.current += 1, lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop });
124
+ }, []), cancelPendingStick = (0, import_react.useCallback)(() => {
125
+ pendingStickRafRef.current !== null && (cancelAnimationFrame(pendingStickRafRef.current), pendingStickRafRef.current = null), stickRequestedRef.current = !1;
126
+ }, []), cancelReturn = (0, import_react.useCallback)(() => {
127
+ returnRafRef.current !== null && (cancelAnimationFrame(returnRafRef.current), returnRafRef.current = null), returnAnimRef.current = null;
128
+ }, []), handleReducedMotionChange = (0, import_react.useCallback)(
129
+ (matches) => {
130
+ if (prefersReducedMotionRef.current !== matches && (prefersReducedMotionRef.current = matches, setPrefersReducedMotion(matches)), !matches || modeRef.current !== "RETURNING_SMOOTH") return;
131
+ cancelPendingStick(), cancelReturn(), setModeBoth("STICKY_INSTANT");
132
+ let viewport = viewportRef.current;
133
+ viewport && (writeScrollTop(measure(viewport).maxScrollTop), prevScrollTopRef.current = viewport.scrollTop), updateDebug();
134
+ },
135
+ [cancelPendingStick, cancelReturn, setModeBoth, updateDebug, writeScrollTop]
136
+ ), reducedMotionChangeHandlerRef = (0, import_react.useRef)(handleReducedMotionChange);
137
+ reducedMotionChangeHandlerRef.current = handleReducedMotionChange;
138
+ let interruptReturnForUserIntent = (0, import_react.useCallback)(() => {
139
+ modeRef.current === "RETURNING_SMOOTH" && (cancelPendingStick(), cancelReturn(), setModeBoth("DETACHED"), updateDebug());
140
+ }, [cancelPendingStick, cancelReturn, setModeBoth, updateDebug]), onViewportKeyDown = (0, import_react.useCallback)(
141
+ (event) => {
142
+ isScrollKeyIntent(event) && interruptReturnForUserIntent();
143
+ },
144
+ [interruptReturnForUserIntent]
145
+ ), stickToBottomInstant = (0, import_react.useCallback)(() => {
146
+ let viewport = viewportRef.current;
147
+ viewport && (stickRequestedRef.current = !0, pendingStickRafRef.current === null && (pendingStickRafRef.current = requestAnimationFrame(() => {
148
+ if (pendingStickRafRef.current = null, !stickRequestedRef.current || (stickRequestedRef.current = !1, modeRef.current !== "STICKY_INSTANT")) return;
149
+ let m = measure(viewport);
150
+ writeScrollTop(m.maxScrollTop), updateDebug();
151
+ })));
152
+ }, [updateDebug, writeScrollTop]), startReturnToBottomSmooth = (0, import_react.useCallback)(() => {
153
+ let viewport = viewportRef.current;
140
154
  if (!viewport) return;
141
- viewport.scrollTop = nextTop;
142
- programmaticWriteCountRef.current += 1;
143
- lastProgrammaticWriteRef.current = { at: performance.now(), top: nextTop };
144
- }, []);
145
- const cancelPendingStick = (0, import_react.useCallback)(() => {
146
- if (pendingStickRafRef.current !== null) {
147
- cancelAnimationFrame(pendingStickRafRef.current);
148
- pendingStickRafRef.current = null;
149
- }
150
- stickRequestedRef.current = false;
151
- }, []);
152
- const cancelReturn = (0, import_react.useCallback)(() => {
153
- if (returnRafRef.current !== null) {
154
- cancelAnimationFrame(returnRafRef.current);
155
- returnRafRef.current = null;
155
+ if (prefersReducedMotionRef.current) {
156
+ cancelPendingStick(), cancelReturn(), setModeBoth("STICKY_INSTANT"), writeScrollTop(measure(viewport).maxScrollTop), prevScrollTopRef.current = viewport.scrollTop, updateDebug();
157
+ return;
156
158
  }
157
- returnAnimRef.current = null;
158
- }, []);
159
- const stickToBottomInstant = (0, import_react.useCallback)(() => {
160
- const viewport = viewportRef.current;
161
- if (!viewport) return;
162
- stickRequestedRef.current = true;
163
- if (pendingStickRafRef.current !== null) return;
164
- pendingStickRafRef.current = requestAnimationFrame(() => {
165
- pendingStickRafRef.current = null;
166
- if (!stickRequestedRef.current) return;
167
- stickRequestedRef.current = false;
168
- if (modeRef.current !== "STICKY_INSTANT") return;
169
- const m = measure(viewport);
170
- writeScrollTop(m.maxScrollTop);
171
- updateDebug();
172
- });
173
- }, [updateDebug, writeScrollTop]);
174
- const startReturnToBottomSmooth = (0, import_react.useCallback)(() => {
175
- const viewport = viewportRef.current;
176
- if (!viewport) return;
177
- cancelPendingStick();
178
- cancelReturn();
179
- const initial = measure(viewport);
159
+ cancelPendingStick(), cancelReturn();
160
+ let initial = measure(viewport);
180
161
  if (initial.distanceToBottom <= EPS_BOTTOM_PX) {
181
- setModeBoth("STICKY_INSTANT");
182
- stickToBottomInstant();
183
- updateDebug();
162
+ setModeBoth("STICKY_INSTANT"), stickToBottomInstant(), updateDebug();
184
163
  return;
185
164
  }
186
- const durationMs = Math.max(
165
+ let durationMs = Math.max(
187
166
  RETURN_MIN_MS,
188
167
  Math.min(RETURN_MAX_MS, initial.distanceToBottom / RETURN_PX_PER_MS)
189
168
  );
@@ -192,118 +171,60 @@ function BottomStickScrollArea({
192
171
  startTop: initial.scrollTop,
193
172
  durationMs,
194
173
  settleFrames: 0
195
- };
196
- setModeBoth("RETURNING_SMOOTH");
197
- const tick = (now) => {
198
- const viewportCurrent = viewportRef.current;
199
- const anim = returnAnimRef.current;
174
+ }, setModeBoth("RETURNING_SMOOTH");
175
+ let tick = (now) => {
176
+ let viewportCurrent = viewportRef.current, anim = returnAnimRef.current;
200
177
  if (!viewportCurrent || !anim || modeRef.current !== "RETURNING_SMOOTH") {
201
178
  cancelReturn();
202
179
  return;
203
180
  }
204
- const before = measure(viewportCurrent);
205
- const progress = clamp01((now - anim.startTime) / anim.durationMs);
206
- const eased = easeOutCubic(progress);
207
- const targetBottom = before.maxScrollTop;
208
- let nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
209
- if (nextTop < before.scrollTop) {
210
- nextTop = before.scrollTop;
211
- }
212
- writeScrollTop(nextTop);
213
- const after = measure(viewportCurrent);
214
- if (after.distanceToBottom <= EPS_BOTTOM_PX) {
215
- anim.settleFrames += 1;
216
- } else {
217
- anim.settleFrames = 0;
218
- }
219
- const doneByTime = progress >= 1;
220
- const doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
181
+ let before = measure(viewportCurrent), progress = clamp01((now - anim.startTime) / anim.durationMs), eased = easeOutCubic(progress), targetBottom = before.maxScrollTop, nextTop = anim.startTop + (targetBottom - anim.startTop) * eased;
182
+ nextTop < before.scrollTop && (nextTop = before.scrollTop), writeScrollTop(nextTop), measure(viewportCurrent).distanceToBottom <= EPS_BOTTOM_PX ? anim.settleFrames += 1 : anim.settleFrames = 0;
183
+ let doneByTime = progress >= 1, doneBySettle = anim.settleFrames >= RETURN_SETTLE_FRAMES && progress >= 0.6;
221
184
  if (doneByTime && doneBySettle) {
222
- cancelReturn();
223
- setModeBoth("STICKY_INSTANT");
224
- stickToBottomInstant();
225
- updateDebug();
185
+ cancelReturn(), setModeBoth("STICKY_INSTANT"), stickToBottomInstant(), updateDebug();
226
186
  return;
227
187
  }
228
- updateDebug();
229
- returnRafRef.current = requestAnimationFrame(tick);
188
+ updateDebug(), returnRafRef.current = requestAnimationFrame(tick);
230
189
  };
231
190
  returnRafRef.current = requestAnimationFrame(tick);
232
- }, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]);
233
- const onViewportScroll = (0, import_react.useCallback)(
191
+ }, [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug, writeScrollTop]), onViewportScroll = (0, import_react.useCallback)(
234
192
  (event) => {
235
- const viewport = event.currentTarget;
236
- const m = measure(viewport);
193
+ let viewport = event.currentTarget, m = measure(viewport);
237
194
  setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
238
- const previousTop = prevScrollTopRef.current;
239
- const delta = m.scrollTop - previousTop;
240
- const lastWrite = lastProgrammaticWriteRef.current;
241
- const wroteRecently = lastWrite !== null && performance.now() - lastWrite.at < 60;
242
- const isLikelyOwnWrite = wroteRecently && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
243
- if (modeRef.current === "RETURNING_SMOOTH") {
244
- if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX) {
245
- cancelReturn();
246
- setModeBoth("DETACHED");
247
- }
248
- } else if (modeRef.current === "STICKY_INSTANT") {
249
- if (!isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing) {
250
- cancelPendingStick();
251
- setModeBoth("DETACHED");
252
- }
253
- } else if (modeRef.current === "DETACHED") {
254
- if (m.distanceToBottom <= EPS_BOTTOM_PX) {
255
- setModeBoth("STICKY_INSTANT");
256
- stickToBottomInstant();
257
- }
258
- }
259
- prevScrollTopRef.current = m.scrollTop;
260
- updateDebug();
195
+ let previousTop = prevScrollTopRef.current, delta = m.scrollTop - previousTop, lastWrite = lastProgrammaticWriteRef.current, isLikelyOwnWrite = lastWrite !== null && performance.now() - lastWrite.at < 60 && lastWrite !== null && Math.abs(m.scrollTop - lastWrite.top) <= 2;
196
+ modeRef.current === "RETURNING_SMOOTH" ? !isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && (cancelReturn(), setModeBoth("DETACHED")) : modeRef.current === "STICKY_INSTANT" ? !isLikelyOwnWrite && delta < -DETACH_SCROLL_DELTA_PX && m.isOverflowing && (cancelPendingStick(), setModeBoth("DETACHED")) : modeRef.current === "DETACHED" && m.distanceToBottom <= EPS_BOTTOM_PX && (setModeBoth("STICKY_INSTANT"), stickToBottomInstant()), prevScrollTopRef.current = m.scrollTop, updateDebug();
261
197
  },
262
198
  [cancelPendingStick, cancelReturn, setModeBoth, stickToBottomInstant, updateDebug]
263
199
  );
264
200
  (0, import_react.useEffect)(() => {
265
- const viewport = viewportRef.current;
266
- const content = contentRef.current;
201
+ let viewport = viewportRef.current, content = contentRef.current;
267
202
  if (!viewport || !content) return;
268
- const observer = new ResizeObserver(() => {
269
- const m = measure(viewport);
270
- setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
271
- if (modeRef.current === "STICKY_INSTANT") {
272
- stickToBottomInstant();
273
- }
274
- updateDebug();
203
+ let observer = new ResizeObserver(() => {
204
+ let m = measure(viewport);
205
+ setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing), modeRef.current === "STICKY_INSTANT" && stickToBottomInstant(), updateDebug();
275
206
  });
276
- observer.observe(content);
277
- observer.observe(viewport);
278
- return () => observer.disconnect();
279
- }, [stickToBottomInstant, updateDebug]);
280
- (0, import_react.useLayoutEffect)(() => {
281
- const viewport = viewportRef.current;
207
+ return observer.observe(content), observer.observe(viewport), () => observer.disconnect();
208
+ }, [stickToBottomInstant, updateDebug]), (0, import_react.useLayoutEffect)(() => {
209
+ let viewport = viewportRef.current;
282
210
  if (!viewport) return;
283
211
  setModeBoth("STICKY_INSTANT");
284
- const initial = measure(viewport);
285
- writeScrollTop(initial.maxScrollTop);
286
- prevScrollTopRef.current = viewport.scrollTop;
287
- setIsOverflowing(initial.isOverflowing);
288
- setDistanceToBottom(initial.distanceToBottom);
289
- updateDebug();
290
- }, [setModeBoth, updateDebug, writeScrollTop]);
291
- (0, import_react.useEffect)(() => {
292
- return () => {
293
- cancelPendingStick();
294
- cancelReturn();
295
- };
212
+ let initial = measure(viewport);
213
+ writeScrollTop(initial.maxScrollTop), prevScrollTopRef.current = viewport.scrollTop, setIsOverflowing(initial.isOverflowing), setDistanceToBottom(initial.distanceToBottom), updateDebug();
214
+ }, [setModeBoth, updateDebug, writeScrollTop]), (0, import_react.useLayoutEffect)(() => {
215
+ if (typeof window > "u" || typeof window.matchMedia != "function") return;
216
+ let mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)"), onChange = () => reducedMotionChangeHandlerRef.current(mediaQuery.matches);
217
+ return onChange(), typeof mediaQuery.addEventListener == "function" ? (mediaQuery.addEventListener("change", onChange), () => mediaQuery.removeEventListener("change", onChange)) : (mediaQuery.addListener(onChange), () => mediaQuery.removeListener(onChange));
218
+ }, []), (0, import_react.useEffect)(() => () => {
219
+ cancelPendingStick(), cancelReturn();
296
220
  }, [cancelPendingStick, cancelReturn]);
297
- const canJump = isOverflowing && mode === "DETACHED";
298
- const jumpButton = renderJumpToBottom?.({
221
+ let canJump = isOverflowing && mode === "DETACHED", jumpButton = renderJumpToBottom?.({
299
222
  mode,
300
223
  canJump,
301
224
  isOverflowing,
302
225
  distanceToBottom,
303
226
  jumpToBottom: startReturnToBottomSmooth
304
- }) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultJumpButton, { canJump, jumpToBottom: startReturnToBottomSmooth });
305
- const jumpContainerClassNameBase = "pointer-events-none absolute z-20";
306
- const jumpContainerStyle = {
227
+ }) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DefaultJumpButton, { canJump, jumpToBottom: startReturnToBottomSmooth }), jumpContainerClassNameBase = "pointer-events-none absolute z-20", jumpContainerStyle = {
307
228
  position: "absolute",
308
229
  zIndex: 20,
309
230
  left: 0,
@@ -312,8 +233,8 @@ function BottomStickScrollArea({
312
233
  display: "flex",
313
234
  justifyContent: "center",
314
235
  opacity: canJump ? 1 : 0,
315
- transform: canJump ? "translateY(0px)" : "translateY(4px)",
316
- transition: "opacity 150ms ease, transform 150ms ease",
236
+ transform: prefersReducedMotion ? "none" : canJump ? "translateY(0px)" : "translateY(4px)",
237
+ transition: prefersReducedMotion ? "none" : "opacity 150ms ease, transform 150ms ease",
317
238
  pointerEvents: "none"
318
239
  };
319
240
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: joinClasses("relative h-full w-full overflow-hidden", className), children: [
@@ -323,6 +244,9 @@ function BottomStickScrollArea({
323
244
  ref: viewportRef,
324
245
  className: joinClasses("h-full w-full overflow-auto", viewportClassName),
325
246
  onScroll: onViewportScroll,
247
+ onWheel: interruptReturnForUserIntent,
248
+ onTouchStart: interruptReturnForUserIntent,
249
+ onKeyDown: onViewportKeyDown,
326
250
  "data-testid": "sticky-scroll-viewport",
327
251
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: contentRef, className: joinClasses("flex min-h-full w-full flex-col", contentClassName), children })
328
252
  }