@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.
- package/CHANGELOG.md +371 -0
- package/README.md +79 -4
- package/dist/blocks-renderer-DAOBFBfi.d.ts +29 -0
- package/dist/blocks-renderer-DQEL1kJW.d.cts +29 -0
- package/dist/components/bottom-stick-scroll-area.cjs +117 -193
- package/dist/components/bottom-stick-scroll-area.mjs +112 -183
- package/dist/components/diff-renderer.cjs +86 -0
- package/dist/components/diff-renderer.d.cts +11 -0
- package/dist/components/diff-renderer.d.ts +11 -0
- package/dist/components/diff-renderer.mjs +66 -0
- package/dist/components/index.cjs +2761 -1508
- package/dist/components/index.d.cts +7 -2
- package/dist/components/index.d.ts +7 -2
- package/dist/components/index.mjs +2730 -1493
- package/dist/components/katex-math.cjs +220 -0
- package/dist/components/katex-math.d.cts +10 -0
- package/dist/components/katex-math.d.ts +10 -0
- package/dist/components/katex-math.mjs +188 -0
- package/dist/contexts/math-tracker.cjs +240 -521
- package/dist/contexts/math-tracker.mjs +235 -513
- package/dist/index-Cmne1yUK.d.cts +723 -0
- package/dist/index-D7dyyu3q.d.ts +723 -0
- package/dist/index.cjs +13029 -6475
- package/dist/index.d.cts +69 -39
- package/dist/index.d.ts +69 -39
- package/dist/index.mjs +13007 -6442
- package/dist/math/display-wrapper.cjs +7 -15
- package/dist/math/display-wrapper.d.cts +2 -2
- package/dist/math/display-wrapper.d.ts +2 -2
- package/dist/math/display-wrapper.mjs +2 -6
- package/dist/node-views-Bpc6Gkgl.d.cts +13 -0
- package/dist/node-views-DpnYdaAS.d.ts +13 -0
- package/dist/renderer/hooks.cjs +35 -20
- package/dist/renderer/hooks.d.cts +22 -1
- package/dist/renderer/hooks.d.ts +22 -1
- package/dist/renderer/hooks.mjs +27 -12
- package/dist/renderer/patch-batching.cjs +5 -8
- package/dist/renderer/patch-coalescing.cjs +5 -8
- package/dist/renderer/patch-commit-scheduler.cjs +138 -356
- package/dist/renderer/patch-commit-scheduler.d.cts +13 -1
- package/dist/renderer/patch-commit-scheduler.d.ts +13 -1
- package/dist/renderer/patch-commit-scheduler.mjs +133 -348
- package/dist/renderer/store.cjs +3775 -1373
- package/dist/renderer/store.d.cts +108 -3
- package/dist/renderer/store.d.ts +108 -3
- package/dist/renderer/store.mjs +3778 -1362
- package/dist/renderer/virtualized-code.cjs +415 -71
- package/dist/renderer/virtualized-code.d.cts +24 -23
- package/dist/renderer/virtualized-code.d.ts +24 -23
- package/dist/renderer/virtualized-code.mjs +409 -62
- package/dist/renderer.cjs +10655 -4334
- package/dist/renderer.d.cts +98 -29
- package/dist/renderer.d.ts +98 -29
- package/dist/renderer.mjs +10582 -4212
- package/dist/server-regions-CPLHGli0.d.cts +32 -0
- package/dist/server-regions-mUhyoKi7.d.ts +32 -0
- package/dist/server.cjs +10195 -3872
- package/dist/server.d.cts +17 -252
- package/dist/server.d.ts +17 -252
- package/dist/server.mjs +9997 -3649
- package/dist/{streaming-markdown-CEI9eDZm.d.ts → streaming-markdown-yELbJxyH.d.ts} +49 -55
- package/dist/{streaming-markdown-DRisClXb.d.cts → streaming-markdown-zVwFuaJG.d.cts} +49 -55
- package/dist/streaming-markdown.cjs +11660 -5378
- package/dist/streaming-markdown.d.cts +7 -2
- package/dist/streaming-markdown.d.ts +7 -2
- package/dist/streaming-markdown.mjs +11679 -5347
- package/dist/trusted-mdx/index.cjs +833 -0
- package/dist/trusted-mdx/index.d.cts +11 -0
- package/dist/trusted-mdx/index.d.ts +11 -0
- package/dist/trusted-mdx/index.mjs +807 -0
- package/dist/trusted-mdx/native-children-slot.cjs +45 -0
- package/dist/trusted-mdx/native-children-slot.d.cts +11 -0
- package/dist/trusted-mdx/native-children-slot.d.ts +11 -0
- package/dist/trusted-mdx/native-children-slot.mjs +24 -0
- package/dist/trusted-mdx/server.cjs +752 -0
- package/dist/trusted-mdx/server.d.cts +24 -0
- package/dist/trusted-mdx/server.d.ts +24 -0
- package/dist/trusted-mdx/server.mjs +724 -0
- package/dist/trusted-mdx-contract-ElKpkDI5.d.cts +113 -0
- package/dist/trusted-mdx-contract-ElKpkDI5.d.ts +113 -0
- package/dist/utils/inline-html.cjs +246 -147
- package/dist/utils/inline-html.d.cts +37 -6
- package/dist/utils/inline-html.d.ts +37 -6
- package/dist/utils/inline-html.mjs +237 -134
- package/package.json +41 -18
- package/dist/index-BVhp_pcF.d.ts +0 -251
- package/dist/index-EaeouYp2.d.cts +0 -251
- package/dist/mdx-client.cjs +0 -408
- package/dist/mdx-client.d.cts +0 -113
- package/dist/mdx-client.d.ts +0 -113
- package/dist/mdx-client.mjs +0 -369
- package/dist/mdx-coordinator.cjs +0 -584
- package/dist/mdx-coordinator.d.cts +0 -21
- package/dist/mdx-coordinator.d.ts +0 -21
- package/dist/mdx-coordinator.mjs +0 -550
- package/dist/renderer/node-views.cjs +0 -1887
- package/dist/renderer/node-views.d.cts +0 -14
- package/dist/renderer/node-views.d.ts +0 -14
- 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:
|
|
11
|
-
}
|
|
12
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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":
|
|
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 =
|
|
93
|
+
showJumpToBottom = !0,
|
|
87
94
|
onDebugStateChange,
|
|
88
95
|
onModeChange,
|
|
89
|
-
debugDomAttributes =
|
|
96
|
+
debugDomAttributes = !1,
|
|
90
97
|
renderJumpToBottom,
|
|
91
98
|
jumpContainerClassName
|
|
92
99
|
}) {
|
|
93
|
-
|
|
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
|
-
|
|
115
|
-
const viewport = viewportRef.current;
|
|
105
|
+
), updateDebug = (0, import_react.useCallback)(() => {
|
|
106
|
+
let viewport = viewportRef.current;
|
|
116
107
|
if (!viewport) return;
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
197
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
236
|
-
const m = measure(viewport);
|
|
193
|
+
let viewport = event.currentTarget, m = measure(viewport);
|
|
237
194
|
setIsOverflowing((previous) => previous === m.isOverflowing ? previous : m.isOverflowing);
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
266
|
-
const content = contentRef.current;
|
|
201
|
+
let viewport = viewportRef.current, content = contentRef.current;
|
|
267
202
|
if (!viewport || !content) return;
|
|
268
|
-
|
|
269
|
-
|
|
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
|
-
|
|
278
|
-
|
|
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
|
-
|
|
285
|
-
writeScrollTop(initial.maxScrollTop);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}, [
|
|
291
|
-
|
|
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
|
-
|
|
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
|
}
|