-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AnglePicker Component; Add useDragging hook
- Loading branch information
1 parent
c8a1eef
commit b82f147
Showing
8 changed files
with
257 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useRef } from '@wordpress/element'; | ||
import { useInstanceId, __experimentalUseDragging as useDragging } from '@wordpress/compose'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import BaseControl from '../base-control'; | ||
|
||
function getAngle( centerX, centerY, pointX, pointY ) { | ||
const y = pointY - centerY; | ||
const x = pointX - centerX; | ||
|
||
const angleInRadians = Math.atan2( y, x ); | ||
const angleInDeg = Math.round( angleInRadians * ( 180 / Math.PI ) ) + 90; | ||
if ( angleInDeg < 0 ) { | ||
return 360 + angleInDeg; | ||
} | ||
return angleInDeg; | ||
} | ||
|
||
const AngleCircle = ( { value, onChange } ) => { | ||
const angleCircleRef = useRef(); | ||
const angleCircleCenter = useRef(); | ||
|
||
const setAngleCircleCenter = () => { | ||
const rect = angleCircleRef.current.getBoundingClientRect(); | ||
angleCircleCenter.current = { | ||
x: rect.x + ( rect.width / 2 ), | ||
y: rect.y + ( rect.height / 2 ), | ||
}; | ||
}; | ||
|
||
const changeAngleToPosition = ( event ) => { | ||
const { x: centerX, y: centerY } = angleCircleCenter.current; | ||
onChange( getAngle( centerX, centerY, event.clientX, event.clientY ) ); | ||
}; | ||
|
||
const { startDrag, isDragging } = useDragging( { | ||
onDragStart: ( event ) => { | ||
setAngleCircleCenter(); | ||
changeAngleToPosition( event ); | ||
}, | ||
onDragMove: changeAngleToPosition, | ||
onDragEnd: changeAngleToPosition, | ||
} ); | ||
return ( | ||
/* eslint-disable jsx-a11y/no-static-element-interactions */ | ||
<div | ||
ref={ angleCircleRef } | ||
onMouseDown={ startDrag } | ||
className="components-angle-picker__angle-circle" | ||
style={ isDragging ? { cursor: 'grabbing' } : undefined } | ||
> | ||
<div | ||
style={ value ? { transform: `rotate(${ value }deg)` } : undefined } | ||
className="components-angle-picker__angle-circle-indicator-wrapper" | ||
> | ||
<span className="components-angle-picker__angle-circle-indicator" /> | ||
</div> | ||
</div> | ||
/* eslint-enable jsx-a11y/no-static-element-interactions */ | ||
); | ||
}; | ||
|
||
export default function AnglePicker( { value, onChange, label = __( 'Angle' ) } ) { | ||
const instanceId = useInstanceId( AnglePicker ); | ||
const inputId = `components-custom-gradient-picker__angle-picker-${ instanceId }`; | ||
return ( | ||
<BaseControl | ||
label={ label } | ||
id={ inputId } | ||
className="components-angle-picker" | ||
> | ||
<AngleCircle value={ value } onChange={ onChange } /> | ||
<input | ||
className="components-angle-picker__input-field" | ||
type="number" | ||
id={ inputId } | ||
onChange={ ( event ) => { | ||
const unprocessedValue = event.target.value; | ||
const inputValue = unprocessedValue !== '' ? | ||
parseInt( event.target.value, 10 ) : | ||
0; | ||
onChange( inputValue ); | ||
} } | ||
value={ value } | ||
min={ 0 } | ||
max={ 360 } | ||
step="1" | ||
/> | ||
</BaseControl> | ||
); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
|
||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useState } from '@wordpress/element'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import AnglePicker from '../'; | ||
|
||
export default { title: 'Components|AnglePicker', component: AnglePicker }; | ||
|
||
const AnglePickerWithState = () => { | ||
const [ angle, setAngle ] = useState(); | ||
return ( | ||
<AnglePicker value={ angle } onChange={ setAngle } /> | ||
); | ||
}; | ||
|
||
export const _default = () => { | ||
return ( <AnglePickerWithState /> ); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
.components-angle-picker { | ||
width: 50%; | ||
&.components-base-control .components-base-control__label { | ||
display: block; | ||
} | ||
} | ||
|
||
.components-angle-picker__input-field { | ||
width: calc(100% - #{$icon-button-size}); | ||
max-width: 100px; | ||
} | ||
|
||
.components-angle-picker__angle-circle { | ||
width: $icon-button-size - ( 2 * $grid-size-small ); | ||
height: $icon-button-size - ( 2 * $grid-size-small ); | ||
border: 2px solid $dark-gray-500; | ||
border-radius: 50%; | ||
float: left; | ||
margin-right: $grid-size-small; | ||
cursor: grab; | ||
} | ||
|
||
.components-angle-picker__angle-circle-indicator-wrapper { | ||
position: relative; | ||
width: 100%; | ||
height: 100%; | ||
} | ||
|
||
.components-angle-picker__angle-circle-indicator { | ||
width: 1px; | ||
height: 1px; | ||
border-radius: 50%; | ||
border: 3px solid $dark-gray-500; | ||
display: block; | ||
position: absolute; | ||
top: -($icon-button-size - (2 * $grid-size-small)) / 2; | ||
bottom: 0; | ||
left: 0; | ||
right: 0; | ||
margin: auto; | ||
background: $dark-gray-500; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { useEffect, useCallback, useState, useRef } from '@wordpress/element'; | ||
|
||
export default function useDragging( { onDragStart, onDragMove, onDragEnd } ) { | ||
const [ isDragging, setIsDragging ] = useState( false ); | ||
|
||
const eventsRef = useRef( { | ||
onDragStart, | ||
onDragMove, | ||
onDragEnd, | ||
} ); | ||
useEffect( | ||
() => { | ||
eventsRef.current.onDragStart = onDragStart; | ||
eventsRef.current.onDragMove = onDragMove; | ||
eventsRef.current.onDragEnd = onDragEnd; | ||
}, | ||
[ onDragStart, onDragMove, onDragEnd ] | ||
); | ||
|
||
const startDrag = useCallback( ( ...args ) => { | ||
if ( eventsRef.current.onDragEnd ) { | ||
eventsRef.current.onDragStart( ...args ); | ||
} | ||
setIsDragging( true ); | ||
} ); | ||
const onMouseMove = useCallback( ( ...args ) => ( eventsRef.current.onDragMove && eventsRef.current.onDragMove( ...args ) ) ); | ||
const endDrag = useCallback( ( ...args ) => { | ||
if ( eventsRef.current.onDragEnd ) { | ||
eventsRef.current.onDragEnd( ...args ); | ||
} | ||
setIsDragging( false ); | ||
} ); | ||
|
||
useEffect( () => { | ||
if ( isDragging ) { | ||
document.addEventListener( 'mousemove', onMouseMove ); | ||
document.addEventListener( 'mouseup', endDrag ); | ||
} | ||
|
||
return () => { | ||
document.removeEventListener( 'mousemove', onMouseMove ); | ||
document.removeEventListener( 'mouseup', endDrag ); | ||
}; | ||
}, [ isDragging ] ); | ||
return { | ||
startDrag, | ||
endDrag, | ||
isDragging, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters