Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add createScrollTo function for scrolling #672

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/scroll/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ Get an `{ x: number, y: number }` object of element/window scroll position.

_PRs Welcome :)_

- `createScrollTo` - A primitive to support scroll to a target
lidarbtc marked this conversation as resolved.
Show resolved Hide resolved
- `createHashScroll` - A primitive to support scrolling based on a hashtag change

## Changelog
Expand Down
50 changes: 50 additions & 0 deletions packages/scroll/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,53 @@ export function createScrollPosition(
export const useWindowScrollPosition = /*#__PURE__*/ createHydratableSingletonRoot(() =>
createScrollPosition(isServer ? () => undefined : window),
);

export type ScrollToOptions = {
left?: number;
top?: number;
behavior?: ScrollBehavior;
};

/**
* Returns a function to scroll the specified target element or window.
*
* @param target - element/window to scroll. Can be a reactive signal.
* @returns a function that takes scroll options or x and y coordinates to scroll the target.
*
* @example
* // Using with default window target
* const scrollTo = createScrollTo();
* scrollTo({ top: 100, behavior: 'smooth' });
*
* // Using with a specific element
* const [element, setElement] = createSignal(document.getElementById('myElement'));
* const elementScrollTo = createScrollTo(element);
* elementScrollTo({ left: 50, behavior: 'smooth' });
*
* // Using with x and y coordinates
* scrollTo(100, 200);
*/
export function createScrollTo(
target: Accessor<Element | Window | undefined> | Element | Window = window,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default value of window could throw on the server. () => window should work.

) {
return (options: ScrollToOptions | number, y?: number) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is just returning a callback, it could be simplified to this to avoid currying

function scrollTo(target: Accessor<Element | Window | undefined> | Element | Window, options: ScrollToOptions | number, y?: number): void

this way it's clear that the utility is not reactive
functions with create__(source: Accessor<T>) signature usually scream that they are reactive

const currentTarget = typeof target === "function" ? target() : target;

if (!currentTarget || isServer) return;

if (typeof options === "number") {
options = {
left: options,
top: y,
};
}

const { left, top, behavior = "auto" } = options;

if (currentTarget instanceof Window) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats this check for? both branches do the same thing

currentTarget.scrollTo({ left, top, behavior });
} else {
currentTarget.scrollTo({ left, top, behavior });
}
Comment on lines +143 to +156
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume it could be simplified to

currentTarget.scrollTo(typeof options === "number" ? {left: options, top: y} : options)

};
}
Loading