Skip to content

Commit

Permalink
feat: onScroll can return false to prevent scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
bbohlender committed Mar 11, 2024
1 parent 0bc2cf5 commit 95d106f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 31 deletions.
54 changes: 27 additions & 27 deletions docs/getting-started/components-and-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
<Fullscreen flexDirection="column" md={{ flexDirection: 'row' }}>
Expand Down Expand Up @@ -412,23 +412,23 @@ All Components support [all R3F event handlers](https://docs.pmnd.rs/react-three
<details>
<summary>View all event handlers</summary>

| Property | Type |
| -------------------- | -------------------------------------------------------------------------------------------- |
| onWheel | `(event: ThreeEvent<WheelEvent>) => void` |
| onPointerUp | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerOver | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerOut | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerMove | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerLeave | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerEnter | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerDown | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerCancel | `(event: ThreeEvent<PointerEvent>) => void` |
| onDoubleClick | `(event: ThreeEvent<MouseEvent>) => void` |
| onContextMenu | `(event: ThreeEvent<MouseEvent>) => void` |
| onClick | `(event: ThreeEvent<MouseEvent>) => void` |
| onSizeChange | `(width: number, height: number) => void` |
| onIsInViewportChange | `(isInViewport: boolean) => void` |
| onScroll | `(scrollX: number, scrollY: number, event?: ThreeEvent<WheelEvent \| PointerEvent>) => void` |
| Property | Type |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| onWheel | `(event: ThreeEvent<WheelEvent>) => void` |
| onPointerUp | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerOver | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerOut | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerMove | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerLeave | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerEnter | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerDown | `(event: ThreeEvent<PointerEvent>) => void` |
| onPointerCancel | `(event: ThreeEvent<PointerEvent>) => void` |
| onDoubleClick | `(event: ThreeEvent<MouseEvent>) => void` |
| onContextMenu | `(event: ThreeEvent<MouseEvent>) => void` |
| onClick | `(event: ThreeEvent<MouseEvent>) => void` |
| onSizeChange | `(width: number, height: number) => void` |
| onIsInViewportChange | `(isInViewport: boolean) => void` |
| onScroll | `(scrollX: number, scrollY: number, scrollPosition: Signal<Vector2Tuple>, event?: ThreeEvent<WheelEvent \| PointerEvent>) => boolean \| void` |

</details>

Expand Down
4 changes: 4 additions & 0 deletions docs/tutorials/scroll.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ However, it is required to configure three.js to support visual clipping, which
<Canvas gl={{ localClippingEnabled: true }}>
```

## 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.
Expand Down
22 changes: 18 additions & 4 deletions packages/uikit/src/scroll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,20 @@ export type ScrollEventHandlers = Pick<
>

export type ScrollListeners = {
onScroll?: (scrollX: number, scrollY: number, event?: ThreeEvent<WheelEvent | PointerEvent>) => 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<Vector2Tuple>,
event?: ThreeEvent<WheelEvent | PointerEvent>,
) => boolean | void
}

export function useScrollPosition() {
Expand Down Expand Up @@ -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],
)
Expand Down

0 comments on commit 95d106f

Please sign in to comment.