@@ -385,7 +385,14 @@ function DraggableCollectionExample(props) {
385385 } ;
386386
387387 return (
388- < DraggableCollection items = { list . items } selectedKeys = { list . selectedKeys } onSelectionChange = { list . setSelectedKeys } onDragEnd = { onDragEnd } onCut = { onCut } isDisabled = { props . isDisabled } >
388+ < DraggableCollection
389+ items = { list . items }
390+ selectedKeys = { list . selectedKeys }
391+ onSelectionChange = { list . setSelectedKeys }
392+ onDragEnd = { onDragEnd }
393+ onCut = { onCut }
394+ isDisabled = { props . isDisabled }
395+ { ...props } >
389396 { item => (
390397 < Item textValue = { item . text } >
391398 { item . type === 'folder' && < Folder size = "S" /> }
@@ -397,7 +404,7 @@ function DraggableCollectionExample(props) {
397404}
398405
399406function DraggableCollection ( props ) {
400- let { isDisabled} = props ;
407+ let { isDisabled, mode , offsetX , offsetY } = props ;
401408 let ref = React . useRef < HTMLDivElement > ( null ) ;
402409 let state = useListState < ItemValue > ( props ) ;
403410 let gridState = useGridState ( {
@@ -472,7 +479,7 @@ function DraggableCollection(props) {
472479 let selectedKeys = dragState . draggingKeys ;
473480 let draggedKey = [ ...selectedKeys ] [ 0 ] ;
474481 let item = state . collection . getItem ( draggedKey ) ;
475- return (
482+ let element = (
476483 < div className = { classNames ( dndStyles , 'draggable' , 'is-drag-preview' , { 'is-dragging-multiple' : selectedKeys . size > 1 } ) } >
477484 < div className = { classNames ( dndStyles , 'drag-handle' ) } >
478485 < ShowMenu size = "XS" />
@@ -483,6 +490,12 @@ function DraggableCollection(props) {
483490 }
484491 </ div >
485492 ) ;
493+
494+ if ( mode === 'custom' ) {
495+ return { element, x : offsetX , y : offsetY } ;
496+ }
497+
498+ return element ;
486499 } }
487500 </ DragPreview >
488501 </ div >
@@ -575,3 +588,129 @@ export const DroppableEnabledDisabledControl: DnDStoryObj = {
575588 }
576589 }
577590} ;
591+
592+ interface PreviewOffsetArgs {
593+ /** Strategy for positioning the preview. */
594+ mode : 'default' | 'custom' ,
595+ /** X offset in pixels (only used when mode = custom). */
596+ offsetX : number ,
597+ /** Y offset in pixels (only used when mode = custom). */
598+ offsetY : number
599+ }
600+
601+ function DraggableWithPreview ( { mode, offsetX, offsetY} : PreviewOffsetArgs ) : JSX . Element {
602+ const preview = React . useRef ( null ) ;
603+
604+ const { dragProps, isDragging} = useDrag ( {
605+ getItems ( ) {
606+ return [ {
607+ 'text/plain' : 'preview offset demo'
608+ } ] ;
609+ } ,
610+ preview,
611+ onDragStart : action ( 'onDragStart' ) ,
612+ onDragEnd : action ( 'onDragEnd' )
613+ } ) ;
614+
615+ const { clipboardProps} = useClipboard ( {
616+ getItems ( ) {
617+ return [ {
618+ 'text/plain' : 'preview offset demo'
619+ } ] ;
620+ }
621+ } ) ;
622+
623+ const ref = React . useRef < HTMLDivElement > ( null ) ;
624+ const { buttonProps} = useButton ( { elementType : 'div' } , ref ) ;
625+
626+ return (
627+ < >
628+ < div
629+ ref = { ref }
630+ { ...mergeProps ( dragProps , buttonProps , clipboardProps ) }
631+ className = { classNames ( dndStyles , 'draggable' , { 'is-dragging' : isDragging } ) }
632+ style = { { cursor : 'grab' } } >
633+ < ShowMenu size = "XS" />
634+ < span > Drag me</ span >
635+ </ div >
636+
637+ { /* Custom drag preview */ }
638+ < DragPreview ref = { preview } >
639+ { ( ) => {
640+ const elem = (
641+ < div className = { classNames ( dndStyles , 'draggable' , 'is-drag-preview' ) } >
642+ < ShowMenu size = "XS" />
643+ < span > Preview</ span >
644+ </ div >
645+ ) ;
646+
647+ if ( mode === 'custom' ) {
648+ return { element : elem , x : offsetX , y : offsetY } ;
649+ }
650+
651+ return elem ;
652+ } }
653+ </ DragPreview >
654+ </ >
655+ ) ;
656+ }
657+
658+ export const PreviewOffset : DnDStoryObj = {
659+ render : ( args ) => (
660+ < Flex direction = "column" gap = "size-200" alignItems = "center" >
661+ < DraggableWithPreview { ...args } />
662+ < Droppable />
663+ </ Flex >
664+ ) ,
665+ name : 'Preview offset' ,
666+ argTypes : {
667+ mode : {
668+ control : 'select' ,
669+ options : [ 'default' , 'custom' ] ,
670+ defaultValue : 'default'
671+ } ,
672+ offsetX : {
673+ control : 'number' ,
674+ defaultValue : 20
675+ } ,
676+ offsetY : {
677+ control : 'number' ,
678+ defaultValue : 20
679+ }
680+ } ,
681+ args : {
682+ mode : 'default' ,
683+ offsetX : 20 ,
684+ offsetY : 20
685+ }
686+ } ;
687+
688+ export const CollectionPreviewOffset : DnDStoryObj = {
689+ render : ( args ) => (
690+ < Flex direction = "column" gap = "size-200" alignItems = "center" >
691+ < DraggableCollectionExample { ...args } />
692+ < Droppable />
693+ </ Flex >
694+ ) ,
695+ name : 'Collection preview offset' ,
696+ argTypes : {
697+ mode : {
698+ control : 'select' ,
699+ options : [ 'default' , 'custom' ] ,
700+ defaultValue : 'default'
701+ } ,
702+ offsetX : {
703+ control : 'number' ,
704+ defaultValue : 20
705+ } ,
706+ offsetY : {
707+ control : 'number' ,
708+ defaultValue : 20
709+ }
710+ } ,
711+ args : {
712+ mode : 'default' ,
713+ offsetX : 20 ,
714+ offsetY : 20
715+ }
716+ } ;
0 commit comments