myoperator-mcp 0.2.374 → 0.2.376
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.js +93 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6780,6 +6780,14 @@ const MENU_MIN_HEIGHT = 120;
|
|
|
6780
6780
|
*/
|
|
6781
6781
|
const SCROLL_END_THRESHOLD_PX = 48;
|
|
6782
6782
|
|
|
6783
|
+
/**
|
|
6784
|
+
* How long to wait after a page lands before re-measuring the list. React has
|
|
6785
|
+
* committed the new rows by the time the effect runs, but the browser has not
|
|
6786
|
+
* necessarily laid them out, so \`scrollHeight\` can still read the pre-growth
|
|
6787
|
+
* value. One frame is usually enough; 50ms is a cheap margin.
|
|
6788
|
+
*/
|
|
6789
|
+
const POST_FETCH_MEASURE_DELAY_MS = 50;
|
|
6790
|
+
|
|
6783
6791
|
/**
|
|
6784
6792
|
* MultiSelect trigger variants matching TextField styling
|
|
6785
6793
|
*/
|
|
@@ -7091,11 +7099,32 @@ const MultiSelect = React.forwardRef(
|
|
|
7091
7099
|
const listRef = React.useRef<HTMLDivElement | null>(null);
|
|
7092
7100
|
/**
|
|
7093
7101
|
* True once \`onScrollEnd\` has fired for the current visit to the bottom.
|
|
7094
|
-
* Cleared
|
|
7095
|
-
*
|
|
7096
|
-
* the finger lifts \u2014
|
|
7102
|
+
* Cleared when the user scrolls back out of the threshold zone, or when a
|
|
7103
|
+
* landed page pushes the bottom back out of reach, so trackpad inertia \u2014
|
|
7104
|
+
* which keeps firing \`scroll\` for hundreds of ms after the finger lifts \u2014
|
|
7105
|
+
* cannot re-trigger the callback.
|
|
7097
7106
|
*/
|
|
7098
7107
|
const isLatchedRef = React.useRef(false);
|
|
7108
|
+
/** Previous \`loadingMore\`, so the re-measure knows a page just landed. */
|
|
7109
|
+
const wasLoadingMoreRef = React.useRef(false);
|
|
7110
|
+
/** Pending \`requestAnimationFrame\` id for the coalesced scroll handler. */
|
|
7111
|
+
const scrollFrameRef = React.useRef<number | null>(null);
|
|
7112
|
+
/**
|
|
7113
|
+
* \`onScrollEnd\` read from a timer rather than from the closure, so an
|
|
7114
|
+
* inline arrow from the consumer cannot restart the post-fetch timer on
|
|
7115
|
+
* every render.
|
|
7116
|
+
*/
|
|
7117
|
+
const onScrollEndRef = React.useRef(onScrollEnd);
|
|
7118
|
+
React.useEffect(() => {
|
|
7119
|
+
onScrollEndRef.current = onScrollEnd;
|
|
7120
|
+
}, [onScrollEnd]);
|
|
7121
|
+
|
|
7122
|
+
/** Distance in px from the current scroll position to the list bottom. */
|
|
7123
|
+
const distanceToBottom = () => {
|
|
7124
|
+
const node = listRef.current;
|
|
7125
|
+
if (!node) return null;
|
|
7126
|
+
return node.scrollHeight - node.scrollTop - node.clientHeight;
|
|
7127
|
+
};
|
|
7099
7128
|
|
|
7100
7129
|
/**
|
|
7101
7130
|
* Deliberately a plain function, not a \`useCallback\` \u2014 it must read the
|
|
@@ -7103,14 +7132,10 @@ const MultiSelect = React.forwardRef(
|
|
|
7103
7132
|
* handler would need a props ref (writing refs during render is banned).
|
|
7104
7133
|
*/
|
|
7105
7134
|
const maybeLoadMore = () => {
|
|
7106
|
-
const
|
|
7107
|
-
if (
|
|
7135
|
+
const distance = distanceToBottom();
|
|
7136
|
+
if (distance === null) return;
|
|
7108
7137
|
|
|
7109
|
-
|
|
7110
|
-
node.scrollHeight - node.scrollTop - node.clientHeight <
|
|
7111
|
-
SCROLL_END_THRESHOLD_PX;
|
|
7112
|
-
|
|
7113
|
-
if (!isNearBottom) {
|
|
7138
|
+
if (distance >= SCROLL_END_THRESHOLD_PX) {
|
|
7114
7139
|
// Only an explicit scroll away from the boundary re-arms the latch.
|
|
7115
7140
|
isLatchedRef.current = false;
|
|
7116
7141
|
return;
|
|
@@ -7122,25 +7147,71 @@ const MultiSelect = React.forwardRef(
|
|
|
7122
7147
|
onScrollEnd();
|
|
7123
7148
|
};
|
|
7124
7149
|
|
|
7150
|
+
/**
|
|
7151
|
+
* \`scroll\` fires far more often than the browser paints, so a fast flick
|
|
7152
|
+
* delivers a burst of events whose geometry is mid-flight. Coalescing to
|
|
7153
|
+
* one \`requestAnimationFrame\` per burst measures once per frame, after
|
|
7154
|
+
* layout has settled, and still sees the final resting position.
|
|
7155
|
+
*/
|
|
7156
|
+
const handleListScroll = () => {
|
|
7157
|
+
if (scrollFrameRef.current !== null) return;
|
|
7158
|
+
scrollFrameRef.current = requestAnimationFrame(() => {
|
|
7159
|
+
scrollFrameRef.current = null;
|
|
7160
|
+
maybeLoadMore();
|
|
7161
|
+
});
|
|
7162
|
+
};
|
|
7163
|
+
|
|
7125
7164
|
// A closed menu or a new search starts from a clean latch.
|
|
7126
7165
|
React.useEffect(() => {
|
|
7127
7166
|
isLatchedRef.current = false;
|
|
7128
7167
|
}, [isOpen, searchQuery]);
|
|
7129
7168
|
|
|
7169
|
+
React.useEffect(
|
|
7170
|
+
() => () => {
|
|
7171
|
+
if (scrollFrameRef.current !== null) {
|
|
7172
|
+
cancelAnimationFrame(scrollFrameRef.current);
|
|
7173
|
+
}
|
|
7174
|
+
},
|
|
7175
|
+
[]
|
|
7176
|
+
);
|
|
7177
|
+
|
|
7130
7178
|
/**
|
|
7131
|
-
*
|
|
7132
|
-
*
|
|
7133
|
-
*
|
|
7134
|
-
*
|
|
7179
|
+
* Re-measure once a page has landed. Content growth emits no \`scroll\`
|
|
7180
|
+
* event, so without this the latch set on the way down would never clear
|
|
7181
|
+
* and pagination would stall permanently after a fast flick to the bottom.
|
|
7182
|
+
* It also covers the case where the page does not make the list taller
|
|
7183
|
+
* than its max-height (few results, or a short viewport), where no further
|
|
7184
|
+
* \`scroll\` event would ever fire either.
|
|
7185
|
+
*
|
|
7186
|
+
* The latch is cleared only once the bottom is genuinely out of reach \u2014
|
|
7187
|
+
* while the user is still pinned at distance ~0, it stays armed and the
|
|
7188
|
+
* next page is chained explicitly, so inertia cannot fan out into
|
|
7189
|
+
* duplicate requests.
|
|
7135
7190
|
*/
|
|
7136
7191
|
React.useEffect(() => {
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
if (!
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7192
|
+
const pageJustLanded = wasLoadingMoreRef.current && !loadingMore;
|
|
7193
|
+
wasLoadingMoreRef.current = loadingMore;
|
|
7194
|
+
if (!isOpen || loadingMore) return;
|
|
7195
|
+
|
|
7196
|
+
const timeoutId = window.setTimeout(() => {
|
|
7197
|
+
const distance = distanceToBottom();
|
|
7198
|
+
if (distance === null) return;
|
|
7199
|
+
|
|
7200
|
+
if (distance >= SCROLL_END_THRESHOLD_PX) {
|
|
7201
|
+
isLatchedRef.current = false;
|
|
7202
|
+
return;
|
|
7203
|
+
}
|
|
7204
|
+
if (!hasMore || !onScrollEndRef.current) return;
|
|
7205
|
+
// Still latched and nothing landed: the scroll handler's request is
|
|
7206
|
+
// in flight (or the consumer never set \`loadingMore\`) \u2014 don't refire.
|
|
7207
|
+
if (isLatchedRef.current && !pageJustLanded) return;
|
|
7208
|
+
|
|
7209
|
+
isLatchedRef.current = true;
|
|
7210
|
+
onScrollEndRef.current();
|
|
7211
|
+
}, POST_FETCH_MEASURE_DELAY_MS);
|
|
7212
|
+
|
|
7213
|
+
return () => window.clearTimeout(timeoutId);
|
|
7214
|
+
}, [isOpen, portalTarget, hasMore, loadingMore, options.length]);
|
|
7144
7215
|
|
|
7145
7216
|
const flatOptions = React.useMemo(
|
|
7146
7217
|
() => flattenMultiSelectOptions(options),
|
|
@@ -7572,7 +7643,7 @@ const MultiSelect = React.forwardRef(
|
|
|
7572
7643
|
{/* Options */}
|
|
7573
7644
|
<div
|
|
7574
7645
|
ref={listRef}
|
|
7575
|
-
onScroll={
|
|
7646
|
+
onScroll={handleListScroll}
|
|
7576
7647
|
className="overflow-auto overscroll-contain p-1"
|
|
7577
7648
|
style={{
|
|
7578
7649
|
maxHeight:
|
package/package.json
CHANGED