Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,14 @@ function MyPicker() {

the main Picker container component.

| Prop | Default | Description |
| :---- | :------- | :----------- |
| value | N/A | `{ [name: string]: string }`<br />Selected value pairs |
| onChange | N/A | `(value: T, key: string) => void`<br />Callback function when the selected value changes |
| height | 216 | `number`<br />Height of the picker in `px` |
| itemHeight | 36 | `number`<br />Height of each item (that is each option) in `px` |
| wheelMode | `'off'` | `'off' \| 'natural' \| 'normal'`<br />Enable wheel scrolling on desktop browsers |
| Prop | Default | Description |
|:-----------|:----------|:-----------------------------------------------------------------------------------------|
| value | N/A | `{ [name: string]: string }`<br />Selected value pairs |
| onChange | N/A | `(value: T, key: string) => void`<br />Callback function when the selected value changes |
| height | 216 | `number`<br />Height of the picker in `px` |
| itemHeight | 36 | `number`<br />Height of each item (that is each option) in `px` |
| wheelMode | `'off'` | `'off' \| 'natural' \| 'normal'`<br />Enable wheel scrolling on desktop browsers |
| mouseMode | `'click'` | `'click' \| 'drag'`<br />How to select an item with a mouse — by click or drag. |

### Picker.Column

Expand Down
1 change: 1 addition & 0 deletions examples/containers/InlinePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default function InlinePicker() {
value={pickerValue}
onChange={setPickerValue}
wheelMode="natural"
mouseMode="drag"
>
<Picker.Column name="title">
{renderOptions(['Mr.', 'Mrs.', 'Ms.', 'Dr.'], 'text-red-600')}
Expand Down
8 changes: 6 additions & 2 deletions lib/components/Picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CSSProperties, HTMLProps, MutableRefObject, createContext, useCallback,
const DEFAULT_HEIGHT = 216
const DEFAULT_ITEM_HEIGHT = 36
const DEFAULT_WHEEL_MODE = 'off'
const DEFAULT_MOUSE_MODE = 'click'

interface Option {
value: string | number
Expand All @@ -19,12 +20,14 @@ export interface PickerRootProps<TType extends PickerValue> extends Omit<HTMLPro
height?: number
itemHeight?: number
wheelMode?: 'off' | 'natural' | 'normal'
mouseMode?: 'drag' | 'click'
}

const PickerDataContext = createContext<{
height: number
itemHeight: number
wheelMode: 'off' | 'natural' | 'normal'
mouseMode: 'drag' | 'click'
value: PickerValue
optionGroups: { [key: string]: Option[] }
} | null>(null)
Expand Down Expand Up @@ -118,6 +121,7 @@ function PickerRoot<TType extends PickerValue>(props: PickerRootProps<TType>) {
height = DEFAULT_HEIGHT,
itemHeight = DEFAULT_ITEM_HEIGHT,
wheelMode = DEFAULT_WHEEL_MODE,
mouseMode= DEFAULT_MOUSE_MODE,
...restProps
} = props

Expand Down Expand Up @@ -149,8 +153,8 @@ function PickerRoot<TType extends PickerValue>(props: PickerRootProps<TType>) {
const [optionGroups, dispatch] = useReducer(pickerReducer, {})

const pickerData = useMemo(
() => ({ height, itemHeight, wheelMode, value, optionGroups }),
[height, itemHeight, value, optionGroups, wheelMode]
() => ({ height, itemHeight, wheelMode, value, optionGroups, mouseMode }),
[height, itemHeight, value, optionGroups, wheelMode, mouseMode]
)

const triggerChange = useCallback((key: string, nextValue: string) => {
Expand Down
23 changes: 22 additions & 1 deletion lib/components/PickerColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function PickerColumn({
name: key,
...restProps
}: PickerColumnProps) {
const { height, itemHeight, wheelMode, value: groupValue, optionGroups } = usePickerData('Picker.Column')
const { height, itemHeight, wheelMode, value: groupValue, optionGroups, mouseMode } = usePickerData('Picker.Column')

// Caculate the selected index
const value = useMemo(
Expand Down Expand Up @@ -104,6 +104,21 @@ function PickerColumn({
setStartScrollerTranslate(scrollerTranslate)
}, [scrollerTranslate])

const handleMouseStart = useCallback((event: React.MouseEvent) => {
if (mouseMode === 'click') return

setIsMoving(true)
setStartTouchY(event.pageY)
setStartScrollerTranslate(scrollerTranslate)
}, [scrollerTranslate])

const handleMouseMove = useCallback((event: MouseEvent) => {
if (event.cancelable) event.preventDefault()
if (!isMoving || mouseMode === 'click') return

updateScrollerWhileMoving(startScrollerTranslate + event.pageY - startTouchY)
}, [isMoving, startScrollerTranslate, startTouchY, updateScrollerWhileMoving])

const handleTouchMove = useCallback((event: TouchEvent) => {
if (event.cancelable) {
event.preventDefault()
Expand Down Expand Up @@ -188,11 +203,13 @@ function PickerColumn({
if (container) {
container.addEventListener('touchmove', handleTouchMove, { passive: false })
container.addEventListener('wheel', handleWheel, { passive: false })
container.addEventListener('mousemove', handleMouseMove, { passive: false })
}
return () => {
if (container) {
container.removeEventListener('touchmove', handleTouchMove)
container.removeEventListener('wheel', handleWheel)
container.removeEventListener('mousemove', handleMouseMove)
}
}
}, [handleTouchMove, handleWheel])
Expand All @@ -205,6 +222,7 @@ function PickerColumn({
transitionTimingFunction: 'cubic-bezier(0, 0, 0.2, 1)',
transitionDuration: isMoving ? '0ms' : '300ms',
transform: `translate3d(0, ${scrollerTranslate}px, 0)`,
...(mouseMode === 'drag' && { cursor: 'grab', userSelect: 'none' }),
}),
[scrollerTranslate, isMoving],
)
Expand All @@ -221,6 +239,9 @@ function PickerColumn({
...style,
}}
ref={containerRef}
onMouseDown={handleMouseStart}
onMouseUp={handleTouchEnd}
onMouseLeave={handleTouchCancel}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
onTouchCancel={handleTouchCancel}
Expand Down
3 changes: 2 additions & 1 deletion lib/components/PickerItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function PickerItem({
...restProps
}: PickerItemProps) {
const optionRef = useRef<HTMLDivElement | null>(null)
const { itemHeight, value: pickerValue } = usePickerData('Picker.Item')
const { itemHeight, value: pickerValue, mouseMode } = usePickerData('Picker.Item')
const pickerActions = usePickerActions('Picker.Item')
const { key } = useColumnData('Picker.Item')

Expand All @@ -43,6 +43,7 @@ function PickerItem({
)

const handleClick = useCallback(() => {
if (mouseMode === 'drag') return
pickerActions.change(key, value)
}, [pickerActions, key, value])

Expand Down