|
1 | 1 | # Changelog |
2 | 2 |
|
| 3 | +## [Unreleased] |
| 4 | + |
| 5 | +A significant update with multiple improvements and some breaking changes. Most |
| 6 | +notably, provides better support for multi-sortable-list use cases. |
| 7 | + |
| 8 | +### Added |
| 9 | + |
| 10 | +- Seamlessly handle re-creation of draggables and droppables during active drag. |
| 11 | + |
| 12 | + In some use cases (such as a kanban board), an item may be moved from one |
| 13 | + container to another during an active drag. In turn this could cause related |
| 14 | + draggables and droppables to be removed and re-added. Previously this would |
| 15 | + just break (with the active draggable disappearing on its removal). Now, it is |
| 16 | + handled by deferring the cleanup of removed draggables and droppables with a |
| 17 | + queued microtask. If a draggable/droppable with matching `id` is added before |
| 18 | + the microtask is called, then it will not clean up and instead persist |
| 19 | + naturally with the new layout and node information. |
| 20 | + |
| 21 | + As part of this, the active draggable's transform is automatically adjusted by |
| 22 | + a temporary internal modifier to account for any difference between the |
| 23 | + previous node layout and the new node layout. This avoids jumping or |
| 24 | + misalignment during the drag that would otherwise be caused by the change in |
| 25 | + underlying node layout. In future this modifier interface may be exposed for |
| 26 | + other use cases. |
| 27 | + |
| 28 | + All layouts are also recomputed if any draggable is active when a new item is |
| 29 | + added. |
| 30 | + |
| 31 | +- Add a basic debugger to help visualise draggable and droppable positions. |
| 32 | + Emphasise active items in debugger. To use, place `<DragDropDebugger>` within |
| 33 | + a `<DragDropProvider>` hierarchy. |
| 34 | + |
| 35 | + Note: droppable positions are rendered untransformed to better reflect |
| 36 | + underlying logic (as droppable transforms are not currently considered in the |
| 37 | + collision detectors). |
| 38 | + |
| 39 | +- Add `transformed` helper property on items. Rather than calling |
| 40 | + `transformLayout(layout, transform)` explicitly, it is now possible to do |
| 41 | + `draggable.transformed` (or `droppable.transformed`) for the same computation. |
| 42 | + |
| 43 | +- Add a closest corners collision detector (`closestCorners`) to provide a more |
| 44 | + natural collision match when droppables are nested. |
| 45 | + |
| 46 | +- Add style helper (`maybeTransformStyle`) that only returns transform style |
| 47 | + when it will have an effect. This helps avoid affecting other styling (e.g. |
| 48 | + z-index) unintentionally. The directive form already uses this approach, and |
| 49 | + now manual setups can have this behaviour more easily too. |
| 50 | + |
| 51 | +### Changed |
| 52 | + |
| 53 | +- **Breaking Change** Refactor collision detection to be more context aware. |
| 54 | + |
| 55 | + Whilst it originally felt better to have collision detection abstracted into |
| 56 | + considering just layouts, in practice it limits smarter handling such as tie |
| 57 | + breaking on active droppable or types. |
| 58 | + |
| 59 | + Now, the active draggable and list of droppables is passed directly to the |
| 60 | + collision detection algorithm along with some additional useful context (such |
| 61 | + as the active droppable id). A new `CollisionDetector` type is also available |
| 62 | + for use when writing custom collision detectors. |
| 63 | + |
| 64 | + ```js |
| 65 | + type CollisionDetector = ( |
| 66 | + draggable: Draggable, |
| 67 | + droppables: Droppable[], |
| 68 | + context: { activeDroppableId: string | number | null } |
| 69 | + ) => Droppable | null; |
| 70 | + ``` |
| 71 | + |
| 72 | +- **Breaking Change** As part of the changes to the collision detection |
| 73 | + interface, update the existing algorithms and rename to drop "layout" from |
| 74 | + their names: |
| 75 | + |
| 76 | + * `closestLayoutCenter` -> `closestCenter` |
| 77 | + * `mostIntersectingLayout` -> `mostIntersecting` |
| 78 | + |
| 79 | +- **Breaking Change** Rename `collisionDetectionAlgorithm` prop of |
| 80 | + `DragDropProvider` to the simpler `collisionDetector`. |
| 81 | + |
| 82 | +- Compute and apply appropriate transform for sortables explicitly, rather than |
| 83 | + rely on delegation to underlying draggable/droppable transforms. |
| 84 | + |
| 85 | + A sortable can be transformed either as the active draggable transform (when |
| 86 | + no drag overlay is used) or as a droppable transform caused by the sorting of |
| 87 | + the list. Correctly compute the correct transform and ensure it is used both |
| 88 | + in directive form and as the returned transform for the sortable interface. |
| 89 | + |
| 90 | + As part of this, always store the computed sortable transform against the |
| 91 | + droppable entry regardless of whether directive used or not. This ensures |
| 92 | + consistency in the data (and helps debuggers visualise the information |
| 93 | + accurately). |
| 94 | + |
| 95 | +- Include `transform` in returned `Droppable` interface for consistency. |
| 96 | + |
| 97 | +- Simplify typings for state. Whilst technically correct, the presence of |
| 98 | + `undefined` in the typing for state like `droppables` makes it more awkward |
| 99 | + for consumers of that state. This is because they have to account for |
| 100 | + `undefined` value even though it will never actually be present (because |
| 101 | + setting state to `undefined` removes it from the state). So simplify the |
| 102 | + typing and override where necessary (such as when removing values). |
| 103 | + |
| 104 | +- Use `createEffect` consistently throughout for a clearer mental model. There |
| 105 | + is currently no clear need for more immediate effects as provided by |
| 106 | + `createRenderEffect` and `createComputed`. |
| 107 | + |
| 108 | +- Encapsulate layout inteface in a `Layout` class to avoid repeated definition |
| 109 | + of getter properties. As part of this, remove the standalone function for |
| 110 | + calculating layout center in favour of a computed property (`center`) on the |
| 111 | + layout itself. |
| 112 | + |
| 113 | +### Fixed |
| 114 | + |
| 115 | +- Strip translation transform when computing an element's layout. If a draggable |
| 116 | + is active when its layout is recomputed, its currently applied transform will |
| 117 | + be evaluated as part of its base layout (by `getBoundingClientRect`). This |
| 118 | + results in the transforms effectively stacking over time and the item being |
| 119 | + misplaced. To prevent this, strip any translation transform that is applied on |
| 120 | + the element. |
| 121 | + |
| 122 | +- Reset sortable positions when indices are invalid. Prevent confusing behaviour |
| 123 | + caused by stale sort order when indices become invalid, but a drag is still |
| 124 | + active. This can happen when sorting across multiple containers for example. |
| 125 | + |
| 126 | +- Ensure item accessors only re-evaluate when the active/previous id value |
| 127 | + changes. Previously, these accessors re-evaluated (when used in an effect) |
| 128 | + whenever the referenced item object itself had changes, leading to confusing |
| 129 | + behaviour. For example, `onDragEnd` firing again when adding new droppables. |
| 130 | + |
| 131 | +- Built-in collision detection now tie-breaks on the active droppable to prevent |
| 132 | + potential flipping situations. When two droppables were equidistant candidates |
| 133 | + for collision, their naive ordering would decide which was returned as the |
| 134 | + match. Due to subsequent sorting, that ordering could change and the very next |
| 135 | + move would result in the alternative candidate matching, resulting in constant |
| 136 | + flipping. By tie-breaking on the active droppable this is avoided in the |
| 137 | + common case. |
| 138 | + |
3 | 139 | ## [0.4.2] - 2022-02-06 |
4 | 140 |
|
5 | 141 | ### Fixed |
|
0 commit comments