import { Canvas, Meta } from '@storybook/addon-docs';

import * as LocalizeStories from './sorter.stories';

<Meta title="API/Drag and Drop/Intro" />

# Drag and Drop

Drag and Drop can be done by using the `UmbSorterController`

To get started using drag and drop, finish the following steps:

- Preparing the model
- Setting the configuration
- Registering the controller

#### Preparing the model

The SorterController needs a model to know what item it is we are dealing with.

```typescript
type MySortEntryType = {
	id: string;
	value: string;
};

const awesomeModel: Array<MySortEntryType> = [
	{
		id: '0',
		value: 'Entry 0',
	},
	{
		id: '1',
		value: 'Entry 1',
	},
	{
		id: '2',
		value: 'Entry 2',
	},
];
```

#### Setting the configuration

When you know the model of which that is being sorted, you can set up the configuration.
The configuration has a lot of optional options, but the required ones are:

- compareElementToModel()
- querySelectModelToElement()
- identifier
- itemSelector
- containerSelector

It can be set up as following:

```typescript
import { UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter';

type MySortEntryType = {...}
const awesomeModel: Array<MySortEntryType> = [...]

const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {
	compareElementToModel: (element: HTMLElement, model: MySortEntryType) => {
		return element.getAttribute('data-sort-entry-id') === model.id;
	},
	querySelectModelToElement: (container: HTMLElement, modelEntry: MySortEntryType) => {
		return container.querySelector('data-sort-entry-id=[' + modelEntry.id + ']');
	},
	identifier: 'test-sorter',
	itemSelector: 'li',
	containerSelector: 'ul',
};

export class MyElement extends UmbElementMixin(LitElement) {

	render() {
		return html`
			<ul>
				${awesomeModel.map(
					(entry) =>
						html`<li data-sort-entry-id="${entry.id}">
							<span>${entry.value}</span>
						</li>`,
				)}
			</ul>
		`;
	}
}
```

#### Registering the controller

When the model and configuration are available we can register the controller and tell the controller what model we are using.

```typescript
import { UmbSorterController, UmbSorterController } from '@umbraco-cms/backoffice/sorter';

type MySortEntryType = {...}
const awesomeModel: Array<MySortEntryType> = [...]
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {...}


export class MyElement extends UmbElementMixin(LitElement) {
	#sorter = new UmbSorterController(this, MY_SORTER_CONFIG);

	constructor() {
		this.#sorter.setModel(awesomeModel);
	}

	render() {
		return html`
			<ul>
				${awesomeModel.map(
					(entry) =>
						html`<li data-sort-entry-id="${entry.id}">
							<span>${entry.value}</span>
						</li>`,
				)}
			</ul>
		`;
	}
}
```

### Placeholder

While dragging an entry, the entry will get an additional class that can be styled.
The class is by default `--umb-sorter-placeholder` but can be changed via the configuration to a different value.

```typescript
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {
	...
	placeholderClass: 'dragging-now',
};
```

```typescript
 static styles = [
    css`
        li {
            display:relative;
        }

        li.dragging-now span {
            visibility: hidden;
        }

        li.dragging-now::after {
            content: '';
            position: absolute;
            inset: 0px;
            border: 1px dashed grey;
        }
    `,
];
```

### Horizontal sorting

By default, the sorter controller will sort vertically. You can sort your model horizontally by setting the `resolveVerticalDirection` to return false.

```typescript
const MY_SORTER_CONFIG: UmbSorterConfig<MySortEntryType> = {
	...
	resolveVerticalDirection: () => return false,
};
```

### Performing logic when using the controller (TODO: Better title)

Let's say your model has a property sortOrder that you would like to update when the entry is being sorted.
You can add your code logic in the configuration option `performItemInsert` and `performItemRemove`

```typescript
export class MyElement extends UmbElementMixin(LitElement) {
	#sorter = new UmbSorterController(this, {
		...SORTER_CONFIG,
		performItemInsert: ({ item, newIndex }) => {
			console.log(item, newIndex);
			// Perform some logic here to calculate the new sortOrder & save it.
			return true;
		},
		performItemRemove: () => true,
	});
}
```
