```js
    <SortableGridBase
      withHandle={false}
      usePortal={false}
      dragPreview={false}
      onDrop={({
        removedIndex,
        addedIndex,
        removedFromContainerId,
        addedToContainerId,
        payload,
      }) =>
        console.log({
          removedIndex,
          addedIndex,
          removedFromContainerId,
          addedToContainerId,
          payload,
        })
      }
      containerId="single-area-1"
      dataHook="grid-single-area"
      items={[{ id: 1, text: 'item1' }, { id: 2, text: 'item2' }]}
      renderItem={({ isPlaceholder, isPreview, id, previewStyles, item }) => {
        return <div>{item.text}</div>;
      }}
    />;
```

<details>
  <summary>`Props`</summary>
  | propName         | propType | defaultValue | isRequired | description |
  | ---              | ---      | ---          | ---        | ---         |
  | items            | array    | -            | true       | array of items, each item should have an id. |
  | renderItem       | func     | -            | true       | render function which will be used to render item block inside of sortable list |
  | insertPosition    | 'start', 'end','any'     | 'any'            | -       | set insertion rule for droppable items.  |
  | onDrop           | func     | -            | true       | callback for onDrop event, it will be called after user drop smth |
  | containerId      | string   | -            | true       | unique id, it required to prevent or allow d&d between several containers |
  | className        | string   | -            | -          | className for root of  SortableListBase, in case if you want to style root element of SortableListBase |
  | contentClassName | string   | -            | -          | className for items wrapper div, it maybe useful if you want to make horizontal sortable list |
  | groupName        | string   | -            | -          | name of group to which SortableListBase is related, d&d allowed inside of the same group |
  | withHandle       | bool     | false        | -          | should whole item be draggable or just handle on it|
  | usePortal        | bool     | false        | -          | render item preview into body|
  | dragPreview      | bool     | false        | -          | in case if you have nested SortableListBases, you need to set dragPreview to true when you drag nested SortableListBase |
  | droppable        | bool     | true         | -          | indicates if user can drop items in the list  |
  | animationDuration| number   | 0            | -          | animation duration. Please note, `SortableListBase` uses CSS `transition`s to animate itself
  | animationTiming  | string   | ''           | -          | animation timing function
  | delay            | number   |  -           | -          | number of ms that user should press on item before drag will start
  | canDrag          | func     |  -           | -          | function which will be used before drag start and can prevent it like if returns false: () => false |
  | listOfPropsThatAffectItems | array     |  -           | -          | Array that contains values that are used inside of renderItem callback.(Change of these values cause re-call of renderItem func) |
  | startFixedElement | node     |  -           | -          | Node which will be rendered before draggable items and this element won't be draggable |
  | endFixedElement   | node     |  -           | -          | Node which will be rendered after draggable items and this element won't be draggable |
</details>

Some details about complex props

<details>
  <summary>`items`</summary>
  Example:
  ```js
  [
    {
      id: 'a',
      text: 'Item 1'
    },
    {
      id: 'b',
      text: 'Item 2'
    },
    {
      id: 'c',
      text: 'Item 3'
    },
    {
      id: 'd',
      text: 'Item 4'
    }
  ]
  ```
</details>
<details>
  <summary>`renderItem`</summary>
  This function called with such parameters:

- `isPlaceholder` - if item in drag state,
  then instead of an item(item previous place)
  we want to render placeholder(empty block, or left item as it is), so you able to style your item by checking isPlaceholder.
- `isPreview` - if item in drag(fly) state,
  then instead of an item,
  we want to render preview
  state(maybe we want to rotate it a little, or hide something),
  so you able to style your item by checking isPreview.
- `id` - an id from item that you render
- `item` - item that you are render
- `isInitialPositionToDrop` - if item in drag state and a drop position matches the initial position
- `withStrip` - Strip between the grid items. Drop position object appears as a vertical strip. Can be "right" or "left" (depends on position of hovered item)

Example without handle:

```js
renderItem = ({
  isPlaceholder,
  isPreview,
  id,
  item,
  withStrip,
  isInitialPositionToDrop,
}) => {
  const stripPositionClass = classNames({
    [defaultDndStyles.withGridItemStrip]: withStrip,
    [defaultDndStyles.withGridItemStripRight]: withStrip === 'right',
  });

  const classes = classNames(
    classNames(defaultDndStyles.item, styles.item, stripPositionClass),
    {
      [classNames(defaultDndStyles.gridItemPreview)]: isPreview,
      [classNames(defaultDndStyles.gridItemPlaceholder)]: isPlaceholder,
      [classNames(
        defaultDndStyles.isInitialPositionToDrop,
      )]: isInitialPositionToDrop,
    },
  );

  return (
    <div className={classes} data-hook={`item-${id}`}>
      {item.text}
    </div>
  );
};
```

Example with handle:

```js
renderItem = ({
  isPlaceholder,
  isPreview,
  id,
  connectHandle,
  previewStyles,
  item,
}) => {
  const classes = classNames(styles.card, {
    [styles.placeholder]: isPlaceholder,
    [styles.preview]: isPreview,
  });

  return (
    <div className={classes} style={previewStyles} data-hook={`item-${id}`}>
      {connectHandle(
        <div className={styles.handle} data-hook={`card-${id}-handle`}>
          <DragAndDropLarge /> // an icon
        </div>,
      )}
      {item.text}
    </div>
  );
};
```

</details>
<details>
  <summary>`onDrop`</summary>
  This function called with such parameters:

- `removedIndex` - index of an item previous position inside of original items array
- `addedIndex` - index of an item new position inside of new items array
- `removedFromContainerId` - id of the container(SortableListBase instance) from which item was removed
- `addedToContainerId` - id of the container(SortableListBase instance) to which item was dropped
- `payload` - original item data

Example of d&d onDrop callback for drag between two columns(two SortableListBase)

```js
handleDrop = ({
  removedIndex,
  addedIndex,
  removedFromContainerId,
  addedToContainerId,
  payload,
}) => {
  const nextState = copy(this.state);
  nextState[removedFromContainerId].splice(removedIndex, 1);
  nextState[addedToContainerId].splice(addedIndex, 0, payload);

  this.setState({ ...nextState });
};
```

</details>
<details>
  <summary>`dragPreview`</summary>
  Case of nested sortable list

```js
  ...
  renderColumn = ({isPlaceholder, isPreview, item, id, previewStyles}) => {
    const classes = classNames(
      {
        [classNames(styles.columnPlaceholder)]: isPlaceholder,
        [classNames(styles.columnItemPreview)]: isPreview
      },
      classNames(styles.columnItem)
    );

    return (
      <div className={classes} style={previewStyles} data-hook={`column-${id}`}>
        <SortableGridBase
          dragPreview={isPreview}
          className={styles.column}
          dataHook={`column-${id}`}
          groupName="multi-area"
          containerId={id}
          items={item.items}
          renderItem={this.renderCell}
          onDrop={this.handleDropCell}
          />
      </div>
    );
  }

  render() {
    return (
      <DragDropContextProvider>
        <div className={styles.root}>
          <SortableGridBase
            className={styles.table}
            contentClassName={styles.content}
            dataHook="draggable-column-multi-area"
            containerId="multiArea"
            items={this.state.columns}
            renderItem={this.renderColumn}
            onDrop={this.handleDropColumn}
            />
        </div>
      </DragDropContextProvider>
    );
  }
```

</details>
<details>
  <summary>`onDrop`</summary>
  This function called with such parameters:

- `removedIndex` - index of an item previous position inside of original items array
- `addedIndex` - index of an item new position inside of new items array
- `removedFromContainerId` - id of the container(SortableListBase instance) from which item was removed
- `addedToContainerId` - id of the container(SortableListBase instance) to which item was dropped
- `payload` - original item data

Example of d&d onDrop callback for drag between two columns(two SortableListBase)

```js
handleDrop = ({
  removedIndex,
  addedIndex,
  removedFromContainerId,
  addedToContainerId,
  payload,
}) => {
  const nextState = copy(this.state);
  nextState[removedFromContainerId].splice(removedIndex, 1);
  nextState[addedToContainerId].splice(addedIndex, 0, payload);

  this.setState({ ...nextState });
};
```

</details>
<details>
  <summary>`listOfPropsThatAffectItems`</summary>
  You can also check SortableListBase.spec.js(`should call renderItem when props changed`) test.

```js
  ...
  class MyComponent extends React.Component {
    state = {
      isListInDragState: false
    }
    handleDragStart = () => this.setState({ isListInDragState: true })
    handleDragEnd = () => this.setState({ isListInDragState: false })

    /*
      GOAL:
      inside of render item callback we use `isListInDragState` from state,
      so we expect, that when we will do setState({ isListInDragState: someValue }),
      the renderItem will call again and render updated state in dom
    */
    renderItem = ({ item }) => (
      <div key={item.id} data-hook={`item-${item.id}`}>
        {item.text}
        Is list in drag state? - {this.state.isListInDragState ? 'yes' : 'no'}
      </div>
    )

    render() {
      /*
        To achieve our goal from renderItem callback, we need to tell SortableListBase,
        that this.state.isListInDragState can affect our items view and that SortableListBase need to
        call renderItem again when this.state.isListInDragState changed.
        To do this we use `listOfPropsThatAffectItems`
      */
      return (
        <div>
          <SortableGridBase
            contentClassName="cl"
            dataHook={dataHook}
            containerId="sortable-list-1"
            groupName="group1"
            items={items}
            renderItem={this.renderItem}
            onDrop={onDrop}
            onDragStart={this.handleDragStart}
            onDragEnd={this.handleDragEnd}
            listOfPropsThatAffectItems={[this.state.isListInDragState]}
          />
        </div>
      );
    }
  }
```

</details>
