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';