({
behavior = "smooth",
children,
direction = "end",
onClick,
render,
tabIndex,
type = "button",
...props
}: MessageScrollerButtonProps)
| 322 | } |
| 323 | |
| 324 | function MessageScrollerButton({ |
| 325 | behavior = "smooth", |
| 326 | children, |
| 327 | direction = "end", |
| 328 | onClick, |
| 329 | render, |
| 330 | tabIndex, |
| 331 | type = "button", |
| 332 | ...props |
| 333 | }: MessageScrollerButtonProps) { |
| 334 | const { scrollToEnd, scrollToStart, stateStore } = useMessageScrollerContext() |
| 335 | const onClickRef = useLatest(onClick) |
| 336 | const subscribe = React.useCallback( |
| 337 | (listener: () => void) => stateStore.subscribe(listener), |
| 338 | [stateStore] |
| 339 | ) |
| 340 | const getSnapshot = React.useCallback(() => { |
| 341 | const state = stateStore.getSnapshot() |
| 342 | |
| 343 | return direction === "start" ? state.start : state.end |
| 344 | }, [direction, stateStore]) |
| 345 | const isActive = React.useSyncExternalStore( |
| 346 | subscribe, |
| 347 | getSnapshot, |
| 348 | getSnapshot |
| 349 | ) |
| 350 | |
| 351 | const handleClick = React.useCallback( |
| 352 | (event: React.MouseEvent<HTMLButtonElement>) => { |
| 353 | if (!isActive) { |
| 354 | return |
| 355 | } |
| 356 | |
| 357 | onClickRef.current?.(event) |
| 358 | |
| 359 | if (!event.defaultPrevented) { |
| 360 | event.currentTarget.blur() |
| 361 | |
| 362 | if (direction === "start") { |
| 363 | scrollToStart({ behavior }) |
| 364 | } else { |
| 365 | scrollToEnd({ behavior }) |
| 366 | } |
| 367 | } |
| 368 | }, |
| 369 | [behavior, direction, isActive, onClickRef, scrollToEnd, scrollToStart] |
| 370 | ) |
| 371 | |
| 372 | return useRender({ |
| 373 | defaultTagName: "button", |
| 374 | props: mergeProps<"button">( |
| 375 | { |
| 376 | type, |
| 377 | inert: !isActive, |
| 378 | tabIndex: isActive ? tabIndex : -1, |
| 379 | children: children ?? <span>Scroll to {direction}</span>, |
| 380 | onClick: handleClick, |
| 381 | }, |
nothing calls this directly
no test coverage detected