Schedule & Unschedule from External Lists
Usage
theme="ios" You can turn auto theming on and let it decide based on the platform.
Usage
themeVariant="light" You can turn auto dark mode on based on system settings.
Usage
clickToCreate={true}
// click to create is on dragToCreate={true}
// drag to create is on dragToMove={true}
// reordering is on dragToResize={true}
// resizing is on eventDelete={true}
// deleting is on Fine-tune drag & drop with these options, which are false by default.
Usage
locale={localeEn} Selecting the locale loads the localized settings and the translated UI text.
Schedule & Unschedule from External Lists
Events and resources can be scheduled by dragging and dropping an external item onto the timeline with Mobiscroll draggable. In order for that to work you will need to have two things set up:
- Enable the timeline to receive external events and/or resources by setting
externalDropand/orexternalResourceDroptotrue. - Initialize the external events or/and resources (containers) as
draggablecomponents.
Use the Draggable component to specify a skeleton event through its dragData option and reference the draggable container in the element option. The dragData accepts a full event definition that will be added to the event calendar on drop. If omitted, a default event will be created.
Mobiscroll provides built-in support for two widely used reorderable drag-and-drop list libraries: SortableJS and Dragula. If you are already using any of these libraries to reorder list items, they can be seamlessly integrated with the timeline. This integration enables a smooth workflow where items can be dragged from external lists and scheduled directly onto the calendar.
Events and resources can be created and scheduled by dragging items from third-party lists into the event calendar. To enable this behavior you will need to:
- Allow the timeline to receive external drops by setting
externalDropor/andexternalResourceDroptotrue. - Use the
sortableJsDraggableordragulaDraggableplugins to connect the third-party list with the scheduler. The event data will be read from the dragged element'sdata-drag-dataattribute, or the plugin's options expose aneventDatafunction where the event definition (title, start, end, resource, etc.) can be specified.
You can then handle the calendars lifecycle events such as onEventCreate, onEventCreated or onEventCreateFailed to run custom logic (e.g. showing a toast) when a drop succeeds or fails.
Additionally events and resources can be unscheduled by dragging them out from the timeline and dropping them onto an external drop container. To activate this, you will need to:
- Enable the timeline to allow dragging events or resources out by setting
externalDragorexternalResourceDragtotrue. - Initialize the
Events can also be dropped on another event calendar with externalDrop enabled.
When an event is dropped into an external drop container or another calendar, it will be deleted from the original calendar and the onEventDelete will be fired.
You can also use the onEventDragLeave and onEventDragEnter, and the drop container's onItemDragEnter and onItemDragLeave events to provide visual feedback or running custom logic during drag.
Learn more from the external drag & drop documentation.
Unscheduling events or resources to SortableJS and Dragula lists Dropping events or resources from the Eventcalendar to SortableJS and Dragula lists is also possible with the sortableJsDraggable and dragulaDraggable plugins. To enable this behavior you will need to set the following under the options configuration:
- Allow the list to receive external drops by setting
externalDroptotrue - Use the
onExternalDropcallback to update the content of the third-party list. The function arguments return theafterElement- the list element before which the clone is dropped,container- the list container,dragData- the dragged event data,position- the index where the clone is dropped on the list.
For details, and option lists see the Third-party dragging support section in the documentation
Demo
The live demo didn't load.
Try it on demo.mobiscroll.com
Code
View code on GitHub
import {
Draggable,
dragulaDraggable,
Dropcontainer,
Eventcalendar,
setOptions,
sortableJsDraggable,
Toast ,
} from '@mobiscroll/react';
import dragula from 'dragula';
import PropTypes from 'prop-types';
import { useCallback, useEffect, useMemo, useState } from 'react';
import Sortable from 'sortablejs';
import 'dragula/dist/dragula.css';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
function Task({ data, isDraggable }) {
const [draggable, setDraggable] = useState();
const setDragElm = useCallback((elm) => {
setDraggable(elm);
}, []);
const eventLength = Math.round(Math.abs(new Date(data.end).getTime() - new Date(data.start).getTime()) / (60 * 60 * 1000));
return (
<div
className="mds-drag-drop-sort-task"
ref={isDraggable && setDragElm}
style={{ background: data.color }}
data-drag-data={!isDraggable && JSON.stringify(data)}
>
<div>{data.title}</div>
<div>{eventLength + ' hour' + (eventLength > 1 ? 's' : '')}</div>
{isDraggable && <Draggable dragData={data} element={draggable} />}
</div>
);
}
Task.propTypes = {
data: PropTypes.object.isRequired,
isDraggable: PropTypes.bool,
};
function Resource({ data, isDraggable }) {
const [draggable, setDraggable] = useState();
const setDragElm = useCallback((elm) => {
setDraggable(elm);
}, []);
return (
<div
ref={isDraggable && setDragElm}
className="mds-drag-drop-sort-task"
style={{ background: '#80808099' }}
data-drag-data={!isDraggable && JSON.stringify(data)}
>
<div>{data.name}</div>
{isDraggable && <Draggable dragData={data} element={draggable} type="resource" />}
</div>
);
}
Resource.propTypes = {
data: PropTypes.object.isRequired,
isDraggable: PropTypes.bool,
};
function App() {
const [dropCont, setDropCont] = useState();
const [sortableTaskCont, setSortableTaskCont] = useState();
const [dragulaTaskCont, setDragulaTaskCont] = useState();
const [sortableResourceCont, setSortableResourceCont] = useState();
const [dragulaResourceCont, setDragulaResourceCont] = useState();
const [isToastOpen, setToastOpen] = useState(false);
const [toastMessage, setToastMessage] = useState();
const [myDraggableTasks, setDraggableTasks] = useState([
{
id: 'draggable-1',
title: 'Task 1',
color: '#cf4343',
start: '2026-10-26T08:00',
end: '2026-10-26T09:30',
},
{
id: 'draggable-2',
title: 'Task 2',
color: '#cf4343',
start: '2026-10-26T08:00',
end: '2026-10-26T10:00',
},
{
id: 'draggable-3',
title: 'Task 3',
color: '#cf4343',
start: '2026-10-26T10:00',
end: '2026-10-26T14:00',
},
{
id: 'draggable-4',
title: 'Task 4',
color: '#cf4343',
start: '2026-10-26T12:00',
end: '2026-10-26T18:00',
},
]);
const [mySortableTasks, setSortableTasks] = useState([
{
id: 'sortable-1',
title: 'Task 5',
color: '#d1891f',
start: '2026-10-26T08:00',
end: '2026-10-26T09:30',
},
{
id: 'sortable-2',
title: 'Task 6',
color: '#d1891f',
start: '2026-10-26T12:00',
end: '2026-10-26T15:00',
},
{
id: 'sortable-3',
title: 'Task 7',
color: '#d1891f',
start: '2026-10-26T08:30',
end: '2026-10-26T11:00',
},
{
id: 'sortable-4',
title: 'Task 8',
color: '#d1891f',
start: '2026-10-26T16:00',
end: '2026-10-26T21:00',
},
]);
const [myDragulaTasks, setDragulaTasks] = useState([
{
id: 'dragula-1',
title: 'Task 9',
color: '#1ca11a',
start: '2026-10-26T08:00',
end: '2026-10-26T09:30',
},
{
id: 'dragula-2',
title: 'Task 10',
color: '#1ca11a',
start: '2026-10-26T12:00',
end: '2026-10-26T15:00',
},
{
id: 'dragula-3',
title: 'Task 11',
color: '#1ca11a',
start: '2026-10-26T08:30',
end: '2026-10-26T11:00',
},
{
id: 'dragula-4',
title: 'Task 12',
color: '#1ca11a',
start: '2026-10-26T16:00',
end: '2026-10-26T20:30',
},
]);
const [myDraggableResources, setDraggableResources] = useState([
{
id: 'draggable-1',
name: 'Resource 1',
},
{
id: 'draggable-2',
name: 'Resource 2',
},
{
id: 'draggable-3',
name: 'Resource 3',
},
{
id: 'draggable-4',
name: 'Resource 4',
},
]);
const [mySortableResources, setSortableResources] = useState([
{
id: 'sortable-1',
name: 'Resource 5',
},
{
id: 'sortable-2',
name: 'Resource 6',
},
{
id: 'sortable-3',
name: 'Resource 7',
},
{
id: 'sortable-4',
name: 'Resource 8',
},
]);
const [myDragulaResources, setDragulaResources] = useState([
{
id: 'dragula-1',
name: 'Resource 9',
},
{
id: 'dragula-2',
name: 'Resource 10',
},
{
id: 'dragula-3',
name: 'Resource 11',
},
{
id: 'dragula-4',
name: 'Resource 12',
},
]);
const myResources = useMemo(
() => [
{ name: 'Resource A', id: 'res-1' },
{ name: 'Resource B', id: 'res-2' },
{ name: 'Resource C', id: 'res-3' },
{ name: 'Resource D', id: 'res-4' },
{ name: 'Resource E', id: 'res-5' },
],
[],
);
const myView = useMemo(
() => ({
timeline: { type: 'day' },
}),
[],
);
const handleEventCreated = useCallback((args) => {
if (args.action === 'externalDrop') {
setDraggableTasks((tasks) => tasks.filter((item) => item.id !== args.event.id));
setSortableTasks((tasks) => tasks.filter((item) => item.id !== args.event.id));
setDragulaTasks((tasks) => tasks.filter((item) => item.id !== args.event.id));
setToastMessage(args.event.title + ' added');
setToastOpen(true);
}
}, []);
const handleEventDeleted = useCallback((args) => {
setToastMessage(args.event.title + ' unscheduled');
setToastOpen(true);
}, []);
const handleResourceCreated = useCallback((args) => {
if (args.type === 'onResourceCreated') {
setDraggableResources((resources) => resources.filter((item) => item.id !== args.resource.id));
setSortableResources((resources) => resources.filter((item) => item.id !== args.resource.id));
setDragulaResources((resources) => resources.filter((item) => item.id !== args.resource.id));
setToastMessage(args.resource.name + ' added');
setToastOpen(true);
}
}, []);
const handleItemDrop = useCallback((args) => {
if (args.data) {
setDraggableTasks((tasks) => [...tasks, args.data]);
}
}, []);
const handleToastClose = useCallback(() => {
setToastOpen(false);
}, []);
useEffect(() => {
let sortableTaskInstance;
if (sortableTaskCont) {
sortableTaskInstance = new Sortable(sortableTaskCont, {
animation: 150,
forceFallback: true,
});
sortableJsDraggable.init(sortableTaskInstance, {
cloneSelector: '.sortable-drag',
externalDrop: true,
onExternalDrop: (a) => {
const dragData = a.dragData;
setSortableTasks((prev) => {
const newTasks = [...prev];
newTasks.splice(a.position, 0, dragData);
return newTasks;
});
},
});
}
let sortableResourceInstance;
if (sortableResourceCont) {
sortableResourceInstance = new Sortable(sortableResourceCont, {
animation: 150,
forceFallback: true,
});
sortableJsDraggable.init(sortableResourceInstance, {
cloneSelector: '.sortable-drag',
type: 'resource',
});
}
let drake1;
if (dragulaTaskCont) {
drake1 = dragula([dragulaTaskCont]);
dragulaDraggable.init(drake1, {
externalDrop: true,
onExternalDrop: (a) => {
const dragData = a.dragData;
setDragulaTasks((prev) => {
const newTasks = [...prev];
newTasks.splice(a.position, 0, dragData);
return newTasks;
});
},
});
}
let drake2;
if (dragulaResourceCont) {
drake2 = dragula([dragulaResourceCont]);
dragulaDraggable.init(drake2, {
type: 'resource',
});
}
return () => {
if (sortableTaskInstance) {
sortableTaskInstance.destroy();
}
if (sortableResourceInstance) {
sortableResourceInstance.destroy();
}
if (drake1) {
drake1.destroy();
}
if (drake2) {
drake2.destroy();
}
};
}, [dragulaTaskCont, dragulaResourceCont, sortableTaskCont, sortableResourceCont]);
return (
<div className="mbsc-grid mbsc-no-padding mds-drag-drop-sort mds-full-height">
<div className="mbsc-row mds-full-height">
<div className="mbsc-col-sm-3 mds-drag-drop-sort-container-wrapper mds-full-height">
<div className="mbsc-txt-muted mds-third-party-title">Mobiscroll draggable</div>
<div className="mbsc-flex">
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0" ref={setDropCont}>
<div className="mbsc-txt-muted mds-third-party-list-title">Event list</div>
<Dropcontainer onItemDrop={handleItemDrop} element={dropCont}>
{myDraggableTasks.map((task) => (
<Task key={task.id} data={task} isDraggable />
))}
</Dropcontainer>
</div>
</div>
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Resource list</div>
{myDraggableResources.map((res) => (
<Resource key={res.id} data={res} isDraggable />
))}
</div>
</div>
</div>
<div className="mbsc-txt-muted mds-third-party-title">SortableJS (externally sortable)</div>
<div className="mbsc-flex">
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Event list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setSortableTaskCont}>
{mySortableTasks.map((task) => (
<Task key={task.id} data={task} />
))}
</div>
</div>
</div>
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Resource list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setSortableResourceCont}>
{mySortableResources.map((res) => (
<Resource key={res.id} data={res} />
))}
</div>
</div>
</div>
</div>
<div className="mbsc-txt-muted mds-third-party-title">Dragula (externally sortable)</div>
<div className="mbsc-flex">
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Event list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setDragulaTaskCont}>
{myDragulaTasks.map((task) => (
<Task key={task.id} data={task} />
))}
</div>
</div>
</div>
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Resource list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setDragulaResourceCont}>
{myDragulaResources.map((res) => (
<Resource key={res.id} data={res} />
))}
</div>
</div>
</div>
</div>
</div>
<div className="mbsc-col-sm-9 mds-drag-drop-sort-calendar mds-full-height">
<Eventcalendar
clickToCreate={ }
dragToCreate={ }
dragToMove={ }
dragToResize={ }
eventDelete={ }
view={myView}
resources={myResources}
dragToMove={true}
dragToCreate={true}
externalDrop={true}
externalDrag={true}
externalResourceDrop={true}
onEventCreated={handleEventCreated}
onResourceCreated={handleResourceCreated}
onEventDelete={handleEventDeleted}
/>
</div>
</div>
<Toast message={toastMessage} isOpen={isToastOpen} onClose={handleToastClose} />
</div>
);
}
export default App;
import {
Draggable,
dragulaDraggable,
Dropcontainer,
Eventcalendar,
MbscCalendarEvent,
MbscEventcalendarView,
MbscEventCreatedEvent,
MbscEventDeletedEvent,
MbscExternalDropEvent,
MbscItemDragEvent,
MbscResource,
MbscResourceCreatedEvent,
setOptions,
sortableJsDraggable,
Toast ,
} from '@mobiscroll/react';
import dragula, { Drake } from 'dragula';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import Sortable from 'sortablejs';
import 'dragula/dist/dragula.css';
setOptions({
locale: ,
theme: ' ',
themeVariant: ' '
});
const Task = (props: { data: MbscCalendarEvent; isDraggable?: boolean }) => {
const data = props.data;
const isDraggable = props.isDraggable;
const [draggable, setDraggable] = useState<HTMLDivElement>();
const setDragElm = useCallback((elm: HTMLDivElement) => {
setDraggable(elm);
}, []);
const eventLength = Math.round(
Math.abs(new Date(data.end as string).getTime() - new Date(data.start as string).getTime()) / (60 * 60 * 1000),
);
return (
<div
className="mds-drag-drop-sort-task"
ref={isDraggable ? setDragElm : null}
style={{ background: data.color }}
data-drag-data={!isDraggable && JSON.stringify(data)}
>
<div>{data.title}</div>
<div>{eventLength + ' hour' + (eventLength > 1 ? 's' : '')}</div>
{isDraggable && <Draggable dragData={data} element={draggable} />}
</div>
);
};
const Resource = (props: { data: MbscResource; isDraggable?: boolean }) => {
const data = props.data;
const isDraggable = props.isDraggable;
const [draggable, setDraggable] = useState<HTMLDivElement>();
const setDragElm = useCallback((elm: HTMLDivElement) => {
setDraggable(elm);
}, []);
return (
<div
ref={isDraggable ? setDragElm : null}
className="mds-drag-drop-sort-task"
style={{ background: '#80808099' }}
data-drag-data={!isDraggable && JSON.stringify(data)}
>
<div>{data.name}</div>
{isDraggable && <Draggable dragData={data} element={draggable} type="resource" />}
</div>
);
};
const App: FC = () => {
const [dropCont, setDropCont] = useState<HTMLDivElement | null>();
const [sortableTaskCont, setSortableTaskCont] = useState<HTMLDivElement | null>();
const [dragulaTaskCont, setDragulaTaskCont] = useState<HTMLDivElement | null>();
const [sortableResourceCont, setSortableResourceCont] = useState<HTMLDivElement | null>();
const [dragulaResourceCont, setDragulaResourceCont] = useState<HTMLDivElement | null>();
const [isToastOpen, setToastOpen] = useState<boolean>(false);
const [toastMessage, setToastMessage] = useState<string>('');
const [myDraggableTasks, setDraggableTasks] = useState<MbscCalendarEvent[]>([
{
id: 'draggable-1',
title: 'Task 1',
color: '#cf4343',
start: '2026-10-26T08:00',
end: '2026-10-26T09:30',
},
{
id: 'draggable-2',
title: 'Task 2',
color: '#cf4343',
start: '2026-10-26T08:00',
end: '2026-10-26T10:00',
},
{
id: 'draggable-3',
title: 'Task 3',
color: '#cf4343',
start: '2026-10-26T10:00',
end: '2026-10-26T14:00',
},
{
id: 'draggable-4',
title: 'Task 4',
color: '#cf4343',
start: '2026-10-26T12:00',
end: '2026-10-26T18:00',
},
]);
const [mySortableTasks, setSortableTasks] = useState<MbscCalendarEvent[]>([
{
id: 'sortable-1',
title: 'Task 5',
color: '#d1891f',
start: '2026-10-26T08:00',
end: '2026-10-26T09:30',
},
{
id: 'sortable-2',
title: 'Task 6',
color: '#d1891f',
start: '2026-10-26T12:00',
end: '2026-10-26T15:00',
},
{
id: 'sortable-3',
title: 'Task 7',
color: '#d1891f',
start: '2026-10-26T08:30',
end: '2026-10-26T11:00',
},
{
id: 'sortable-4',
title: 'Task 8',
color: '#d1891f',
start: '2026-10-26T16:00',
end: '2026-10-26T21:00',
},
]);
const [myDragulaTasks, setDragulaTasks] = useState<MbscCalendarEvent[]>([
{
id: 'dragula-1',
title: 'Task 9',
color: '#1ca11a',
start: '2026-10-26T08:00',
end: '2026-10-26T09:30',
},
{
id: 'dragula-2',
title: 'Task 10',
color: '#1ca11a',
start: '2026-10-26T12:00',
end: '2026-10-26T15:00',
},
{
id: 'dragula-3',
title: 'Task 11',
color: '#1ca11a',
start: '2026-10-26T08:30',
end: '2026-10-26T11:00',
},
{
id: 'dragula-4',
title: 'Task 12',
color: '#1ca11a',
start: '2026-10-26T16:00',
end: '2026-10-26T20:30',
},
]);
const [myDraggableResources, setDraggableResources] = useState<MbscResource[]>([
{
id: 'draggable-1',
name: 'Resource 1',
},
{
id: 'draggable-2',
name: 'Resource 2',
},
{
id: 'draggable-3',
name: 'Resource 3',
},
{
id: 'draggable-4',
name: 'Resource 4',
},
]);
const [mySortableResources, setSortableResources] = useState<MbscResource[]>([
{
id: 'sortable-1',
name: 'Resource 5',
},
{
id: 'sortable-2',
name: 'Resource 6',
},
{
id: 'sortable-3',
name: 'Resource 7',
},
{
id: 'sortable-4',
name: 'Resource 8',
},
]);
const [myDragulaResources, setDragulaResources] = useState<MbscResource[]>([
{
id: 'dragula-1',
name: 'Resource 9',
},
{
id: 'dragula-2',
name: 'Resource 10',
},
{
id: 'dragula-3',
name: 'Resource 11',
},
{
id: 'dragula-4',
name: 'Resource 12',
},
]);
const myResources = useMemo<MbscResource[]>(
() => [
{ name: 'Resource A', id: 'res-1' },
{ name: 'Resource B', id: 'res-2' },
{ name: 'Resource C', id: 'res-3' },
{ name: 'Resource D', id: 'res-4' },
{ name: 'Resource E', id: 'res-5' },
],
[],
);
const myView = useMemo<MbscEventcalendarView>(
() => ({
timeline: { type: 'day' },
}),
[],
);
const handleEventCreated = useCallback((args: MbscEventCreatedEvent) => {
if (args.action === 'externalDrop') {
setDraggableTasks((tasks) => tasks.filter((item) => item.id !== args.event.id));
setSortableTasks((tasks) => tasks.filter((item) => item.id !== args.event.id));
setDragulaTasks((tasks) => tasks.filter((item) => item.id !== args.event.id));
setToastMessage(args.event.title + ' added');
setToastOpen(true);
}
}, []);
const handleEventDeleted = useCallback((args: MbscEventDeletedEvent) => {
setToastMessage(args.event.title + ' unscheduled');
setToastOpen(true);
}, []);
const handleResourceCreated = useCallback((args: MbscResourceCreatedEvent) => {
if (args.type === 'onResourceCreated') {
setDraggableResources((resources) => resources.filter((item) => item.id !== args.resource.id));
setSortableResources((resources) => resources.filter((item) => item.id !== args.resource.id));
setDragulaResources((resources) => resources.filter((item) => item.id !== args.resource.id));
setToastMessage(args.resource.name + ' added');
setToastOpen(true);
}
}, []);
const handleItemDrop = useCallback((args: MbscItemDragEvent) => {
if (args.data) {
setDraggableTasks((tasks) => [...tasks, args.data]);
}
}, []);
const handleToastClose = useCallback(() => {
setToastOpen(false);
}, []);
useEffect(() => {
let sortableTaskInstance: Sortable;
if (sortableTaskCont) {
sortableTaskInstance = new Sortable(sortableTaskCont, {
animation: 150,
forceFallback: true,
});
sortableJsDraggable.init(sortableTaskInstance, {
cloneSelector: '.sortable-drag',
externalDrop: true,
onExternalDrop: (a: MbscExternalDropEvent) => {
const dragData = a.dragData;
setSortableTasks((prev) => {
const newTasks = [...prev];
newTasks.splice(a.position, 0, dragData);
return newTasks;
});
},
});
}
let sortableResourceInstance: Sortable;
if (sortableResourceCont) {
sortableResourceInstance = new Sortable(sortableResourceCont, {
animation: 150,
forceFallback: true,
});
sortableJsDraggable.init(sortableResourceInstance, {
cloneSelector: '.sortable-drag',
type: 'resource',
});
}
let drake1: Drake;
if (dragulaTaskCont) {
drake1 = dragula([dragulaTaskCont]);
dragulaDraggable.init(drake1, {
externalDrop: true,
onExternalDrop: (a: MbscExternalDropEvent) => {
const dragData = a.dragData;
setDragulaTasks((prev) => {
const newTasks = [...prev];
newTasks.splice(a.position, 0, dragData);
return newTasks;
});
},
});
}
let drake2: Drake;
if (dragulaResourceCont) {
drake2 = dragula([dragulaResourceCont]);
dragulaDraggable.init(drake2, {
type: 'resource',
});
}
return () => {
if (sortableTaskInstance) {
sortableTaskInstance.destroy();
}
if (sortableResourceInstance) {
sortableResourceInstance.destroy();
}
if (drake1) {
drake1.destroy();
}
if (drake2) {
drake2.destroy();
}
};
}, [dragulaTaskCont, dragulaResourceCont, sortableTaskCont, sortableResourceCont]);
return (
<div className="mbsc-grid mbsc-no-padding mds-drag-drop-sort mds-full-height">
<div className="mbsc-row mds-full-height">
<div className="mbsc-col-sm-3 mds-drag-drop-sort-container-wrapper mds-full-height">
<div className="mbsc-txt-muted mds-third-party-title">Mobiscroll draggable</div>
<div className="mbsc-flex">
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0" ref={setDropCont}>
<div className="mbsc-txt-muted mds-third-party-list-title">Event list</div>
<Dropcontainer onItemDrop={handleItemDrop} element={dropCont}>
{myDraggableTasks.map((task) => (
<Task key={task.id} data={task} isDraggable />
))}
</Dropcontainer>
</div>
</div>
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Resource list</div>
{myDraggableResources.map((res) => (
<Resource key={res.id} data={res} isDraggable />
))}
</div>
</div>
</div>
<div className="mbsc-txt-muted mds-third-party-title">SortableJS (externally sortable)</div>
<div className="mbsc-flex">
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Event list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setSortableTaskCont}>
{mySortableTasks.map((task) => (
<Task key={task.id} data={task} />
))}
</div>
</div>
</div>
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Resource list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setSortableResourceCont}>
{mySortableResources.map((res) => (
<Resource key={res.id} data={res} />
))}
</div>
</div>
</div>
</div>
<div className="mbsc-txt-muted mds-third-party-title">Dragula (externally sortable)</div>
<div className="mbsc-flex">
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Event list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setDragulaTaskCont}>
{myDragulaTasks.map((task) => (
<Task key={task.id} data={task} />
))}
</div>
</div>
</div>
<div className="mbsc-col-sm-6 mbsc-flex-col">
<div className="mds-drag-drop-sort-container mbsc-flex-col mbsc-flex-1-0">
<div className="mds-third-party-list-title mbsc-txt-muted">Resource list</div>
<div className="mbsc-flex-col mbsc-flex-1-0" ref={setDragulaResourceCont}>
{myDragulaResources.map((res) => (
<Resource key={res.id} data={res} />
))}
</div>
</div>
</div>
</div>
</div>
<div className="mbsc-col-sm-9 mds-drag-drop-sort-calendar mds-full-height">
<Eventcalendar
clickToCreate={ }
dragToCreate={ }
dragToMove={ }
dragToResize={ }
eventDelete={ }
view={myView}
externalDrop={true}
externalResourceDrop={true}
dragToMove={true}
dragToCreate={true}
externalDrag={true}
onEventCreated={handleEventCreated}
onResourceCreated={handleResourceCreated}
onEventDeleted={handleEventDeleted}
resources={myResources}
/>
</div>
</div>
<Toast message={toastMessage} isOpen={isToastOpen} onClose={handleToastClose} />
</div>
);
};
export default App;
.mds-full-height {
height: 100%;
}
.mds-drag-drop-sort-calendar {
border-left: 1px solid #ccc;
}
.mds-drag-drop-sort .mbsc-timeline-resource-col {
width: 100px;
}
.mds-drag-drop-sort-container {
margin: 5px;
}
.mds-drag-drop-sort-container-wrapper {
overflow: auto;
}
.mds-drag-drop-sort-task {
margin-top: 5px;
padding: 10px 12px 10px 12px;
align-content: center;
touch-action: none;
color: #fff;
border-radius: 8px;
flex: 0 0 4.2em;
font-family:
-apple-system,
Segoe UI,
Roboto,
sans-serif;
font-size: 12px;
}
.mds-third-party-title {
margin-top: 12px;
padding: 0 10px;
font-size: 16px;
font-weight: 600;
}
.mds-third-party-list-title {
font-weight: 600;
padding: 0 5px;
font-size: 12px;
text-transform: none;
}
.mds-drag-drop-sort-duration {
font-size: 10px;
}