From 95d106f610bef445ab7e855fb402dcbde992108e Mon Sep 17 00:00:00 2001 From: Bela Bohlender Date: Mon, 11 Mar 2024 15:34:48 +0100 Subject: [PATCH] feat: onScroll can return false to prevent scrolling --- .../components-and-properties.md | 54 +++++++++---------- docs/tutorials/scroll.md | 4 ++ packages/uikit/src/scroll.tsx | 22 ++++++-- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/docs/getting-started/components-and-properties.md b/docs/getting-started/components-and-properties.md index 5aec8618..289f59d2 100644 --- a/docs/getting-started/components-and-properties.md +++ b/docs/getting-started/components-and-properties.md @@ -368,16 +368,16 @@ The `FontFamilyProvider` component allows you to use the specified font families uikit allows you to declare properties that depend on the element's interaction state, similar to CSS selectors, such as `:hover`. Conditional properties also enable elements in the layout to be responsive based on several breakpoints. uikit supports a range of conditional properties: -| Name | Explanation | -| -------- | ------------------------------------------------------ | -| hover | when the user hovers over the element | -| active | when the users clicks (pointer down) on the element | -| sm | when the width of the root element is bigger than 640 | -| md | when the width of the root element is bigger than 768 | -| lg | when the width of the root element is bigger than 1024 | -| xl | when the width of the root element is bigger than 1280 | -| 2xl | when the width of the root element is bigger than 1536 | -| dark | when the preferred color scheme is dark | +| Name | Explanation | +| ------ | ------------------------------------------------------ | +| hover | when the user hovers over the element | +| active | when the users clicks (pointer down) on the element | +| sm | when the width of the root element is bigger than 640 | +| md | when the width of the root element is bigger than 768 | +| lg | when the width of the root element is bigger than 1024 | +| xl | when the width of the root element is bigger than 1280 | +| 2xl | when the width of the root element is bigger than 1536 | +| dark | when the preferred color scheme is dark | ```jsx @@ -412,23 +412,23 @@ All Components support [all R3F event handlers](https://docs.pmnd.rs/react-three
View all event handlers -| Property | Type | -| -------------------- | -------------------------------------------------------------------------------------------- | -| onWheel | `(event: ThreeEvent) => void` | -| onPointerUp | `(event: ThreeEvent) => void` | -| onPointerOver | `(event: ThreeEvent) => void` | -| onPointerOut | `(event: ThreeEvent) => void` | -| onPointerMove | `(event: ThreeEvent) => void` | -| onPointerLeave | `(event: ThreeEvent) => void` | -| onPointerEnter | `(event: ThreeEvent) => void` | -| onPointerDown | `(event: ThreeEvent) => void` | -| onPointerCancel | `(event: ThreeEvent) => void` | -| onDoubleClick | `(event: ThreeEvent) => void` | -| onContextMenu | `(event: ThreeEvent) => void` | -| onClick | `(event: ThreeEvent) => void` | -| onSizeChange | `(width: number, height: number) => void` | -| onIsInViewportChange | `(isInViewport: boolean) => void` | -| onScroll | `(scrollX: number, scrollY: number, event?: ThreeEvent) => void` | +| Property | Type | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| onWheel | `(event: ThreeEvent) => void` | +| onPointerUp | `(event: ThreeEvent) => void` | +| onPointerOver | `(event: ThreeEvent) => void` | +| onPointerOut | `(event: ThreeEvent) => void` | +| onPointerMove | `(event: ThreeEvent) => void` | +| onPointerLeave | `(event: ThreeEvent) => void` | +| onPointerEnter | `(event: ThreeEvent) => void` | +| onPointerDown | `(event: ThreeEvent) => void` | +| onPointerCancel | `(event: ThreeEvent) => void` | +| onDoubleClick | `(event: ThreeEvent) => void` | +| onContextMenu | `(event: ThreeEvent) => void` | +| onClick | `(event: ThreeEvent) => void` | +| onSizeChange | `(width: number, height: number) => void` | +| onIsInViewportChange | `(isInViewport: boolean) => void` | +| onScroll | `(scrollX: number, scrollY: number, scrollPosition: Signal, event?: ThreeEvent) => boolean \| void` |
diff --git a/docs/tutorials/scroll.md b/docs/tutorials/scroll.md index 40611e97..63054577 100644 --- a/docs/tutorials/scroll.md +++ b/docs/tutorials/scroll.md @@ -12,6 +12,10 @@ However, it is required to configure three.js to support visual clipping, which ``` +## onScroll + +If a `Container` component uses `overflow="scroll"`, the `onScroll` event is called when the user scrolls through their scroll wheel or touching. `onScroll` receives the new `x` and `y` coordinates for the scroll position, the signal containing the current `scrollPosition`, and the optional event that caused the scrolling. The listener passed to `onScroll` can return `false` to prevent setting the new `x` and `y` scroll position. + ## Scrollbars uikit renders scrollbars if the content overflows an element that has the property `overflow="scroll"`. The scrollbar can be styled similarly to the background panel of any component via the following properties. diff --git a/packages/uikit/src/scroll.tsx b/packages/uikit/src/scroll.tsx index 7f6846a6..91c5834c 100644 --- a/packages/uikit/src/scroll.tsx +++ b/packages/uikit/src/scroll.tsx @@ -28,7 +28,20 @@ export type ScrollEventHandlers = Pick< > export type ScrollListeners = { - onScroll?: (scrollX: number, scrollY: number, event?: ThreeEvent) => void + /** + * scroll listener called right before the new scroll position is set when a scroll event is caused + * @param scrollX the new scroll x position + * @param scrollY the new scroll y position + * @param scrollPosition the current/old scroll position + * @param event the event that caused the scrolling + * @returns false to prevent the new scroll x and scroll y position from beeing applied + */ + onScroll?: ( + scrollX: number, + scrollY: number, + scrollPosition: Signal, + event?: ThreeEvent, + ) => boolean | void } export function useScrollPosition() { @@ -131,10 +144,11 @@ export function ScrollHandler({ wasScrolledY || Math.min(y, (maxY ?? 0) - y) > 5, ) } - if (x != newX || y != newY) { - scrollPosition.value = [newX, newY] - onScrollRef.current?.(...scrollPosition.value, event) + const preventScroll = onScrollRef.current?.(newX, newY, scrollPosition, event) + if (preventScroll === false || (x === newX && y === newY)) { + return } + scrollPosition.value = [newX, newY] }, [node, scrollPosition, scrollVelocity], )