@data-fair/lib-vue 1.28.0 → 1.28.1

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.
@@ -7,15 +7,23 @@ import { type MaybeRefOrGetter } from 'vue';
7
7
  * `target` is what actually scrolls — pass `window` (or the current document's
8
8
  * scroller) for a page that scrolls as a whole, or a getter returning the inner
9
9
  * scrollable element when the growing region lives inside an `overflow: auto`
10
- * container. VueUse's `arrivedState.bottom` carries a built-in 1px tolerance,
11
- * and appending content fires no scroll event, so following only ever turns off
12
- * on a real upward scroll no manual threshold needed.
10
+ * container.
11
+ *
12
+ * Following is driven by the bottom being in view (`arrivedState.bottom`), not
13
+ * by scroll direction: when the content shrinks (a loader removed, a panel
14
+ * collapsed) the browser clamps scrollTop upward, and a direction-based check
15
+ * would mistake that for the user scrolling away and stop following for good.
16
+ *
17
+ * "In view" allows a small margin (`bottomThreshold`): exact scrollTop rarely
18
+ * reaches the very bottom (sub-pixel rounding) and live content keeps appending,
19
+ * so a 0px check could never re-arm following once the user had scrolled away.
13
20
  *
14
21
  * @param target the scroll container: `window`, an element, or a ref/getter to
15
22
  * one (tolerates `null`/`undefined` while the element is not yet mounted)
16
23
  * @param growthSignal reactive getter for the content length (the growth signal)
17
24
  * @param isActive getter telling whether the source is still streaming/growing
25
+ * @param bottomThreshold px from the bottom still counted as "at the bottom"
18
26
  */
19
- export declare const useAutoScrollBottom: (target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>, growthSignal: () => number, isActive: () => boolean) => {
27
+ export declare const useAutoScrollBottom: (target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>, growthSignal: () => number, isActive: () => boolean, bottomThreshold?: number) => {
20
28
  following: import("vue").Ref<boolean, boolean>;
21
29
  };
@@ -8,26 +8,30 @@ import { useScroll, useEventListener } from '@vueuse/core';
8
8
  * `target` is what actually scrolls — pass `window` (or the current document's
9
9
  * scroller) for a page that scrolls as a whole, or a getter returning the inner
10
10
  * scrollable element when the growing region lives inside an `overflow: auto`
11
- * container. VueUse's `arrivedState.bottom` carries a built-in 1px tolerance,
12
- * and appending content fires no scroll event, so following only ever turns off
13
- * on a real upward scroll no manual threshold needed.
11
+ * container.
12
+ *
13
+ * Following is driven by the bottom being in view (`arrivedState.bottom`), not
14
+ * by scroll direction: when the content shrinks (a loader removed, a panel
15
+ * collapsed) the browser clamps scrollTop upward, and a direction-based check
16
+ * would mistake that for the user scrolling away and stop following for good.
17
+ *
18
+ * "In view" allows a small margin (`bottomThreshold`): exact scrollTop rarely
19
+ * reaches the very bottom (sub-pixel rounding) and live content keeps appending,
20
+ * so a 0px check could never re-arm following once the user had scrolled away.
14
21
  *
15
22
  * @param target the scroll container: `window`, an element, or a ref/getter to
16
23
  * one (tolerates `null`/`undefined` while the element is not yet mounted)
17
24
  * @param growthSignal reactive getter for the content length (the growth signal)
18
25
  * @param isActive getter telling whether the source is still streaming/growing
26
+ * @param bottomThreshold px from the bottom still counted as "at the bottom"
19
27
  */
20
- export const useAutoScrollBottom = (target, growthSignal, isActive) => {
28
+ export const useAutoScrollBottom = (target, growthSignal, isActive, bottomThreshold = 48) => {
21
29
  // Start following so a freshly opened, still-growing source pins to its tail
22
30
  // even though it usually mounts scrolled to the top.
23
31
  const following = ref(true);
24
- const { arrivedState, directions, y } = useScroll(target, {
25
- onScroll: () => {
26
- if (directions.top)
27
- following.value = false; // scrolled up → stop
28
- else if (arrivedState.bottom)
29
- following.value = true; // back at bottom → resume
30
- }
32
+ const { arrivedState, y } = useScroll(target, {
33
+ offset: { bottom: bottomThreshold },
34
+ onScroll: () => { following.value = arrivedState.bottom; } // near bottom → follow, else stop
31
35
  });
32
36
  // A wheel-up reaches us even when the target can't scroll (short content, or
33
37
  // an auto-height embed where a parent scrolls) — the only "stop following"
@@ -1 +1 @@
1
- {"version":3,"file":"auto-scroll-bottom.js","sourceRoot":"","sources":["auto-scroll-bottom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAyB,MAAM,KAAK,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAiE,EACjE,YAA0B,EAC1B,QAAuB,EACvB,EAAE;IACF,6EAA6E;IAC7E,qDAAqD;IACrD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAE3B,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE;QACxD,QAAQ,EAAE,GAAG,EAAE;YACb,IAAI,UAAU,CAAC,GAAG;gBAAE,SAAS,CAAC,KAAK,GAAG,KAAK,CAAA,CAAC,qBAAqB;iBAC5D,IAAI,YAAY,CAAC,MAAM;gBAAE,SAAS,CAAC,KAAK,GAAG,IAAI,CAAA,CAAC,0BAA0B;QACjF,CAAC;KACF,CAAC,CAAA;IAEF,6EAA6E;IAC7E,2EAA2E;IAC3E,0BAA0B;IAC1B,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAa,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,SAAS,CAAC,KAAK,GAAG,KAAK,CAAA,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAEtH,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,0EAA0E;QAC1E,kEAAkE;QAClE,CAAC,CAAC,KAAK,GAAG,EAAE,YAAY,MAAM;YAC5B,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,YAAY;YACtE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAA;IACrB,CAAC,CAAA;IAED,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI,QAAQ,EAAE,IAAI,SAAS,CAAC,KAAK;QAAE,WAAW,EAAE,CAAA,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IAElG,OAAO,EAAE,SAAS,EAAE,CAAA;AACtB,CAAC,CAAA","sourcesContent":["import { ref, watch, toValue, type MaybeRefOrGetter } from 'vue'\nimport { useScroll, useEventListener } from '@vueuse/core'\n\n/**\n * Stick-to-bottom autoscroll for a growing, live region (a run log, a chat\n * transcript, ...): follows new content while the user is at the bottom, any\n * upward scroll or wheel-up stops it, scrolling back to the bottom resumes.\n *\n * `target` is what actually scrolls — pass `window` (or the current document's\n * scroller) for a page that scrolls as a whole, or a getter returning the inner\n * scrollable element when the growing region lives inside an `overflow: auto`\n * container. VueUse's `arrivedState.bottom` carries a built-in 1px tolerance,\n * and appending content fires no scroll event, so following only ever turns off\n * on a real upward scroll no manual threshold needed.\n *\n * @param target the scroll container: `window`, an element, or a ref/getter to\n * one (tolerates `null`/`undefined` while the element is not yet mounted)\n * @param growthSignal reactive getter for the content length (the growth signal)\n * @param isActive getter telling whether the source is still streaming/growing\n */\nexport const useAutoScrollBottom = (\n target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>,\n growthSignal: () => number,\n isActive: () => boolean\n) => {\n // Start following so a freshly opened, still-growing source pins to its tail\n // even though it usually mounts scrolled to the top.\n const following = ref(true)\n\n const { arrivedState, directions, y } = useScroll(target, {\n onScroll: () => {\n if (directions.top) following.value = false // scrolled up → stop\n else if (arrivedState.bottom) following.value = true // back at bottom → resume\n }\n })\n\n // A wheel-up reaches us even when the target can't scroll (short content, or\n // an auto-height embed where a parent scrolls) — the only \"stop following\"\n // signal available there.\n useEventListener(target, 'wheel', (e: WheelEvent) => { if (e.deltaY < 0) following.value = false }, { passive: true })\n\n const pinToBottom = () => {\n const el = toValue(target)\n if (!el) return\n // For an element, `y` sets its scrollTop; for the window we scroll to the\n // document's full height (window has no scrollHeight of its own).\n y.value = el instanceof Window\n ? (document.scrollingElement ?? document.documentElement).scrollHeight\n : el.scrollHeight\n }\n\n watch(growthSignal, () => { if (isActive() && following.value) pinToBottom() }, { flush: 'post' })\n\n return { following }\n}\n"]}
1
+ {"version":3,"file":"auto-scroll-bottom.js","sourceRoot":"","sources":["auto-scroll-bottom.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAyB,MAAM,KAAK,CAAA;AAChE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAiE,EACjE,YAA0B,EAC1B,QAAuB,EACvB,eAAe,GAAG,EAAE,EACpB,EAAE;IACF,6EAA6E;IAC7E,qDAAqD;IACrD,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAE3B,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE;QAC5C,MAAM,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE;QACnC,QAAQ,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,KAAK,GAAG,YAAY,CAAC,MAAM,CAAA,CAAC,CAAC,CAAC,kCAAkC;KAC7F,CAAC,CAAA;IAEF,6EAA6E;IAC7E,2EAA2E;IAC3E,0BAA0B;IAC1B,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAa,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,SAAS,CAAC,KAAK,GAAG,KAAK,CAAA,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAEtH,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;QAC1B,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,0EAA0E;QAC1E,kEAAkE;QAClE,CAAC,CAAC,KAAK,GAAG,EAAE,YAAY,MAAM;YAC5B,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC,YAAY;YACtE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAA;IACrB,CAAC,CAAA;IAED,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI,QAAQ,EAAE,IAAI,SAAS,CAAC,KAAK;QAAE,WAAW,EAAE,CAAA,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IAElG,OAAO,EAAE,SAAS,EAAE,CAAA;AACtB,CAAC,CAAA","sourcesContent":["import { ref, watch, toValue, type MaybeRefOrGetter } from 'vue'\nimport { useScroll, useEventListener } from '@vueuse/core'\n\n/**\n * Stick-to-bottom autoscroll for a growing, live region (a run log, a chat\n * transcript, ...): follows new content while the user is at the bottom, any\n * upward scroll or wheel-up stops it, scrolling back to the bottom resumes.\n *\n * `target` is what actually scrolls — pass `window` (or the current document's\n * scroller) for a page that scrolls as a whole, or a getter returning the inner\n * scrollable element when the growing region lives inside an `overflow: auto`\n * container.\n *\n * Following is driven by the bottom being in view (`arrivedState.bottom`), not\n * by scroll direction: when the content shrinks (a loader removed, a panel\n * collapsed) the browser clamps scrollTop upward, and a direction-based check\n * would mistake that for the user scrolling away and stop following for good.\n *\n * \"In view\" allows a small margin (`bottomThreshold`): exact scrollTop rarely\n * reaches the very bottom (sub-pixel rounding) and live content keeps appending,\n * so a 0px check could never re-arm following once the user had scrolled away.\n *\n * @param target the scroll container: `window`, an element, or a ref/getter to\n * one (tolerates `null`/`undefined` while the element is not yet mounted)\n * @param growthSignal reactive getter for the content length (the growth signal)\n * @param isActive getter telling whether the source is still streaming/growing\n * @param bottomThreshold px from the bottom still counted as \"at the bottom\"\n */\nexport const useAutoScrollBottom = (\n target: MaybeRefOrGetter<HTMLElement | Window | null | undefined>,\n growthSignal: () => number,\n isActive: () => boolean,\n bottomThreshold = 48\n) => {\n // Start following so a freshly opened, still-growing source pins to its tail\n // even though it usually mounts scrolled to the top.\n const following = ref(true)\n\n const { arrivedState, y } = useScroll(target, {\n offset: { bottom: bottomThreshold },\n onScroll: () => { following.value = arrivedState.bottom } // near bottom → follow, else stop\n })\n\n // A wheel-up reaches us even when the target can't scroll (short content, or\n // an auto-height embed where a parent scrolls) — the only \"stop following\"\n // signal available there.\n useEventListener(target, 'wheel', (e: WheelEvent) => { if (e.deltaY < 0) following.value = false }, { passive: true })\n\n const pinToBottom = () => {\n const el = toValue(target)\n if (!el) return\n // For an element, `y` sets its scrollTop; for the window we scroll to the\n // document's full height (window has no scrollHeight of its own).\n y.value = el instanceof Window\n ? (document.scrollingElement ?? document.documentElement).scrollHeight\n : el.scrollHeight\n }\n\n watch(growthSignal, () => { if (isActive() && following.value) pinToBottom() }, { flush: 'post' })\n\n return { following }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@data-fair/lib-vue",
3
- "version": "1.28.0",
3
+ "version": "1.28.1",
4
4
  "description": "Composables and other utilities for Vue applications in the data-fair stack.",
5
5
  "main": "index.js",
6
6
  "files": [