-
-
Notifications
You must be signed in to change notification settings - Fork 280
feat: add move operation for List #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 8 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
b0ee9fd
add move operation for List
hvsy 522ee30
Fixed format error
hvsy 70288fb
Fixed format error
hvsy 7f1d951
Fixed input can not be selectable
hvsy 09eb435
Fixed format for eslint
hvsy bf47330
add noneffective move test
hvsy 4397bab
remove unnecessary action of draggable list example
hvsy 077aba2
remove lodash-move
hvsy 3601dc6
add test for array move function
hvsy c348a27
move "arrayMove" function to valueUtil.ts file.
hvsy ae16986
add more test cases for move function.
hvsy 06167f3
upgrade father to latest
hvsy 2e99658
add missing match key tests.
hvsy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,91 @@ | ||
| /* eslint-disable react/prop-types */ | ||
|
|
||
| import React from 'react'; | ||
| import HTML5Backend from 'react-dnd-html5-backend'; | ||
| import { DndProvider } from 'react-dnd'; | ||
| import Form from '../src'; | ||
| import Input from './components/Input'; | ||
| import LabelField from './components/LabelField'; | ||
| import useDraggable from './components/useDraggable'; | ||
|
|
||
| const { List, useForm } = Form; | ||
|
|
||
| type LabelFieldProps = Parameters<typeof LabelField>[0]; | ||
| interface DraggableProps extends LabelFieldProps{ | ||
| id : string|number, | ||
| index : number, | ||
| move : (from:number, to :number)=>void, | ||
| } | ||
| const DisableDraggable = { | ||
| onDragStart(event) { | ||
| event.stopPropagation(); | ||
| event.preventDefault(); | ||
| }, | ||
| draggable: true, | ||
| }; | ||
| const Draggable :React.FunctionComponent<DraggableProps> = ({ id, index, move, children }) => { | ||
| const { ref, isDragging } = useDraggable('list-draggable', id, index, move); | ||
| return <div ref={ref} style={{ | ||
| opacity: isDragging ? 0.5 : 1, | ||
| }}> | ||
| {children} | ||
| </div>; | ||
| }; | ||
| const Demo = () => { | ||
| const [form] = useForm(); | ||
|
|
||
| return ( | ||
| <DndProvider backend={HTML5Backend}> | ||
| <div> | ||
|
||
| <h3>Draggable List of Form</h3> | ||
| <p>You can set Field as List and sortable by drag and drop</p> | ||
|
|
||
| <Form | ||
| form={form} | ||
| onValuesChange={(_, values) => { | ||
| console.log('values:', values); | ||
| }} | ||
| style={{ border: '1px solid red', padding: 15 }} | ||
| > | ||
| <List name="users"> | ||
| {(fields, { add, remove, move }) => { | ||
| return ( | ||
| <div> | ||
| <h4>List of `users`</h4> | ||
| {fields.map((field, index) => ( | ||
| <Draggable move={move} | ||
| index={index} id={field.key} {...field} rules={[{ required: true }]}> | ||
| <LabelField {...field} rules={[{ required: true }]}> | ||
| {control => ( | ||
| <div style={{ position: 'relative' }}> | ||
| <Input {...DisableDraggable} {...control} /> | ||
| <a style={{ position: 'absolute', top: 12, right: -300 }} onClick={() => { | ||
| remove(index); | ||
| }}> | ||
| Remove | ||
| </a> | ||
| </div> | ||
| )} | ||
| </LabelField> | ||
| </Draggable> | ||
| ))} | ||
|
|
||
| <button | ||
| type="button" | ||
| onClick={() => { | ||
| add(); | ||
| }} | ||
| > | ||
| + New User | ||
| </button> | ||
| </div> | ||
| ); | ||
| }} | ||
| </List> | ||
| </Form> | ||
| </div> | ||
| </DndProvider> | ||
| ); | ||
| }; | ||
|
|
||
| export default Demo; | ||
This file contains hidden or 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,81 @@ | ||
| import { useRef } from 'react'; | ||
| import { DragObjectWithType, useDrag, useDrop } from 'react-dnd'; | ||
|
|
||
| type DragWithIndex = DragObjectWithType & { | ||
| index : number, | ||
| }; | ||
| export default function useDraggable(type : string, | ||
| id : string|number, | ||
| index : number, move : (from : number, to : number)=>void) { | ||
| const ref = useRef(null); | ||
| const [, drop] = useDrop({ | ||
| accept: type, | ||
| hover(item : DragWithIndex, monitor) { | ||
| if (!ref.current) { | ||
| return; | ||
| } | ||
| const dragIndex = item.index; | ||
| if (dragIndex === undefined || dragIndex === null) return; | ||
| const hoverIndex = index; | ||
|
|
||
| // Don't replace items with themselves | ||
| if (dragIndex === hoverIndex) { | ||
| return; | ||
| } | ||
|
|
||
| // Determine rectangle on screen | ||
| const hoverBoundingRect = ref.current.getBoundingClientRect(); | ||
|
|
||
| // Get vertical middle | ||
| const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; | ||
| const hoverMiddleX = (hoverBoundingRect.right - hoverBoundingRect.left) / 2; | ||
|
|
||
| // Determine mouse position | ||
| const clientOffset = monitor.getClientOffset(); | ||
|
|
||
| // Get pixels to the top | ||
| const hoverClientY = clientOffset.y - hoverBoundingRect.top; | ||
| const hoverClientX = clientOffset.x - hoverBoundingRect.left; | ||
|
|
||
| // console.log(hoverBoundingRect,hoverMiddleY,clientOffset,hoverClientY, | ||
| // dragIndex,hoverIndex | ||
| // ); | ||
| // Only perform the move when the mouse has crossed half of the items height | ||
| // When dragging downwards, only move when the cursor is below 50% | ||
| // When dragging upwards, only move when the cursor is above 50% | ||
|
|
||
| // Dragging downwards | ||
| if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY | ||
| && hoverClientX < hoverMiddleX | ||
| ) { | ||
| return; | ||
| } | ||
|
|
||
| // Dragging upwards | ||
| if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY | ||
| && hoverClientX > hoverMiddleX | ||
| ) { | ||
| return; | ||
| } | ||
|
|
||
| // Time to actually perform the action | ||
| move(dragIndex, hoverIndex); | ||
|
|
||
| // Note: we're mutating the monitor item here! | ||
| // Generally it's better to avoid mutations, | ||
| // but it's good here for the sake of performance | ||
| // to avoid expensive index searches. | ||
| item.index = hoverIndex; | ||
| }, | ||
| }); | ||
| const [{ isDragging }, drag] = useDrag({ | ||
| item: { type, id, index }, | ||
| collect: monitor => ({ | ||
| isDragging: monitor.isDragging(), | ||
| }), | ||
| }); | ||
| drag(drop(ref)); | ||
| return { | ||
| ref, isDragging, | ||
| }; | ||
| } |
This file contains hidden or 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 hidden or 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 hidden or 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,35 @@ | ||
| export function arrayMove<T>(array: T[], moveIndex: number, toIndex: number) { | ||
zombieJ marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /* #move - Moves an array item from one position in an array to another. | ||
| Note: This is a pure function so a new array will be returned, instead | ||
| of altering the array argument. | ||
| Arguments: | ||
| 1. array (String) : Array in which to move an item. (required) | ||
| 2. moveIndex (Object) : The index of the item to move. (required) | ||
| 3. toIndex (Object) : The index to move item at moveIndex to. (required) | ||
| */ | ||
zombieJ marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const item = array[moveIndex]; | ||
zombieJ marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const { length } = array; | ||
| const diff = moveIndex - toIndex; | ||
|
|
||
| if (diff > 0) { | ||
| // move left | ||
| return [ | ||
| ...array.slice(0, toIndex), | ||
| item, | ||
| ...array.slice(toIndex, moveIndex), | ||
| ...array.slice(moveIndex + 1, length), | ||
| ]; | ||
| } | ||
| if (diff < 0) { | ||
| // move right | ||
| return [ | ||
| ...array.slice(0, moveIndex), | ||
| ...array.slice(moveIndex + 1, toIndex + 1), | ||
| item, | ||
| ...array.slice(toIndex + 1, length), | ||
| ]; | ||
| } | ||
| return array; | ||
| } | ||
This file contains hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LabelFieldProps{=>LabelFieldProps {Seems still missing types. Could you try to remove
.git/hooksand reinstallnode_modulesto makefatherpre-commit hooks work. This will auto prettier the code when commit.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please reference to following code. The default config don't include the examples directory.
so father pre-commit don't work for it.
https://github.com/umijs/father/blob/86e4eb154c212072cd937d6a87fd91762159e069/packages/father/src/preCommit.ts#L113
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me add PR for this. Thanks for notice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add "examples" to the regex of pre-commit by manual. after then, I get following errors by exec "father pre-commit".
'react-dnd-html5-backend' and 'react-dnd' should only be used for example. it should be listed in devDependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for feedback. Add PR for this: umijs/fabric#6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
@umi/fabric, please check.