@proteos/ui 0.77.0 → 0.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +991 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +592 -2
- package/dist/index.d.ts +592 -2
- package/dist/index.js +969 -9
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/components/data-table/data-table.scroll-restore.test.tsx +97 -0
- package/src/components/data-table/data-table.test.tsx +22 -2
- package/src/components/data-table/data-table.tsx +31 -1
- package/src/components/frame-strip/frame-strip.stories.tsx +61 -0
- package/src/components/frame-strip/frame-strip.test.tsx +112 -0
- package/src/components/frame-strip/frame-strip.tsx +131 -0
- package/src/components/frame-strip/index.ts +2 -0
- package/src/components/media-player/index.ts +22 -0
- package/src/components/media-player/media-controls.tsx +145 -0
- package/src/components/media-player/media-markers.tsx +108 -0
- package/src/components/media-player/media-peaks.test.ts +68 -0
- package/src/components/media-player/media-peaks.ts +78 -0
- package/src/components/media-player/media-player.stories.tsx +243 -0
- package/src/components/media-player/media-player.test.tsx +318 -0
- package/src/components/media-player/media-player.tsx +334 -0
- package/src/components/media-player/media-time.ts +27 -0
- package/src/components/media-player/media-timeline.test.tsx +133 -0
- package/src/components/media-player/media-timeline.tsx +78 -0
- package/src/components/media-player/media-video-stage.tsx +113 -0
- package/src/components/media-player/media-waveform.tsx +330 -0
- package/src/components/slider/index.ts +2 -0
- package/src/components/slider/slider.stories.tsx +32 -0
- package/src/components/slider/slider.test.tsx +35 -0
- package/src/components/slider/slider.tsx +89 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from '@testing-library/react'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { Slider } from './slider'
|
|
5
|
+
|
|
6
|
+
describe('Slider', () => {
|
|
7
|
+
it('exposes its name and value', () => {
|
|
8
|
+
render(<Slider aria-label="Volume" value={30} maxValue={100} />)
|
|
9
|
+
const slider = screen.getByRole('slider', { name: 'Volume' })
|
|
10
|
+
expect(slider).toHaveValue('30')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('announces valueText instead of the number', () => {
|
|
14
|
+
render(<Slider aria-label="Seek" value={48} maxValue={156} valueText="48 seconds" />)
|
|
15
|
+
expect(screen.getByRole('slider')).toHaveAttribute('aria-valuetext', '48 seconds')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('keeps valueText current when the value changes', () => {
|
|
19
|
+
const { rerender } = render(<Slider aria-label="Seek" value={1} maxValue={9} valueText="one" />)
|
|
20
|
+
rerender(<Slider aria-label="Seek" value={2} maxValue={9} valueText="two" />)
|
|
21
|
+
expect(screen.getByRole('slider')).toHaveAttribute('aria-valuetext', 'two')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('reports changes', () => {
|
|
25
|
+
const onChange = vi.fn()
|
|
26
|
+
render(<Slider aria-label="Seek" value={10} maxValue={100} onChange={onChange} />)
|
|
27
|
+
fireEvent.change(screen.getByRole('slider'), { target: { value: '40' } })
|
|
28
|
+
expect(onChange).toHaveBeenCalledWith(40)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('disables its input', () => {
|
|
32
|
+
render(<Slider aria-label="Seek" value={0} maxValue={100} isDisabled />)
|
|
33
|
+
expect(screen.getByRole('slider')).toBeDisabled()
|
|
34
|
+
})
|
|
35
|
+
})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Slider as AriaSlider,
|
|
4
|
+
type SliderProps as AriaSliderProps,
|
|
5
|
+
SliderThumb,
|
|
6
|
+
SliderTrack,
|
|
7
|
+
} from 'react-aria-components'
|
|
8
|
+
import { tv, type VariantProps } from 'tailwind-variants'
|
|
9
|
+
|
|
10
|
+
import { cn } from '../../lib/cn'
|
|
11
|
+
|
|
12
|
+
/* =========================================================================
|
|
13
|
+
Slider — a single-thumb numeric range on RAC Slider. Thin rail, ink fill,
|
|
14
|
+
small ink thumb; the 18px track is the pointer target around the 4px rail.
|
|
15
|
+
`valueText` replaces the announced number when the raw value means little
|
|
16
|
+
on its own (a media position reads "48 seconds of 2 minutes").
|
|
17
|
+
========================================================================= */
|
|
18
|
+
|
|
19
|
+
export const sliderStyles = tv({
|
|
20
|
+
slots: {
|
|
21
|
+
root: 'flex w-full items-center',
|
|
22
|
+
track: 'group relative h-[18px] w-full cursor-pointer data-[disabled]:cursor-default',
|
|
23
|
+
rail: 'absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 overflow-hidden rounded-pill bg-surface-3',
|
|
24
|
+
fill: 'h-full bg-ink',
|
|
25
|
+
thumb: [
|
|
26
|
+
'top-1/2 size-3 rounded-pill bg-ink',
|
|
27
|
+
'shadow-[var(--shadow-rest)]',
|
|
28
|
+
'data-[focus-visible]:shadow-[var(--shadow-focus)]',
|
|
29
|
+
'data-[disabled]:hidden',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
export type SliderVariants = VariantProps<typeof sliderStyles>
|
|
35
|
+
|
|
36
|
+
export type SliderProps = Omit<
|
|
37
|
+
AriaSliderProps<number>,
|
|
38
|
+
'children' | 'value' | 'defaultValue' | 'onChange' | 'onChangeEnd' | 'orientation'
|
|
39
|
+
> & {
|
|
40
|
+
value: number
|
|
41
|
+
onChange?: (value: number) => void
|
|
42
|
+
onChangeEnd?: (value: number) => void
|
|
43
|
+
/** Spoken in place of the number. */
|
|
44
|
+
valueText?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function Slider({
|
|
48
|
+
value,
|
|
49
|
+
onChange,
|
|
50
|
+
onChangeEnd,
|
|
51
|
+
valueText,
|
|
52
|
+
className,
|
|
53
|
+
...props
|
|
54
|
+
}: SliderProps) {
|
|
55
|
+
const styles = sliderStyles()
|
|
56
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
57
|
+
|
|
58
|
+
// RAC writes its formatted number onto the thumb's input on every render and
|
|
59
|
+
// offers no override, so ours has to land after it.
|
|
60
|
+
useLayoutEffect(() => {
|
|
61
|
+
if (valueText !== undefined) inputRef.current?.setAttribute('aria-valuetext', valueText)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<AriaSlider
|
|
66
|
+
{...props}
|
|
67
|
+
value={value}
|
|
68
|
+
{...(onChange ? { onChange } : {})}
|
|
69
|
+
{...(onChangeEnd ? { onChangeEnd } : {})}
|
|
70
|
+
className={(renderProps) =>
|
|
71
|
+
cn(styles.root(), typeof className === 'function' ? className(renderProps) : className)
|
|
72
|
+
}
|
|
73
|
+
>
|
|
74
|
+
<SliderTrack className={styles.track()}>
|
|
75
|
+
{({ state }) => (
|
|
76
|
+
<>
|
|
77
|
+
<div className={styles.rail()}>
|
|
78
|
+
<div
|
|
79
|
+
className={styles.fill()}
|
|
80
|
+
style={{ width: `${state.getThumbPercent(0) * 100}%` }}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
<SliderThumb inputRef={inputRef} className={styles.thumb()} />
|
|
84
|
+
</>
|
|
85
|
+
)}
|
|
86
|
+
</SliderTrack>
|
|
87
|
+
</AriaSlider>
|
|
88
|
+
)
|
|
89
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -26,12 +26,14 @@ export * from './components/error-animation'
|
|
|
26
26
|
export * from './components/field'
|
|
27
27
|
export * from './components/file-field'
|
|
28
28
|
export * from './components/file-viewer'
|
|
29
|
+
export * from './components/frame-strip'
|
|
29
30
|
export * from './components/glow-frame'
|
|
30
31
|
export * from './components/icon-picker'
|
|
31
32
|
export * from './components/image-attachment'
|
|
32
33
|
export * from './components/image-lightbox'
|
|
33
34
|
export * from './components/input'
|
|
34
35
|
export * from './components/kbd'
|
|
36
|
+
export * from './components/media-player'
|
|
35
37
|
export * from './components/menu'
|
|
36
38
|
export * from './components/message-composer'
|
|
37
39
|
export * from './components/modal'
|
|
@@ -49,6 +51,7 @@ export * from './components/segmented-control'
|
|
|
49
51
|
export * from './components/select'
|
|
50
52
|
export * from './components/separator'
|
|
51
53
|
export * from './components/skeleton'
|
|
54
|
+
export * from './components/slider'
|
|
52
55
|
export * from './components/stepper'
|
|
53
56
|
export * from './components/success-animation'
|
|
54
57
|
export * from './components/switch'
|