diff --git a/src/components/Sortable/Item/Item.jsx b/src/components/Sortable/Item/Item.jsx new file mode 100644 index 0000000..2736471 --- /dev/null +++ b/src/components/Sortable/Item/Item.jsx @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2020, Amdocs Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, {useContext, useRef} from 'react'; +import cls from 'classnames'; +import Draggable from 'components/Draggable'; +import Context from '../Sortable.context'; +import {propTypes, defaultProps} from './Item.props'; +import './Item.scss'; + +const Item = ({children, index, ...props}) => { + const ref = useRef(); + const context = useContext(Context); + const source = Draggable.useSource({ + data: {index}, + onBeginDrag: () => { + context.sort.current.from = index; + context.sort.current.displacement = ref.current.getBoundingClientRect().height; + context.onBeginSort(); + }, + onDrop: () => { + context.sort.current = {}; + context.onEndSort(); + }, + }); + const target = Draggable.useTarget({ + data: {index}, + onBeginHover: source => { + // When swapping, the dragged element moves below the clone, triggering a 'mouseover' + // event on itself. To prevent an infinite loop, we verify that the dragged item is not the target. + if (source.data.index !== index && context.sort.current.to !== index) { + context.sort.current.to = index; + context.onSort(context.sort.current) + context.sort.current.from = index; + } + }, + }); + const combined = Draggable.useCombined(source, target); + return ( + + {children} + + ); +}; + +Item.propTypes = propTypes; +Item.defaultProps = defaultProps; + +export default Item; \ No newline at end of file diff --git a/src/components/Sortable/Item/Item.props.js b/src/components/Sortable/Item/Item.props.js new file mode 100644 index 0000000..36037bc --- /dev/null +++ b/src/components/Sortable/Item/Item.props.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2020, Amdocs Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {number, node} from 'prop-types'; + +export const propTypes = { + children: node, + index: number.isRequired, +}; + +export const defaultProps = { + children: null, +}; diff --git a/src/components/Sortable/Item/Item.scss b/src/components/Sortable/Item/Item.scss new file mode 100644 index 0000000..d3fb3ef --- /dev/null +++ b/src/components/Sortable/Item/Item.scss @@ -0,0 +1,3 @@ +.sortable-item { + transition: transform 2s ease-out; +} \ No newline at end of file diff --git a/src/components/Sortable/Sortable.context.js b/src/components/Sortable/Sortable.context.js new file mode 100644 index 0000000..b40d1d7 --- /dev/null +++ b/src/components/Sortable/Sortable.context.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2020, Amdocs Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; + +export default React.createContext({}); \ No newline at end of file diff --git a/src/components/Sortable/Sortable.jsx b/src/components/Sortable/Sortable.jsx new file mode 100644 index 0000000..d094dc0 --- /dev/null +++ b/src/components/Sortable/Sortable.jsx @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2020, Amdocs Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, {useMemo, useRef} from 'react'; +import Context from './Sortable.context'; +import {propTypes, defaultProps} from './Sortable.props'; + +export const Sortable = ({children, onBeginSort, onSort, onEndSort}) => { + const context = useRef({}); + const sort = useRef({}); + context.current = {onBeginSort, onSort, onEndSort}; + return ( + ({ + sort, + onBeginSort: (...args) => context.current.onBeginSort(...args), + onSort: (...args) => context.current.onSort(...args), + onEndSort: (...args) => context.current.onEndSort(...args), + }), [])}> + {children} + + ); +}; + +Sortable.propTypes = propTypes; +Sortable.defaultProps = defaultProps; + +export default Sortable; \ No newline at end of file diff --git a/src/components/Sortable/Sortable.props.js b/src/components/Sortable/Sortable.props.js new file mode 100644 index 0000000..04d8587 --- /dev/null +++ b/src/components/Sortable/Sortable.props.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2020, Amdocs Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {func, node} from 'prop-types'; +import {noop} from 'utility/memory'; + +export const propTypes = { + children: node, + onBeginSort: func, + onSort: func, + onEndSort: func, +}; + +export const defaultProps = { + children: null, + onBeginSort: noop, + onSort: noop, + onEndSort: noop, +}; diff --git a/src/components/Sortable/index.js b/src/components/Sortable/index.js new file mode 100644 index 0000000..88e4dc8 --- /dev/null +++ b/src/components/Sortable/index.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2020, Amdocs Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Sortable from './Sortable'; +import Item from './Item/Item'; + +Sortable.Item = Item; + +export default Sortable; \ No newline at end of file diff --git a/src/components/index.js b/src/components/index.js index c8e7c3f..04ea237 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -3,6 +3,7 @@ export {default as Draggable} from './Draggable'; export {default as Movable} from './Movable'; export {default as Resizable} from './Resizable'; export {default as Scrollable} from './Scrollable'; +export {default as Sortable} from './Sortable'; export {default as Stackable} from './Stackable'; export {default as Scalable} from './Scalable'; export {default as Pannable} from './Pannable';