このコミットが含まれているのは:
@@ -0,0 +1,93 @@
|
||||
import { useContext, useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { CountsTableScope, MAX_COUNT_WIDTH, MIN_COUNT_WIDTH,
|
||||
useCountsTableLayout } from '@/lib/countsTableLayout'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useUITranslation } from '@/lib/useUITranslation'
|
||||
|
||||
|
||||
const CountsResizeHandle = ({ field, label }: {
|
||||
field: string; label: { text: string; language: string } }) => {
|
||||
const family = useContext (CountsTableScope)
|
||||
const layout = useCountsTableLayout ()
|
||||
const { message } = useUITranslation ('counts')
|
||||
const [active, setActive] = useState (false)
|
||||
const press = useRef<{ x: number; y: number; width: number; armed: boolean
|
||||
timer?: ReturnType<typeof setTimeout> } | null> (null)
|
||||
const saved = useRef<{ cursor: string; userSelect: string } | null> (null)
|
||||
const restore = () => {
|
||||
if (saved.current == null) return
|
||||
document.body.style.cursor = saved.current.cursor
|
||||
document.body.style.userSelect = saved.current.userSelect
|
||||
saved.current = null
|
||||
}
|
||||
const finish = () => {
|
||||
if (press.current?.timer != null) clearTimeout (press.current.timer)
|
||||
press.current = null
|
||||
setActive (false)
|
||||
restore ()
|
||||
}
|
||||
const arm = () => {
|
||||
if (press.current == null) return
|
||||
press.current.armed = true
|
||||
saved.current = { cursor: document.body.style.cursor,
|
||||
userSelect: document.body.style.userSelect }
|
||||
document.body.style.cursor = 'col-resize'
|
||||
document.body.style.userSelect = 'none'
|
||||
setActive (true)
|
||||
}
|
||||
useEffect (() => () => {
|
||||
if (press.current?.timer != null) clearTimeout (press.current.timer)
|
||||
if (saved.current != null)
|
||||
{
|
||||
document.body.style.cursor = saved.current.cursor
|
||||
document.body.style.userSelect = saved.current.userSelect
|
||||
}
|
||||
}, [])
|
||||
const name = message ('resize.column', { column: label.text })
|
||||
return (
|
||||
<span role="separator" tabIndex={0} aria-orientation="vertical"
|
||||
aria-label={name.text} lang={name.language}
|
||||
aria-valuenow={layout.width (family, field)} aria-valuemin={MIN_COUNT_WIDTH}
|
||||
aria-valuemax={MAX_COUNT_WIDTH} title={name.text}
|
||||
data-counts-resize
|
||||
className={cn ('absolute inset-y-0 right-0 z-30 w-3 cursor-col-resize touch-none',
|
||||
'select-none outline-offset-[-2px] focus-visible:outline',
|
||||
'before:absolute before:inset-y-1 before:left-1/2 before:border-l',
|
||||
'before:border-slate-300 dark:before:border-slate-600',
|
||||
'hover:before:border-blue-500 dark:hover:before:border-blue-400',
|
||||
active && 'before:border-blue-500 dark:before:border-blue-400')}
|
||||
onPointerDown={event => {
|
||||
event.stopPropagation ()
|
||||
if (!event.isPrimary || event.button !== 0) return
|
||||
event.preventDefault ()
|
||||
finish ()
|
||||
event.currentTarget.setPointerCapture (event.pointerId)
|
||||
press.current = { x: event.clientX, y: event.clientY,
|
||||
width: layout.width (family, field), armed: false }
|
||||
if (event.pointerType === 'mouse') arm ()
|
||||
else press.current.timer = setTimeout (arm, 400)
|
||||
}}
|
||||
onPointerMove={event => {
|
||||
event.stopPropagation ()
|
||||
const state = press.current
|
||||
if (state == null) return
|
||||
if (state.armed)
|
||||
layout.resize (family, field, state.width + event.clientX - state.x)
|
||||
else if (Math.hypot (event.clientX - state.x, event.clientY - state.y) > 8)
|
||||
finish ()
|
||||
}}
|
||||
onPointerUp={finish} onPointerCancel={finish} onLostPointerCapture={finish}
|
||||
onClick={event => { event.preventDefault (); event.stopPropagation () }}
|
||||
onContextMenu={event => event.preventDefault ()}
|
||||
onKeyDown={event => {
|
||||
event.stopPropagation ()
|
||||
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return
|
||||
event.preventDefault ()
|
||||
layout.resize (family, field, layout.width (family, field)
|
||||
+ (event.key === 'ArrowLeft' ? -10 : 10))
|
||||
}}/>)
|
||||
}
|
||||
|
||||
|
||||
export default CountsResizeHandle
|
||||
新しいイシューから参照
ユーザーをブロックする