a sortable view for flat lists which also supports dragging items into and out of a list
It is based on svelte-drag-and-drop-actions and, consequently, on HTML5 native Drag-and-Drop.
some of its Features:
All examples are live and may be changed on the fly!
svelte-sortable-flat-list-view may also suffer from any bugs in the browser implementations of native HTML drag-and-drop (thinking of Safari 13.0/13.1, f.e.) if they can not be compensated by the authorNPM users: please consider the Github README for the latest description of this package (as updating the docs would otherwise always require a new NPM package version)
Mobile Developers: since many mobile platforms lack support for native HTML5 drag-and-drop, you should consider importing svelte-drag-drop-touch as a polyfill (a simple import of that package will suffice - there is no extra programming needed)
Just a small note: if you like this module and plan to use it, consider "starring" this repository (you will find the "Star" button on the top right of this page), so that I know which of my repositories to take most care of.
npm install svelte-sortable-flat-list-view
svelte-sortable-flat-list-view should be imported in a module context (perhaps together with svelte-drag-drop-touch) and may then be used in your markup:
<script context="module">
import DragDropTouch from 'svelte-drag-drop-touch'
import ListView from 'svelte-sortable-flat-list-view'
</script>
<script>
let List = []
</script>
<ListView {List}/>
More detailled examples for a variety of use cases can be found below.
In addition, this repo also contains a file example_ListView_on_web_page.html which demonstrates how to use a ListView on a web page (i.e., outside of Svelte)
svelte-sortable-flat-list-view emits some Svelte events and exports some types (for TypeScript users) and properties (for anybody), as shown below.
TypeScript programmers may import the following types in order to benefit from static type checking (JavaScript programmers may simply skip this section):
type ListDroppableExtras = { List:any[], Item:any, ItemList:any[] }ListDroppableExtras defines the shape of DroppableExtras (as defined by svelte-drag-and-drop-actions) when a Droppable which is dragged over a list item that may serve as a DropZone comes from this (or another) svelte-sortable-flat-list-view instancetype ListDropZoneExtras = { List:any[], Item:any }ListDropZoneExtras defines the shape of DropZoneExtras (as defined by svelte-drag-and-drop-actions) when a Droppable is dragged over this drop zonesvelte-sortable-flat-list-view exports the following Svelte "props" (shown with TypeScript type annotations - JavaScript users may simply ignore them):
class?:stringclass attribute (to a CSS class name), the list view assumes that you will take over any styling and remove its defaults (see below for more details)style?:stringstyle attribute to set important CSS properties for the list view itself (not its item views). "Important" CSS properties could, f.e., control position and size of a list view and set basic visual parameters such as background, borders or text size and colorList:{}[]List attribute accepts the actual list to be shown. It should be a JavaScript array with arbitrary objects as elements. Note: lists of JavaScript primitives will be rejected!Key?:string|FunctionKey attribute specifies which string to be used as the (unique) "key" of a list item - such "keys" are required by Svelte for proper rendering of lists. Key may either be set to the (fixed) name of a list item property containing the key or to a function which receives a list item and that item's current index in the list and returns that item's key (which must be a string). If omitted, the list item itself is used as its key (after conversion into a string). List item keys must be unique within the whole list - or Svelte will throw an error SelectionLimit?:numberSelectionLimit attribute to an ordinal number, you may set an upper limit for selectionsSelectionList:{}[]SelectionList attribute specifies which elements of List are to be selected in the list view. It must contain elements of List only and should not contain more than SelectionLimit elements (otherwise only the first SelectionLimit elements will be considered and all others removed). If SelectionList is bound to a variable, that variable also reflects any selection changes made within the list viewAttachmentRegion?:stringAttachmentRegion attribute to the HTML you want to be shown in that region - by default, attachment regions are just emptyPlaceholder?:stringPlaceholder attribute to the HTML you want to be shown in that placeholder - by default, the text "(empty list)" is shownwithTransitions:booleanwithTransitions atttribute to falsesortable?:booleansortable attribute to true if you want the list view to support sorting - or false otherwise. By default, sorting is not supported (such list views just support selections)onlyFrom?:stringonlyFrom is an optional, comma-separated list of CSS selectors identifying the inner elements of a list item view, from which a drag operation must be started in order to be allowed. If onlyFrom is missing, no onlyFrom restriction is appliedneverFrom?:stringneverFrom is an optional, comma-separated list of CSS selectors identifying the inner elements of a list item view, from which a drag operation must never be started in order to be allowed. If neverFrom is missing, no neverFrom restriction is appliedonSortRequest?:(x:number,y:number, DroppableExtras:ListDroppableExtras, DropZoneExtras:ListDropZoneExtras) => booleanonSortRequest is an optional callback which (when invoked during sorting) indicates whether the currently dragged list items may be inserted immediately before the currently hovered list element or not. x and y contain the current mouse pointer (or finger) position within the hovered list item, DroppableExtras are the configured "extras" for the currently dragged list item and DropZoneExtras those for the currently hovered one. If onSortRequest is missing, insertion is allowed everywhere in the listonSort?:(beforeItem:any|undefined, ItemList:{}[]) => voidonSort is an optional callback which (when invoked during sorting) performs the actual reordering of list items - it can be used to update the state of the surrounding Svelte application if the default behaviour (which simply updates the given list and emits an event) does not suffice. The callback receives the sequence ItemList of list items to be moved (given in their original order) and the list item beforeItem before which the dragged list items should be inserted - if beforeItem is undefined, the dragged items should just be appended to the listOperations?:stringOperations is either a blank-separated list of drop operations ('copy', 'move' or 'link'), the keyword all (which includes all three available operations) or the keyword none (which effectively suppresses dropping) and specifies which kind of data transfer list items support when dropped outside of their list - by default, no such drop is allowed DataToOffer?:DataOfferSetDataToOffer is a plain JavaScript object whose keys represent the various data formats a droppable list item supports and whose corresponding values contain the transferrable data in that format. Often, the given keys denote MIME formats (which simplifies data transfer between different applications) or contain the special value "DownloadURL", but - in principle - any string (except none) may be usedTypesToAccept?:TypeAcceptanceSetTypesToAccept is a plain JavaScript object whose keys represent the various data formats a list item serving as drop zone may accept and whose corresponding values contain a blank-separated, perhaps empty, list of supported drop operations for that format. Often, the given keys denote MIME formats (which simplifies data transfer between different applications) or contain the special value "DownloadURL", but - in principle - any string (except none) may be used. Note: since native HTML5 drag-and-drop implementations often fail reporting a correct "dropEffect", the given drop operations can not be properly checked - with the exception, that types with empty operation lists will never be acceptedonDroppedOutside?:(x:number,y:number, Operation:DropOperation, TypeTransferred:string|undefined, DataTransferred:any|undefined, DropZoneExtras:any, DroppableExtras:ListDroppableExtras) => voidonDroppedOutside is an optional callback which is invoked when one or multiple items of this list were dropped somewhere outside this list. It may be used for any housekeeping required - or even for performing the actual data transfer in case that the foreign drop zone is not able to do so. x and y contain the mouse pointer (or finger) position within the foreign drop zone when the list item(s) were dropped, Operation contains the accepted data transfer operation (i.e., 'copy', 'move' or 'link'), TypeTransferred the accepted type and DataTransferred the actually accepted data, DropZoneExtras are the configured "extras" for the foreign drop zone and DroppableExtras those for the actually dragged list item. TypeTransferred and DataTransferred may both be undefined in order to indicate that there values are unknown. If onDroppedOutside is missing, it simply does not get called and the actual drop zone has to perform the data transfer itselfonOuterDropRequest?:(x:number,y:number, Operation:DropOperation, offeredTypeList:string[], DroppableExtras:any, DropZoneExtras:ListDropZoneExtras) => booleanonDroppedOutside is an optional callback which is invoked when a draggable object that is not already an item of this list is dragged over an item of this list. It should return true if dropping is allowed or false otherwise. x and y contain the current mouse pointer (or finger) position within the list item that should serve as a drop zone, Operation the requested data transfer operation (i.e., 'copy', 'move' or 'link') and offeredTypeList a list of types the dragged object offers. DroppableExtras are the configured "extras" for the currently dragged (foreign) object and DropZoneExtras those for the currently hovered list item. If onOuterDropRequest is missing the permission to drop or not to drop is determined by comparing the requested data transfer types and operations with those configured for this listonDropFromOutside?:(x:number,y:number, Operation:DropOperation, DataOffered:DataOfferSet, DroppableExtras:any, DropZoneExtras:ListDropZoneExtras) => string | undefinedonDropFromOutside is an optional callback which is invoked after a draggable object that is not already an item of this list was dropped onto an item of this list. It should either return the actually accepted data type (i.e., one of the keys from DataOffered) or none if the drop is not acceptable. If undefined is returned instead, the drop operation is considered accepted, but the accepted data type remains unknwon. x and y contain the current mouse pointer (or finger) position within the list item that served as a drop zone, Operation the requested data transfer operation (i.e., 'copy', 'move' or 'link') and DataOffered a JavaScript object, whose keys represent the various data formats offered and whose corresponding values contain the offered data in that format. DroppableExtras are the configured "extras" for the currently dragged (foreign) object and DropZoneExtras those for the list item acting as drop zone. If onDropFromOutside is missing, the list view only accepts items that match the configured data transfer types and operations for this list and look like items of another svelte-sortable-flat-list-viewHoldDelay?:numberHoldDelay milliseconds without much movement, the onDroppableHold callback is invoked (if it exists). The property is optional: when missing, onDroppableHold will never be calledonDroppableHold?: (x:number,y:number, DroppableExtras:any, DropZoneExtras:ListDropZoneExtras) => voidonDroppableHold is an optional callback which (when invoked) indicates that a droppable whose data is at least partially acceptable, stood still for at least HoldDelay milliseconds within the bounds of a list item view. x and y contain the current coordinates of the mouse or finger relative to the list item view, DroppableExtras are any Extras configured for the held droppable and DropZoneExtras any Extras configured for the list item view that acts as a drop zone. Warning: be careful with what to do within that callback - if you disturb the flow of events (e.g., by invoking window.alert), the visual feedback for the list view may get mixed up!PanSensorWidth?:numbersvelte-sortable-flat-list-view supports automatic scrolling (aka "panning") of only partially visible lists while dragging. PanSensorWidth is an optional ordinal number (defaulting to 20) which specifies the width (in pixels) of the horizontal pan sensor area: panning starts as soon as the mouse pointer (or finger) gets closer than the given number of pixels to the left or right border of the list view. If set to 0, no horizontal panning will be performedPanSensorHeight?:numbersvelte-sortable-flat-list-view supports automatic scrolling (aka "panning") of only partially visible lists while dragging. PanSensorHeight is an optional ordinal number (defaulting to 20) which specifies the height (in pixels) of the vertical pan sensor area: panning starts as soon as the mouse pointer (or finger) gets closer than the given number of pixels to the upper or lower border of the list view. If set to 0, no vertical panning will be performedPanSpeed?:numbersvelte-sortable-flat-list-view supports automatic scrolling (aka "panning") of only partially visible lists while dragging. PanSpeed is an optional ordinal number (defaulting to 10) which specifies the "speed" of panning - values in the range of 10...20 are reasonable choices, but it is always a good idea to make this parameter configurable for the users of your application. If set to 0, no panning will be performed'selected-item' (const Item:any = Event.detail)selected-item is emitted whenever a list item becomes selected, Event.detail refers to the newly selected item'deselected-item' (const Item:any = Event.detail)deselected-item is emitted whenever a list item becomes deselected, Event.detail refers to the no longer selected item'sorted-items' (const [sortedItems:any[],InsertionIndex:number] = Event.detail)sorted-items is emitted after one or multiple list items have been moved to new positions within their list using the default approach implemented by svelte-sortable-flat-list-view itself (i.e., not by a given onSort callback). Event.detail contains a list with two elements: the first one being the list of repositioned items and the second one being the new index of the first repositioned item (all items are placed one after the other)'inserted-items' (const [ItemsToBeInserted:any[],InsertionIndex:number] = Event.detail)inserted-items is emitted after one or multiple items of another list have been moved into this one using the default approach implemented by svelte-sortable-flat-list-view itself (i.e., not by a given onDropFromOutside callback). Event.detail contains a list with two elements: the first one being the list of inserted (i.e., new) items and the second one being the index of the first inserted item (all items are placed one after the other)'removed-items' (const ItemList:any[] = Event.detail)removed-items is emitted after one or multiple items of this list have been dropped onto another drop zone using the default approach implemented by svelte-sortable-flat-list-view itself (i.e., not by a given onDroppedOutside callback). Event.detail contains a list of all removed list itemsWithout explicitly specifying a CSS class for a list view, standard styling is applied. Otherwise, the following selectors may be used to define custom list view styling (assuming that you instantiate your list view with a class attribute containing ListView, like so: <sortableFlatListView class="ListView" .../>):
ListViewListView > .ListItemView selector, this also allows for horizontal or even two-dimensional list viewsListView > .ListItemViewListView selector itself, this also allows for horizontal or even two-dimensional list viewsListView > .ListItemView > *ListView:not(.transitioning) > .ListItemView:hover:not(.dragged)transitioning is a class added to all list item view elements which are going to appear or disappear - and, usually, you don't want to apply the styling of hovered elements to those)ListView:not(.transitioning) > .ListItemView.selected:not(.dragged)transitioning is a class added to all list item view elements which are going to appear or disappear - and, usually, you don't want to apply the styling of selected elements to those)ListView > .ListItemView.draggedListView > .ListItemView.hovered:not(.dragged)ListView > .AttachmentRegionListView > .AttachmentRegion.hoveredListView > .PlaceholderImportant: whenever you change the style of a list item during dragging, you should take great care that HTML5 drag-and-drop still recognizes the styled list item as a draggable or drop zone. More precisely: you should avoid to move drop zones away from the mouse pointer (or finger, resp.), hide draggables or drop zones completely (e.g., with display:none) or change their sensitivity to mouse and touch events (with pointer-events:none)
There is an example (ListView with custom CSS classes) which specifically demonstrates how to style a list view using the abovementioned selectors.
A few examples may help understanding how svelte-sortable-flat-list-view may be used.
You may easily build this package yourself.
Just install NPM according to the instructions for your platform and follow these steps:
npm install in order to install the complete build environmentnpm run build to create a new buildSee the author's build-configuration-study for a general description of his build environment.