diff --git a/package.json b/package.json index a16b524..b4fc2bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@selenite/commons", - "version": "0.12.1", + "version": "0.12.2", "scripts": { "dev": "npm run wasm && vite dev", "wasm": "wasm-pack build ./selenite-commons-rs --target web", diff --git a/src/lib/actions/scroll.ts b/src/lib/actions/scroll.ts index 4ec7811..f34ff3c 100644 --- a/src/lib/actions/scroll.ts +++ b/src/lib/actions/scroll.ts @@ -1,9 +1,13 @@ +import { clamp, debounce } from 'lodash-es'; import type { Action } from 'svelte/action'; import { tweened } from 'svelte/motion'; import { get } from 'svelte/store'; /** * Adds horizontal scrolling to an element. + * + * This action removes the needs to press ctrl or right to scroll + * horizontally. * @param node - The element to add horizontal scrolling to. * @param params - The duration of the scroll animation. * @returns svelte action @@ -12,22 +16,49 @@ export const horizontalScroll: Action { + let isActionScroll = false; let scroll = tweened(node.scrollLeft, { duration, interpolate: (a, b) => (t) => a + (b - a) * t }); - + let isFirst = true; scroll.subscribe((value) => { + if (isFirst) { + isFirst = false; + return; + } + if (!isActionScroll)return; node.scrollLeft = value; }); + const stopClamingScroll = debounce(() => { + isActionScroll = false; + }, duration, {leading: false, trailing: true}) + const handleWheel = (e: WheelEvent) => { if (e.deltaY === 0) return; - scroll.set(get(scroll) + e.deltaY); + isActionScroll = true; + const firstChildRect = node.firstElementChild?.getBoundingClientRect(); + const lastChildRect = node.lastElementChild?.getBoundingClientRect(); + if (!firstChildRect || !lastChildRect) { + console.warn("Horizontal scroll: No children found"); + return + } + // Ensure offset stays valid + const maxOffset = lastChildRect.width + lastChildRect.x - firstChildRect.x; + scroll.set(clamp(node.scrollLeft + e.deltaY, 0, maxOffset)); e.preventDefault(); + stopClamingScroll(); }; node.addEventListener('wheel', handleWheel, { passive: false }); + + + node.addEventListener('scroll', (e) => { + if (!isActionScroll) { + scroll.set(node.scrollLeft); + } + }) return { destroy() { node.removeEventListener('wheel', handleWheel); @@ -35,11 +66,16 @@ export const horizontalScroll: Action = (node, enabled) => { - if (enabled || enabled === undefined) - node.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' }); -} \ No newline at end of file + const parent = node.parentElement; + if (!parent) return; + + if (!enabled) return; + + const parentRect = parent.getBoundingClientRect() + const nodeRect = node.getBoundingClientRect() + parent.scrollTo({ left: nodeRect.left - parentRect.left, top: nodeRect.top - parentRect.top, behavior: 'smooth' }); +}; diff --git a/src/routes/scroll/+page.svelte b/src/routes/scroll/+page.svelte index 052b5c8..800010f 100644 --- a/src/routes/scroll/+page.svelte +++ b/src/routes/scroll/+page.svelte @@ -1,11 +1,26 @@ -
+
{#each range(100) as i} {i} + {/each} +
+
+ {#each range(100) as i} + {i} + {/each} +
+
+ {#each range(100) as i} + {i} + {/each} +
+
+ {#each range(100) as i} + {i} {/each}
\ No newline at end of file