Skip to content

Commit

Permalink
fix(slider): focus and focus-styles management
Browse files Browse the repository at this point in the history
  • Loading branch information
soykje committed Nov 10, 2023
1 parent a8937b0 commit 50a47e3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
28 changes: 28 additions & 0 deletions packages/components/slider/src/Slider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ describe('Slider', () => {
* cf. https://github.com/radix-ui/primitives/blob/28bebf2c6992d056244845c898abeff45dec2871/packages/react/slider/src/Slider.tsx#L9C10-L9C17
*/
mockResizeObserver()

Object.defineProperty(HTMLSpanElement.prototype, 'setPointerCapture', {
value: vi.fn(),
})
})

beforeEach(() => vi.clearAllMocks())
Expand Down Expand Up @@ -87,4 +91,28 @@ describe('Slider', () => {
*/
expect(commit).toHaveBeenCalledWith([32])
})

it('should set data attribute based on event type', async () => {
const user = userEvent.setup()

render(
<form>
<Slider name="form-slider" defaultValue={[25]}>
<Slider.Track />
<Slider.Thumb />
</Slider>
</form>
)

const thumb = screen.getByRole('slider')

await user.pointer({ keys: '[TouchA>]', target: thumb })
expect(thumb).toHaveAttribute('data-interaction', 'pointerdown')

await user.keyboard('{ArrowRight>}')
expect(thumb).toHaveAttribute('data-interaction', 'keydown')

thumb.blur()
expect(thumb).toHaveAttribute('data-interaction', 'blur')
})
})
1 change: 1 addition & 0 deletions packages/components/slider/src/SliderThumb.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const thumbVariants = cva(
'hover:ring-4 u-shadow-border-transition',
'outline-none',
'focus-visible:u-ring',
'data-[interaction=pointerdown]:focus-visible:!ring-0',
'spark-disabled:hover:ring-0 spark-disabled:cursor-not-allowed',
],
{
Expand Down
31 changes: 28 additions & 3 deletions packages/components/slider/src/SliderThumb.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as RadixSlider from '@radix-ui/react-slider'
import { forwardRef } from 'react'
import { type FocusEvent, forwardRef, type KeyboardEvent, type PointerEvent, useRef } from 'react'

import { useSliderContext } from './SliderContext'
import { thumbVariants } from './SliderThumb.styles'
Expand All @@ -12,14 +12,39 @@ export interface SliderThumbProps extends RadixSlider.SliderThumbProps {
asChild?: boolean
}

export const SliderThumb = forwardRef<HTMLDivElement, SliderThumbProps>(
({ asChild = false, className, ...rest }, ref) => {
export const SliderThumb = forwardRef<HTMLSpanElement, SliderThumbProps>(
({ asChild = false, className, onPointerDown, onKeyDown, onBlur, ...rest }, forwardedRef) => {
const { intent } = useSliderContext()

const innerRef = useRef(null)
const ref = forwardedRef || innerRef

const setInteractionType = (e: KeyboardEvent | FocusEvent | PointerEvent) => {
/**
* Radix Slider implementation uses `.focus()` and thus prevent us to handle
* distinctively focus/focus-visible styles. So we use a `data-interaction` attribute to stay
* aware of the type of event, and adapt styles if needed.
*/
if (typeof ref === 'function' || !ref.current) return
ref.current.dataset.interaction = e.type
}

return (
<RadixSlider.Thumb
ref={ref}
asChild={asChild}
onPointerDown={(e: PointerEvent<HTMLSpanElement>) => {
setInteractionType(e)
onPointerDown?.(e)
}}
onKeyDown={(e: KeyboardEvent<HTMLSpanElement>) => {
setInteractionType(e)
onKeyDown?.(e)
}}
onBlur={(e: FocusEvent<HTMLSpanElement>) => {
setInteractionType(e)
onBlur?.(e)
}}
className={thumbVariants({ intent, className })}
{...rest}
/>
Expand Down

0 comments on commit 50a47e3

Please sign in to comment.