@particle-academy/react-fancy 5.32.0 → 5.34.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 (85) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/LICENSE +21 -0
  3. package/dist/activity-light.cjs +13 -0
  4. package/dist/activity-light.cjs.map +1 -0
  5. package/dist/activity-light.d.cts +64 -0
  6. package/dist/activity-light.d.ts +64 -0
  7. package/dist/activity-light.js +4 -0
  8. package/dist/activity-light.js.map +1 -0
  9. package/dist/button.cjs +4 -4
  10. package/dist/button.js +2 -2
  11. package/dist/{chunk-WRQBV7GU.cjs → chunk-23FTDEGR.cjs} +2 -2
  12. package/dist/chunk-23FTDEGR.cjs.map +1 -0
  13. package/dist/{chunk-ZYVWKYPO.js → chunk-2OMB3OOR.js} +3 -3
  14. package/dist/{chunk-ZYVWKYPO.js.map → chunk-2OMB3OOR.js.map} +1 -1
  15. package/dist/{chunk-WHOVPDC5.js → chunk-2XAVAPDA.js} +2 -2
  16. package/dist/chunk-2XAVAPDA.js.map +1 -0
  17. package/dist/{chunk-G6VMNSCM.js → chunk-46IPQEUP.js} +3 -3
  18. package/dist/{chunk-G6VMNSCM.js.map → chunk-46IPQEUP.js.map} +1 -1
  19. package/dist/{chunk-H6PXIB35.cjs → chunk-5Q7EQQTT.cjs} +4 -4
  20. package/dist/{chunk-H6PXIB35.cjs.map → chunk-5Q7EQQTT.cjs.map} +1 -1
  21. package/dist/{chunk-BQ77ZWFM.js → chunk-6ASZUE4T.js} +4 -4
  22. package/dist/{chunk-BQ77ZWFM.js.map → chunk-6ASZUE4T.js.map} +1 -1
  23. package/dist/{chunk-WEKQD4BQ.js → chunk-DCDW3LW6.js} +3 -3
  24. package/dist/{chunk-WEKQD4BQ.js.map → chunk-DCDW3LW6.js.map} +1 -1
  25. package/dist/{chunk-YMU3SS6D.cjs → chunk-E2SZBIAV.cjs} +16 -16
  26. package/dist/{chunk-YMU3SS6D.cjs.map → chunk-E2SZBIAV.cjs.map} +1 -1
  27. package/dist/chunk-EHNMKQ4O.cjs +71 -0
  28. package/dist/chunk-EHNMKQ4O.cjs.map +1 -0
  29. package/dist/chunk-IR6JSQ4O.cjs +233 -0
  30. package/dist/chunk-IR6JSQ4O.cjs.map +1 -0
  31. package/dist/{chunk-VRJTPXJ7.cjs → chunk-J2KYNK63.cjs} +5 -5
  32. package/dist/{chunk-VRJTPXJ7.cjs.map → chunk-J2KYNK63.cjs.map} +1 -1
  33. package/dist/{chunk-B4PFNSX7.js → chunk-KM4R4XWB.js} +3 -3
  34. package/dist/{chunk-B4PFNSX7.js.map → chunk-KM4R4XWB.js.map} +1 -1
  35. package/dist/{chunk-5TUZENNJ.cjs → chunk-MTUH2X3W.cjs} +4 -4
  36. package/dist/{chunk-5TUZENNJ.cjs.map → chunk-MTUH2X3W.cjs.map} +1 -1
  37. package/dist/chunk-PZTA6NCD.js +69 -0
  38. package/dist/chunk-PZTA6NCD.js.map +1 -0
  39. package/dist/{chunk-UWL6U3L7.cjs → chunk-RMJGF7MN.cjs} +3 -3
  40. package/dist/{chunk-UWL6U3L7.cjs.map → chunk-RMJGF7MN.cjs.map} +1 -1
  41. package/dist/{chunk-EIUS2K72.js → chunk-TX6VUYBC.js} +3 -3
  42. package/dist/{chunk-EIUS2K72.js.map → chunk-TX6VUYBC.js.map} +1 -1
  43. package/dist/{chunk-LAQGBLIU.cjs → chunk-VKXNCYLE.cjs} +14 -5
  44. package/dist/chunk-VKXNCYLE.cjs.map +1 -0
  45. package/dist/{chunk-32HCJ5GD.js → chunk-W6RDAZJC.js} +14 -5
  46. package/dist/chunk-W6RDAZJC.js.map +1 -0
  47. package/dist/{chunk-LQFQ2UKU.cjs → chunk-WWUKTXPX.cjs} +3 -3
  48. package/dist/{chunk-LQFQ2UKU.cjs.map → chunk-WWUKTXPX.cjs.map} +1 -1
  49. package/dist/chunk-Z4CW3U6C.js +231 -0
  50. package/dist/chunk-Z4CW3U6C.js.map +1 -0
  51. package/dist/composer.cjs +2 -2
  52. package/dist/composer.d.cts +1 -1
  53. package/dist/composer.d.ts +1 -1
  54. package/dist/composer.js +1 -1
  55. package/dist/editor.cjs +4 -4
  56. package/dist/editor.js +2 -2
  57. package/dist/file-upload.cjs +3 -3
  58. package/dist/file-upload.js +1 -1
  59. package/dist/{index-CDo7LyIB.d.ts → index-C8PKWA_5.d.cts} +21 -0
  60. package/dist/{index-CDo7LyIB.d.cts → index-C8PKWA_5.d.ts} +21 -0
  61. package/dist/index.cjs +154 -144
  62. package/dist/index.d.cts +3 -1
  63. package/dist/index.d.ts +3 -1
  64. package/dist/index.js +29 -27
  65. package/dist/inputs.cjs +9 -9
  66. package/dist/inputs.js +3 -3
  67. package/dist/json-editor.cjs +15 -15
  68. package/dist/json-editor.js +4 -4
  69. package/dist/magic-wand.cjs +4 -4
  70. package/dist/magic-wand.js +3 -3
  71. package/dist/prompt-input.cjs +4 -4
  72. package/dist/prompt-input.js +3 -3
  73. package/dist/reason-tag.cjs +4 -4
  74. package/dist/reason-tag.js +3 -3
  75. package/dist/virtual-list.cjs +13 -0
  76. package/dist/virtual-list.cjs.map +1 -0
  77. package/dist/virtual-list.d.cts +125 -0
  78. package/dist/virtual-list.d.ts +125 -0
  79. package/dist/virtual-list.js +4 -0
  80. package/dist/virtual-list.js.map +1 -0
  81. package/package.json +23 -2
  82. package/dist/chunk-32HCJ5GD.js.map +0 -1
  83. package/dist/chunk-LAQGBLIU.cjs.map +0 -1
  84. package/dist/chunk-WHOVPDC5.js.map +0 -1
  85. package/dist/chunk-WRQBV7GU.cjs.map +0 -1
@@ -0,0 +1,231 @@
1
+ import { cn } from './chunk-MMW2JGKZ.js';
2
+ import { useRef, useState, useCallback, useMemo, useEffect, useLayoutEffect } from 'react';
3
+ import { jsx } from 'react/jsx-runtime';
4
+
5
+ function VirtualList({
6
+ items,
7
+ renderRow,
8
+ height = "100%",
9
+ estimateRowHeight = 32,
10
+ overscan = 6,
11
+ followTail = false,
12
+ onFollowChange,
13
+ onUnseenChange,
14
+ scrollToId = null,
15
+ onScrollToIdResolved,
16
+ className,
17
+ ref,
18
+ ...props
19
+ }) {
20
+ const viewportRef = useRef(null);
21
+ const windowRef = useRef(null);
22
+ const heights = useRef(/* @__PURE__ */ new Map());
23
+ const [measured, setMeasured] = useState(0);
24
+ const [scrollTop, setScrollTop] = useState(0);
25
+ const [clientHeight, setClientHeight] = useState(0);
26
+ const attachViewport = useCallback(
27
+ (el) => {
28
+ viewportRef.current = el;
29
+ if (typeof ref === "function") ref(el);
30
+ else if (ref) ref.current = el;
31
+ },
32
+ [ref]
33
+ );
34
+ const viewport = clientHeight > 0 ? clientHeight : typeof height === "number" ? height : estimateRowHeight * 20;
35
+ const { offsets, total } = useMemo(() => {
36
+ const offs = new Float64Array(items.length + 1);
37
+ for (let i = 0; i < items.length; i += 1) {
38
+ offs[i + 1] = offs[i] + (heights.current.get(items[i].id) ?? estimateRowHeight);
39
+ }
40
+ return { offsets: offs, total: items.length === 0 ? 0 : offs[items.length] };
41
+ }, [items, measured, estimateRowHeight]);
42
+ const indexAt = useCallback(
43
+ (y) => {
44
+ let lo = 0;
45
+ let hi = items.length - 1;
46
+ while (lo < hi) {
47
+ const mid = lo + hi + 1 >> 1;
48
+ if (offsets[mid] <= y) lo = mid;
49
+ else hi = mid - 1;
50
+ }
51
+ return Math.max(0, lo);
52
+ },
53
+ [items.length, offsets]
54
+ );
55
+ const start = Math.max(0, indexAt(scrollTop) - overscan);
56
+ const end = Math.min(items.length, indexAt(scrollTop + viewport) + 1 + overscan);
57
+ const visible = useMemo(() => items.slice(start, end), [items, start, end]);
58
+ const observer = useRef(null);
59
+ useEffect(() => {
60
+ if (typeof ResizeObserver === "undefined") return;
61
+ const ro = new ResizeObserver(() => setMeasured((v) => v + 1));
62
+ observer.current = ro;
63
+ return () => {
64
+ ro.disconnect();
65
+ observer.current = null;
66
+ };
67
+ }, []);
68
+ useLayoutEffect(() => {
69
+ const win = windowRef.current;
70
+ if (!win) return;
71
+ let changed = false;
72
+ for (const el of Array.from(win.children)) {
73
+ const id = el.getAttribute(ROW_ID_ATTR);
74
+ if (id === null) continue;
75
+ observer.current?.observe(el);
76
+ const h = el.getBoundingClientRect().height;
77
+ if (h > 0 && heights.current.get(id) !== h) {
78
+ heights.current.set(id, h);
79
+ changed = true;
80
+ }
81
+ }
82
+ const vp = viewportRef.current;
83
+ if (vp && vp.clientHeight > 0 && vp.clientHeight !== clientHeight) setClientHeight(vp.clientHeight);
84
+ if (changed) setMeasured((v) => v + 1);
85
+ });
86
+ const anchored = useRef(null);
87
+ const resolved = useRef(null);
88
+ useEffect(() => {
89
+ anchored.current = null;
90
+ resolved.current = null;
91
+ }, [scrollToId]);
92
+ useLayoutEffect(() => {
93
+ if (scrollToId === null || resolved.current === scrollToId) return;
94
+ const index = items.findIndex((item) => item.id === scrollToId);
95
+ if (index < 0) {
96
+ resolved.current = scrollToId;
97
+ onScrollToIdResolved?.(scrollToId, false);
98
+ return;
99
+ }
100
+ const vp = viewportRef.current;
101
+ if (!vp) return;
102
+ const target = Math.max(0, Math.min(offsets[index], Math.max(0, total - viewport)));
103
+ if (anchored.current !== target) {
104
+ anchored.current = target;
105
+ vp.scrollTop = target;
106
+ setScrollTop(target);
107
+ return;
108
+ }
109
+ if (Math.abs(vp.scrollTop - target) <= 1) {
110
+ resolved.current = scrollToId;
111
+ onScrollToIdResolved?.(scrollToId, true);
112
+ }
113
+ });
114
+ const reportedFollow = useRef(followTail);
115
+ const programmatic = useRef(false);
116
+ useEffect(() => {
117
+ reportedFollow.current = followTail;
118
+ }, [followTail]);
119
+ const askFollow = useCallback(
120
+ (next) => {
121
+ if (reportedFollow.current === next) return;
122
+ reportedFollow.current = next;
123
+ onFollowChange?.(next);
124
+ },
125
+ [onFollowChange]
126
+ );
127
+ useLayoutEffect(() => {
128
+ if (!followTail) return;
129
+ if (scrollToId !== null && resolved.current !== scrollToId) return;
130
+ const vp = viewportRef.current;
131
+ if (!vp) return;
132
+ const bottom = Math.max(0, total - viewport);
133
+ if (Math.abs(vp.scrollTop - bottom) > 0.5) {
134
+ programmatic.current = true;
135
+ vp.scrollTop = bottom;
136
+ setScrollTop(bottom);
137
+ }
138
+ });
139
+ const onScroll = useCallback(() => {
140
+ const vp = viewportRef.current;
141
+ if (!vp) return;
142
+ const next = vp.scrollTop;
143
+ const previous = scrollTop;
144
+ setScrollTop(next);
145
+ const bottom = Math.max(0, total - viewport);
146
+ const wasProgrammatic = programmatic.current;
147
+ programmatic.current = false;
148
+ if (next <= bottom - BOTTOM_SLACK) {
149
+ if (!wasProgrammatic && next < previous) askFollow(false);
150
+ } else {
151
+ askFollow(true);
152
+ }
153
+ }, [scrollTop, total, viewport, askFollow]);
154
+ const onWheel = useCallback(
155
+ (e) => {
156
+ if (e.deltaY < 0) askFollow(false);
157
+ },
158
+ [askFollow]
159
+ );
160
+ const onKeyDown = useCallback(
161
+ (e) => {
162
+ if (UPWARD_KEYS.has(e.key)) askFollow(false);
163
+ },
164
+ [askFollow]
165
+ );
166
+ const touchStart = useRef(null);
167
+ const onTouchStart = useCallback((e) => {
168
+ touchStart.current = e.touches[0]?.clientY ?? null;
169
+ }, []);
170
+ const onTouchMove = useCallback(
171
+ (e) => {
172
+ const from = touchStart.current;
173
+ const y = e.touches[0]?.clientY;
174
+ if (from !== null && y !== void 0 && y - from > TOUCH_SLOP) askFollow(false);
175
+ },
176
+ [askFollow]
177
+ );
178
+ const seen = useRef(items.length);
179
+ const reportedUnseen = useRef(null);
180
+ useEffect(() => {
181
+ const unseen = followTail ? 0 : Math.max(0, items.length - seen.current);
182
+ if (followTail) seen.current = items.length;
183
+ if (reportedUnseen.current === unseen) return;
184
+ reportedUnseen.current = unseen;
185
+ onUnseenChange?.(unseen);
186
+ }, [items.length, followTail, onUnseenChange]);
187
+ return /* @__PURE__ */ jsx(
188
+ "div",
189
+ {
190
+ ref: attachViewport,
191
+ "data-react-fancy-virtual-list": "",
192
+ "data-react-fancy-virtual-list-following": followTail ? "true" : "false",
193
+ "data-react-fancy-virtual-list-rows": items.length,
194
+ role: "log",
195
+ tabIndex: 0,
196
+ className: cn("relative overflow-y-auto overflow-x-hidden outline-none", className),
197
+ style: { height },
198
+ onScroll,
199
+ onWheel,
200
+ onKeyDown,
201
+ onTouchStart,
202
+ onTouchMove,
203
+ ...props,
204
+ children: /* @__PURE__ */ jsx(
205
+ "div",
206
+ {
207
+ "data-react-fancy-virtual-list-sizer": "",
208
+ style: { height: `${total}px`, position: "relative" },
209
+ children: /* @__PURE__ */ jsx(
210
+ "div",
211
+ {
212
+ ref: windowRef,
213
+ "data-react-fancy-virtual-list-window": "",
214
+ "data-react-fancy-virtual-list-start": start,
215
+ style: { transform: `translateY(${offsets[start] ?? 0}px)` },
216
+ children: visible.map((item, i) => /* @__PURE__ */ jsx("div", { "data-react-fancy-virtual-row-id": item.id, children: renderRow(item, start + i) }, item.id))
217
+ }
218
+ )
219
+ }
220
+ )
221
+ }
222
+ );
223
+ }
224
+ var ROW_ID_ATTR = "data-react-fancy-virtual-row-id";
225
+ var BOTTOM_SLACK = 4;
226
+ var TOUCH_SLOP = 4;
227
+ var UPWARD_KEYS = /* @__PURE__ */ new Set(["ArrowUp", "PageUp", "Home"]);
228
+
229
+ export { VirtualList };
230
+ //# sourceMappingURL=chunk-Z4CW3U6C.js.map
231
+ //# sourceMappingURL=chunk-Z4CW3U6C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/VirtualList/VirtualList.tsx"],"names":[],"mappings":"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","file":"chunk-Z4CW3U6C.js","sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent, TouchEvent, WheelEvent } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport type { VirtualListProps, VirtualListRow } from \"./VirtualList.types\";\n\n/**\n * A windowed list for ledgers that run to tens of thousands of rows — only the\n * visible slice is in the DOM, with **measured** variable row heights, deep\n * links by row id, and sticky-bottom tail-following.\n *\n * Built for an agent event stream, where every one of those three is load\n * bearing at once: message rows wrap and event rows do not, a link carries\n * `?at=<rowId>` to the exact row under discussion, and new rows arrive while\n * the human is reading older ones.\n *\n * ## Heights are measured, never predicted\n *\n * `estimateRowHeight` only seeds rows that have never been on screen. The\n * moment a row renders, its real height is measured and replaces the estimate,\n * and every offset after it moves. The alternative — a `rowHeight(item)`\n * callback — is a prediction about text wrapping, font loading and container\n * width, and when it is wrong the error accumulates down the list: rows draw in\n * the wrong place and `scrollToId` lands on a neighbour. Measuring is slower to\n * settle and correct when it does.\n *\n * ## Tail-follow breaks on INTENT, not on position\n *\n * Any upward gesture — wheel, drag, PageUp, Home — stops following\n * immediately, even when the list is still pinned to the bottom and\n * `scrollTop` has not changed yet. Position cannot tell \"the human scrolled\n * up\" from \"content grew downward\", so a position-only implementation keeps\n * following through a wheel-up and yanks the reader back on the next append.\n *\n * ## It is controlled\n *\n * `followTail` is the consumer's state. This component only ever *asks* via\n * `onFollowChange`, so the follow state is readable and writable by an agent\n * over a bridge, as the Human+ component contract requires. The `↓ n new` pill\n * is the consumer's to render, from `onUnseenChange`.\n *\n * @example\n * ```tsx\n * const [following, setFollowing] = useState(true);\n * const [unseen, setUnseen] = useState(0);\n *\n * <VirtualList\n * items={events}\n * renderRow={(e) => <StreamRow event={e} />}\n * height=\"100%\"\n * estimateRowHeight={28}\n * followTail={following}\n * onFollowChange={setFollowing}\n * onUnseenChange={setUnseen}\n * scrollToId={params.at}\n * />\n * {!following && unseen > 0 && (\n * <Button onClick={() => setFollowing(true)}>↓ {unseen} new</Button>\n * )}\n * ```\n */\nexport function VirtualList<T extends VirtualListRow>({\n items,\n renderRow,\n height = \"100%\",\n estimateRowHeight = 32,\n overscan = 6,\n followTail = false,\n onFollowChange,\n onUnseenChange,\n scrollToId = null,\n onScrollToIdResolved,\n className,\n ref,\n ...props\n}: VirtualListProps<T>) {\n const viewportRef = useRef<HTMLDivElement | null>(null);\n const windowRef = useRef<HTMLDivElement | null>(null);\n\n /** Measured heights by row id, so a height follows its row across a reindex. */\n const heights = useRef(new Map<string, number>());\n /** Bumped when a measurement actually changed, to recompute offsets. */\n const [measured, setMeasured] = useState(0);\n\n const [scrollTop, setScrollTop] = useState(0);\n const [clientHeight, setClientHeight] = useState(0);\n\n const attachViewport = useCallback(\n (el: HTMLDivElement | null) => {\n viewportRef.current = el;\n if (typeof ref === \"function\") ref(el);\n else if (ref) (ref as { current: HTMLDivElement | null }).current = el;\n },\n [ref],\n );\n\n // A number `height` IS the viewport height, and is usable before the element\n // has been measured. Without one, render a conservative first window so there\n // is something on screen for the measurement pass to work from.\n const viewport =\n clientHeight > 0 ? clientHeight : typeof height === \"number\" ? height : estimateRowHeight * 20;\n\n /**\n * Prefix sums of row heights: `offsets[i]` is where row `i` starts, and the\n * last entry is the total. Rebuilt whenever rows or measurements change —\n * O(n) once per change, against O(log n) per scroll from the binary search,\n * rather than O(n) on every scroll frame.\n */\n const { offsets, total } = useMemo(() => {\n const offs = new Float64Array(items.length + 1);\n for (let i = 0; i < items.length; i += 1) {\n offs[i + 1] = offs[i] + (heights.current.get(items[i].id) ?? estimateRowHeight);\n }\n\n return { offsets: offs, total: items.length === 0 ? 0 : offs[items.length] };\n }, [items, measured, estimateRowHeight]);\n\n /** First row whose span contains `y`. */\n const indexAt = useCallback(\n (y: number): number => {\n let lo = 0;\n let hi = items.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (offsets[mid] <= y) lo = mid;\n else hi = mid - 1;\n }\n\n return Math.max(0, lo);\n },\n [items.length, offsets],\n );\n\n const start = Math.max(0, indexAt(scrollTop) - overscan);\n const end = Math.min(items.length, indexAt(scrollTop + viewport) + 1 + overscan);\n const visible = useMemo(() => items.slice(start, end), [items, start, end]);\n\n // ---------------------------------------------------------------- measuring\n\n const observer = useRef<ResizeObserver | null>(null);\n\n useEffect(() => {\n // Absent in jsdom and in older runtimes. Without it the list still measures\n // on every render; it just does not notice a row reflowing in place.\n if (typeof ResizeObserver === \"undefined\") return;\n\n const ro = new ResizeObserver(() => setMeasured((v) => v + 1));\n observer.current = ro;\n\n return () => {\n ro.disconnect();\n observer.current = null;\n };\n }, []);\n\n // No dependency array on purpose: every render re-measures what is on screen,\n // and the `changed` guard is what stops it looping. A render that learns\n // nothing new sets no state.\n useLayoutEffect(() => {\n const win = windowRef.current;\n if (!win) return;\n\n let changed = false;\n for (const el of Array.from(win.children) as HTMLElement[]) {\n const id = el.getAttribute(ROW_ID_ATTR);\n if (id === null) continue;\n\n observer.current?.observe(el);\n\n const h = el.getBoundingClientRect().height;\n // A zero height is \"not laid out yet\", not a 0px row. Recording it would\n // collapse the list and make every offset after it wrong.\n if (h > 0 && heights.current.get(id) !== h) {\n heights.current.set(id, h);\n changed = true;\n }\n }\n\n const vp = viewportRef.current;\n if (vp && vp.clientHeight > 0 && vp.clientHeight !== clientHeight) setClientHeight(vp.clientHeight);\n\n if (changed) setMeasured((v) => v + 1);\n });\n\n // ------------------------------------------------------------- deep linking\n\n /** The target this component last moved to, to detect that it has settled. */\n const anchored = useRef<number | null>(null);\n const resolved = useRef<string | null>(null);\n\n useEffect(() => {\n // A new id is a new request, even if the old one had resolved.\n anchored.current = null;\n resolved.current = null;\n }, [scrollToId]);\n\n useLayoutEffect(() => {\n if (scrollToId === null || resolved.current === scrollToId) return;\n\n const index = items.findIndex((item) => item.id === scrollToId);\n if (index < 0) {\n // A link to a row that is no longer in the list. Leaving the viewport\n // where it is and SAYING SO is the only honest outcome — scrolling to the\n // top would be indistinguishable from a successful landing.\n resolved.current = scrollToId;\n onScrollToIdResolved?.(scrollToId, false);\n\n return;\n }\n\n const vp = viewportRef.current;\n if (!vp) return;\n\n // Clamped the way the browser clamps: a row inside the final viewport-height\n // of the list cannot be brought to the top, and pretending otherwise would\n // leave this waiting for a position that can never be reached.\n const target = Math.max(0, Math.min(offsets[index], Math.max(0, total - viewport)));\n\n if (anchored.current !== target) {\n anchored.current = target;\n vp.scrollTop = target;\n setScrollTop(target);\n\n return;\n }\n\n // The target stopped moving as rows above it were measured, and we are on\n // it. Only now is the deep link actually honoured.\n if (Math.abs(vp.scrollTop - target) <= 1) {\n resolved.current = scrollToId;\n onScrollToIdResolved?.(scrollToId, true);\n }\n });\n\n // ------------------------------------------------------------- tail-follow\n\n const reportedFollow = useRef(followTail);\n const programmatic = useRef(false);\n\n useEffect(() => {\n // The prop is the truth, so adopt it rather than remembering what we asked\n // for. Otherwise a consumer that declines an `onFollowChange(false)` would\n // never be asked again.\n reportedFollow.current = followTail;\n }, [followTail]);\n\n const askFollow = useCallback(\n (next: boolean) => {\n if (reportedFollow.current === next) return;\n reportedFollow.current = next;\n onFollowChange?.(next);\n },\n [onFollowChange],\n );\n\n useLayoutEffect(() => {\n if (!followTail) return;\n // A pending deep link wins while it resolves; otherwise the two would fight\n // over the same scrollTop and the link would lose.\n if (scrollToId !== null && resolved.current !== scrollToId) return;\n\n const vp = viewportRef.current;\n if (!vp) return;\n\n const bottom = Math.max(0, total - viewport);\n if (Math.abs(vp.scrollTop - bottom) > 0.5) {\n programmatic.current = true;\n vp.scrollTop = bottom;\n setScrollTop(bottom);\n }\n });\n\n const onScroll = useCallback(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n\n const next = vp.scrollTop;\n const previous = scrollTop;\n setScrollTop(next);\n\n const bottom = Math.max(0, total - viewport);\n const wasProgrammatic = programmatic.current;\n programmatic.current = false;\n\n if (next <= bottom - BOTTOM_SLACK) {\n // Moved up, and not because we moved it.\n if (!wasProgrammatic && next < previous) askFollow(false);\n } else {\n askFollow(true);\n }\n }, [scrollTop, total, viewport, askFollow]);\n\n /** Any upward gesture is a statement of intent, whatever scrollTop says. */\n const onWheel = useCallback(\n (e: WheelEvent<HTMLDivElement>) => {\n if (e.deltaY < 0) askFollow(false);\n },\n [askFollow],\n );\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (UPWARD_KEYS.has(e.key)) askFollow(false);\n },\n [askFollow],\n );\n\n const touchStart = useRef<number | null>(null);\n\n const onTouchStart = useCallback((e: TouchEvent<HTMLDivElement>) => {\n touchStart.current = e.touches[0]?.clientY ?? null;\n }, []);\n\n const onTouchMove = useCallback(\n (e: TouchEvent<HTMLDivElement>) => {\n const from = touchStart.current;\n const y = e.touches[0]?.clientY;\n // Finger travelling DOWN drags the content down, which scrolls up.\n if (from !== null && y !== undefined && y - from > TOUCH_SLOP) askFollow(false);\n },\n [askFollow],\n );\n\n // ------------------------------------------------------------ unseen count\n\n const seen = useRef(items.length);\n const reportedUnseen = useRef<number | null>(null);\n\n useEffect(() => {\n const unseen = followTail ? 0 : Math.max(0, items.length - seen.current);\n if (followTail) seen.current = items.length;\n\n if (reportedUnseen.current === unseen) return;\n reportedUnseen.current = unseen;\n onUnseenChange?.(unseen);\n }, [items.length, followTail, onUnseenChange]);\n\n // ------------------------------------------------------------------ render\n\n return (\n <div\n ref={attachViewport}\n data-react-fancy-virtual-list=\"\"\n data-react-fancy-virtual-list-following={followTail ? \"true\" : \"false\"}\n data-react-fancy-virtual-list-rows={items.length}\n role=\"log\"\n tabIndex={0}\n className={cn(\"relative overflow-y-auto overflow-x-hidden outline-none\", className)}\n style={{ height }}\n onScroll={onScroll}\n onWheel={onWheel}\n onKeyDown={onKeyDown}\n onTouchStart={onTouchStart}\n onTouchMove={onTouchMove}\n {...props}\n >\n {/* Holds the full scroll range so the scrollbar is honest from the first\n paint, instead of growing as rows are discovered. */}\n <div\n data-react-fancy-virtual-list-sizer=\"\"\n style={{ height: `${total}px`, position: \"relative\" }}\n >\n <div\n ref={windowRef}\n data-react-fancy-virtual-list-window=\"\"\n data-react-fancy-virtual-list-start={start}\n style={{ transform: `translateY(${offsets[start] ?? 0}px)` }}\n >\n {visible.map((item, i) => (\n <div key={item.id} data-react-fancy-virtual-row-id={item.id}>\n {renderRow(item, start + i)}\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nconst ROW_ID_ATTR = \"data-react-fancy-virtual-row-id\";\n/** Within this many px of the bottom counts as \"at the bottom\". */\nconst BOTTOM_SLACK = 4;\n/** Ignore a touch jitter smaller than this before calling it an upward drag. */\nconst TOUCH_SLOP = 4;\nconst UPWARD_KEYS = new Set([\"ArrowUp\", \"PageUp\", \"Home\"]);\n"]}
package/dist/composer.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkWRQBV7GU_cjs = require('./chunk-WRQBV7GU.cjs');
3
+ var chunk23FTDEGR_cjs = require('./chunk-23FTDEGR.cjs');
4
4
  require('./chunk-SNHU2AI4.cjs');
5
5
  require('./chunk-ZU5Q77OT.cjs');
6
6
 
@@ -8,7 +8,7 @@ require('./chunk-ZU5Q77OT.cjs');
8
8
 
9
9
  Object.defineProperty(exports, "Composer", {
10
10
  enumerable: true,
11
- get: function () { return chunkWRQBV7GU_cjs.Composer; }
11
+ get: function () { return chunk23FTDEGR_cjs.Composer; }
12
12
  });
13
13
  //# sourceMappingURL=composer.cjs.map
14
14
  //# sourceMappingURL=composer.cjs.map
@@ -1,2 +1,2 @@
1
- export { C as Composer, a as ComposerProps, H as HeldPaste } from './index-CDo7LyIB.cjs';
1
+ export { C as Composer, a as ComposerProps, H as HeldPaste } from './index-C8PKWA_5.cjs';
2
2
  import 'react';
@@ -1,2 +1,2 @@
1
- export { C as Composer, a as ComposerProps, H as HeldPaste } from './index-CDo7LyIB.js';
1
+ export { C as Composer, a as ComposerProps, H as HeldPaste } from './index-C8PKWA_5.js';
2
2
  import 'react';
package/dist/composer.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Composer } from './chunk-WHOVPDC5.js';
1
+ export { Composer } from './chunk-2XAVAPDA.js';
2
2
  import './chunk-EDYAXGUM.js';
3
3
  import './chunk-MMW2JGKZ.js';
4
4
  //# sourceMappingURL=composer.js.map
package/dist/editor.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunkLQFQ2UKU_cjs = require('./chunk-LQFQ2UKU.cjs');
3
+ var chunkWWUKTXPX_cjs = require('./chunk-WWUKTXPX.cjs');
4
4
  require('./chunk-HPNIEYSJ.cjs');
5
5
  require('./chunk-T6YELZPJ.cjs');
6
+ require('./chunk-ND5D7GJB.cjs');
6
7
  require('./chunk-G7227RTY.cjs');
7
8
  require('./chunk-TXTRTTG7.cjs');
8
9
  require('./chunk-3WGRVDQR.cjs');
9
- require('./chunk-ND5D7GJB.cjs');
10
10
  require('./chunk-BFKCVSNK.cjs');
11
11
  require('./chunk-J2DI6RMR.cjs');
12
12
  require('./chunk-L3V3BYVS.cjs');
@@ -19,11 +19,11 @@ require('./chunk-ZU5Q77OT.cjs');
19
19
 
20
20
  Object.defineProperty(exports, "Editor", {
21
21
  enumerable: true,
22
- get: function () { return chunkLQFQ2UKU_cjs.Editor; }
22
+ get: function () { return chunkWWUKTXPX_cjs.Editor; }
23
23
  });
24
24
  Object.defineProperty(exports, "useEditor", {
25
25
  enumerable: true,
26
- get: function () { return chunkLQFQ2UKU_cjs.useEditor; }
26
+ get: function () { return chunkWWUKTXPX_cjs.useEditor; }
27
27
  });
28
28
  //# sourceMappingURL=editor.cjs.map
29
29
  //# sourceMappingURL=editor.cjs.map
package/dist/editor.js CHANGED
@@ -1,10 +1,10 @@
1
- export { Editor, useEditor } from './chunk-EIUS2K72.js';
1
+ export { Editor, useEditor } from './chunk-TX6VUYBC.js';
2
2
  import './chunk-FWCREAIT.js';
3
3
  import './chunk-CPY7NHXM.js';
4
+ import './chunk-25ZOOUFG.js';
4
5
  import './chunk-FBWUXSKH.js';
5
6
  import './chunk-5U2DZ7AV.js';
6
7
  import './chunk-CHADHN6M.js';
7
- import './chunk-25ZOOUFG.js';
8
8
  import './chunk-XJXQG34J.js';
9
9
  import './chunk-MQ6VGG62.js';
10
10
  import './chunk-NRXK42LO.js';
@@ -1,17 +1,17 @@
1
1
  'use strict';
2
2
 
3
- var chunkLAQGBLIU_cjs = require('./chunk-LAQGBLIU.cjs');
3
+ var chunkVKXNCYLE_cjs = require('./chunk-VKXNCYLE.cjs');
4
4
  require('./chunk-ZU5Q77OT.cjs');
5
5
 
6
6
 
7
7
 
8
8
  Object.defineProperty(exports, "FileUpload", {
9
9
  enumerable: true,
10
- get: function () { return chunkLAQGBLIU_cjs.FileUpload; }
10
+ get: function () { return chunkVKXNCYLE_cjs.FileUpload; }
11
11
  });
12
12
  Object.defineProperty(exports, "useFileUpload", {
13
13
  enumerable: true,
14
- get: function () { return chunkLAQGBLIU_cjs.useFileUpload; }
14
+ get: function () { return chunkVKXNCYLE_cjs.useFileUpload; }
15
15
  });
16
16
  //# sourceMappingURL=file-upload.cjs.map
17
17
  //# sourceMappingURL=file-upload.cjs.map
@@ -1,4 +1,4 @@
1
- export { FileUpload, useFileUpload } from './chunk-32HCJ5GD.js';
1
+ export { FileUpload, useFileUpload } from './chunk-W6RDAZJC.js';
2
2
  import './chunk-MMW2JGKZ.js';
3
3
  //# sourceMappingURL=file-upload.js.map
4
4
  //# sourceMappingURL=file-upload.js.map
@@ -90,6 +90,27 @@ interface UsePastePillsResult {
90
90
  * still closed carries the text.
91
91
  *
92
92
  * It owns no DOM. The host renders the pills.
93
+ *
94
+ * ---------------------------------------------------------------------------
95
+ * Who actually calls this (as of 5.32.0): `Composer`, and nothing else
96
+ * ---------------------------------------------------------------------------
97
+ *
98
+ * The estate that specified it **withdrew before adopting it**, hours after it
99
+ * shipped — their design moved the pill INTO the message as a `[paste:id|label]`
100
+ * marker in the same grammar as their other object tags, which makes the message
101
+ * itself the record of what is attached. A parallel `heldPastes` array would then be
102
+ * a second place answering "what am I sending?", and the two would disagree the
103
+ * moment someone backspaced a badge. Their reasoning was better than the spec.
104
+ *
105
+ * Recorded because a reader should not infer an extension point under active
106
+ * external use. It is kept rather than withdrawn for two reasons that are about
107
+ * cost, not optimism: it is published API on a 5.x package, so removing it needs a
108
+ * major; and `Composer` calls it, so it is exercised by that component's tests on
109
+ * every run and cannot rot unnoticed.
110
+ *
111
+ * **It gets no further surface without a real caller.** No extra options, no second
112
+ * hook. An API with one hypothetical consumer is how a package accumulates surface
113
+ * nobody uses.
93
114
  */
94
115
  declare function usePastePills({ threshold, heldPastes: controlledHeldPastes, onHeldPastesChange, }?: UsePastePillsOptions): UsePastePillsResult;
95
116
 
@@ -90,6 +90,27 @@ interface UsePastePillsResult {
90
90
  * still closed carries the text.
91
91
  *
92
92
  * It owns no DOM. The host renders the pills.
93
+ *
94
+ * ---------------------------------------------------------------------------
95
+ * Who actually calls this (as of 5.32.0): `Composer`, and nothing else
96
+ * ---------------------------------------------------------------------------
97
+ *
98
+ * The estate that specified it **withdrew before adopting it**, hours after it
99
+ * shipped — their design moved the pill INTO the message as a `[paste:id|label]`
100
+ * marker in the same grammar as their other object tags, which makes the message
101
+ * itself the record of what is attached. A parallel `heldPastes` array would then be
102
+ * a second place answering "what am I sending?", and the two would disagree the
103
+ * moment someone backspaced a badge. Their reasoning was better than the spec.
104
+ *
105
+ * Recorded because a reader should not infer an extension point under active
106
+ * external use. It is kept rather than withdrawn for two reasons that are about
107
+ * cost, not optimism: it is published API on a 5.x package, so removing it needs a
108
+ * major; and `Composer` calls it, so it is exercised by that component's tests on
109
+ * every run and cannot rot unnoticed.
110
+ *
111
+ * **It gets no further surface without a real caller.** No extra options, no second
112
+ * hook. An API with one hypothetical consumer is how a package accumulates surface
113
+ * nobody uses.
93
114
  */
94
115
  declare function usePastePills({ threshold, heldPastes: controlledHeldPastes, onHeldPastesChange, }?: UsePastePillsOptions): UsePastePillsResult;
95
116