diff --git a/README.md b/README.md
index eb0f265..3b67a0f 100644
--- a/README.md
+++ b/README.md
@@ -127,13 +127,14 @@ function MyPicker() {
the main Picker container component.
-| Prop | Default | Description |
-| :---- | :------- | :----------- |
-| value | N/A | `{ [name: string]: string }`
Selected value pairs |
-| onChange | N/A | `(value: T, key: string) => void`
Callback function when the selected value changes |
-| height | 216 | `number`
Height of the picker in `px` |
-| itemHeight | 36 | `number`
Height of each item (that is each option) in `px` |
-| wheelMode | `'off'` | `'off' \| 'natural' \| 'normal'`
Enable wheel scrolling on desktop browsers |
+| Prop | Default | Description |
+|:-----------|:----------|:-----------------------------------------------------------------------------------------|
+| value | N/A | `{ [name: string]: string }`
Selected value pairs |
+| onChange | N/A | `(value: T, key: string) => void`
Callback function when the selected value changes |
+| height | 216 | `number`
Height of the picker in `px` |
+| itemHeight | 36 | `number`
Height of each item (that is each option) in `px` |
+| wheelMode | `'off'` | `'off' \| 'natural' \| 'normal'`
Enable wheel scrolling on desktop browsers |
+| mouseMode | `'click'` | `'click' \| 'drag'`
How to select an item with a mouse — by click or drag. |
### Picker.Column
diff --git a/examples/containers/InlinePicker.tsx b/examples/containers/InlinePicker.tsx
index 7915616..575f74b 100644
--- a/examples/containers/InlinePicker.tsx
+++ b/examples/containers/InlinePicker.tsx
@@ -30,6 +30,7 @@ export default function InlinePicker() {
value={pickerValue}
onChange={setPickerValue}
wheelMode="natural"
+ mouseMode="drag"
>
{renderOptions(['Mr.', 'Mrs.', 'Ms.', 'Dr.'], 'text-red-600')}
diff --git a/lib/components/Picker.tsx b/lib/components/Picker.tsx
index 56c4b19..9315bdb 100644
--- a/lib/components/Picker.tsx
+++ b/lib/components/Picker.tsx
@@ -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
@@ -19,12 +20,14 @@ export interface PickerRootProps extends Omit(null)
@@ -118,6 +121,7 @@ function PickerRoot(props: PickerRootProps) {
height = DEFAULT_HEIGHT,
itemHeight = DEFAULT_ITEM_HEIGHT,
wheelMode = DEFAULT_WHEEL_MODE,
+ mouseMode= DEFAULT_MOUSE_MODE,
...restProps
} = props
@@ -149,8 +153,8 @@ function PickerRoot(props: PickerRootProps) {
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) => {
diff --git a/lib/components/PickerColumn.tsx b/lib/components/PickerColumn.tsx
index bc5cb51..4daf7c9 100644
--- a/lib/components/PickerColumn.tsx
+++ b/lib/components/PickerColumn.tsx
@@ -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(
@@ -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()
@@ -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])
@@ -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],
)
@@ -221,6 +239,9 @@ function PickerColumn({
...style,
}}
ref={containerRef}
+ onMouseDown={handleMouseStart}
+ onMouseUp={handleTouchEnd}
+ onMouseLeave={handleTouchCancel}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
onTouchCancel={handleTouchCancel}
diff --git a/lib/components/PickerItem.tsx b/lib/components/PickerItem.tsx
index 75f916d..21ae538 100644
--- a/lib/components/PickerItem.tsx
+++ b/lib/components/PickerItem.tsx
@@ -23,7 +23,7 @@ function PickerItem({
...restProps
}: PickerItemProps) {
const optionRef = useRef(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')
@@ -43,6 +43,7 @@ function PickerItem({
)
const handleClick = useCallback(() => {
+ if (mouseMode === 'drag') return
pickerActions.change(key, value)
}, [pickerActions, key, value])