### Install Livewire Sortable via NPM Source: https://github.com/livewire/sortable/blob/master/README.md Install the package using npm and import it into your bundle. This method is suitable for projects managed with npm. ```bash npm install livewire-sortable --save-dev ``` ```javascript import 'livewire-sortable' // Or. require('livewire-sortable') ``` -------------------------------- ### Minimal Sortable List Example Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md This example demonstrates a basic sortable list in a Blade template and the corresponding Livewire component method to handle order updates. ```html ``` ```php public function updateTaskOrder($items) { foreach ($items as $item) { Task::where('id', $item['value']) ->update(['order' => $item['order']]); } } ``` -------------------------------- ### Before Handle-Only Dragging Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md This example shows the default behavior where dragging can be initiated from anywhere within the list item. ```blade
  • {{ $task->title }}

    {{ $task->description }}

    Link
  • ``` -------------------------------- ### Simple List Sorting with Livewire Sortable Source: https://github.com/livewire/sortable/blob/master/README.md Use `wire:sortable`, `wire:sortable.item`, and `wire:sortable.handle` for basic sortable lists like a todo list. This example shows how to structure the markup for a sortable task list. ```html ``` -------------------------------- ### Install Livewire Sortable via CDN Source: https://github.com/livewire/sortable/blob/master/README.md Include this script tag in your HTML to use Livewire Sortable via a CDN. Ensure you are using Livewire v3. ```html ``` -------------------------------- ### JavaScript Example of Data Conversion Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md Illustrates how numeric and string values are represented in JavaScript before being sent to PHP. Note that 'value' remains a string. ```javascript { order: 1, value: '42' } ``` -------------------------------- ### Handle Drag Start Event in JavaScript Source: https://github.com/livewire/sortable/blob/master/_autodocs/INDEX.md Use this JavaScript snippet to execute custom logic when a drag operation begins. Attach event listeners to the sortable instance. ```javascript sortable.on('drag:start', (event) => { // Handle drag start }); ``` -------------------------------- ### Example Sortable Item List Payload Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md An example of the JavaScript object passed to a Livewire method when a simple sortable list is reordered. ```javascript [ { order: 1, value: "task-42" }, { order: 2, value: "task-18" }, { order: 3, value: "task-99" } ] ``` -------------------------------- ### Livewire Component Method for Updating Order Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md Example of a Livewire component method that receives the reordered item data and updates the database accordingly. ```php update(['order' => $item['order']]); } } public function render() { return view('livewire.task-list', [ 'tasks' => Task::orderBy('order')->get() ]); } } ?> ``` -------------------------------- ### HTML Structure for Sortable Groups and Items Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md Example HTML demonstrating how to structure nested draggable groups and items using Livewire's `wire:sortable` and `wire:sortable-group` directives. It includes methods for reordering groups and tasks, and for adding new tasks and groups. ```html
    @foreach ($groups as $group)

    {{ $group->label }}

    @endforeach
    ``` -------------------------------- ### Checking Livewire Sortable Plugin Activation Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Use this JavaScript code to verify if the Livewire and Sortable plugins are loaded, if the directive is registered, and if a Sortable instance is active on a specific container. It also includes an example of manually triggering a 'drag:start' event. ```javascript // Check if plugin loaded console.log('Livewire:', window.Livewire); console.log('Sortable:', window.Sortable); // Check if directive is registered const container = document.querySelector('[wire\:sortable="updateTaskOrder"]'); console.log('Container:', container); console.log('Sortable instance:', container?.livewire_sortable); // Manually inspect event handlers if (container?.livewire_sortable) { console.log('Sortable is active on this container'); // Try to trigger an event container.livewire_sortable.on('drag:start', () => { console.log('Drag started!'); }); } ``` -------------------------------- ### Efficiently Update Task Order in Bulk Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md This method provides a more efficient way to update task orders by preparing updates and then executing them. It also shows an example of a raw query for upserting, which should be used with caution. ```php public function updateTaskOrder($items) { $updates = []; foreach ($items as $item) { $updates[$item['value']] = $item['order']; } foreach ($updates as $id => $order) { Task::where('id', $id)->update(['order' => $order]); } // Or with raw query (use with caution): // DB::table('tasks')->upsert( // array_map(fn($id, $order) => ['id' => $id, 'order' => $order], // array_keys($updates), // $updates), // 'id', // ['order'] // ); } ``` -------------------------------- ### Nested Sortable Group List Example Data Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md An example of the data structure for a nested sortable list, representing groups and their items. ```javascript [ { order: 1, value: "backlog", items: [ { order: 1, value: "task-1" }, { order: 2, value: "task-3" } ] }, { order: 2, value: "in-progress", items: [ { order: 1, value: "task-2" }, { order: 2, value: "task-5" } ] }, { order: 3, value: "done", items: [ { order: 1, value: "task-4" } ] } ] ``` -------------------------------- ### Livewire Component Method Definition Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md Example of a public method in a Livewire component that can be called from JavaScript to handle reordering. It accepts the serialized order data as an argument. ```php public function updateTaskOrder($items) { // Handle reordering } ``` -------------------------------- ### Race Condition Example in Livewire Sortable Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md Rapid succession of drag operations can lead to multiple wire calls being enqueued before the first completes, potentially causing conflicts. Mitigation strategies like optimistic locking or version columns in the database are recommended. ```text 1. First drag: setTimeout(..., 1) enqueues the wire call 2. Second drag: Another wire call enqueued (before first completes) 3. Both calls are sent (order depends on network timing) ``` -------------------------------- ### Nested Sortable Groups with Livewire Sortable Source: https://github.com/livewire/sortable/blob/master/README.md Implement nested sortable elements, similar to Trello boards, using `wire:sortable-group` attributes. This example demonstrates a structure for draggable groups containing draggable tasks. ```html
    @foreach ($groups as $group)

    {{ $group->label }}

    @endforeach
    ``` -------------------------------- ### After Handle-Only Dragging Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md This example restricts dragging to only the `

    ` element, allowing other elements like links to be clicked normally. ```blade
  • {{ $task->title }}

    {{ $task->description }}

    Link
  • ``` -------------------------------- ### Initialize Sortable Instance for Groups Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md Initializes a new Sortable instance for the `wire:sortable-group` directive. It starts with an empty array of containers, as they are added dynamically via the `item-group` modifier. ```javascript const sortable = el.livewire_sortable = new Sortable([], options); ``` -------------------------------- ### NPM Scripts for Build and Test (JSON) Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md Defines the npm scripts for building, watching, and testing the Livewire Sortable project. Includes commands for one-time builds, watch mode, running tests, and debugging tests. ```json { "build": "npx rollup -c", "watch": "npx rollup -c -w", "test": "npx jest", "test:debug": "node --inspect node_modules/.bin/jest --runInBand" } ``` -------------------------------- ### Load Livewire and Sortable Scripts Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Ensure Livewire and Livewire Sortable scripts are loaded in the correct order. Livewire should be loaded before Livewire Sortable. ```html ``` -------------------------------- ### Check Sortable.js Loading Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Verify if the bundled Sortable.js is loaded. If undefined, ensure `livewire-sortable.js` or the CDN script is loaded in the correct order after Livewire. ```javascript console.log(window.Sortable); ``` -------------------------------- ### Initialize Sortable Container Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md Use 'wire:sortable' on the parent container to initialize Sortable. It expects the name of the Livewire method to invoke when sorting completes. ```html ``` -------------------------------- ### Livewire Kanban Board Component (PHP) Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md This Livewire component manages the Kanban board's state and logic. It handles fetching groups and tasks, updating their order via `updateGroupOrder` and `updateTaskOrder` methods, creating new tasks, and deleting existing ones. The `render` method fetches and orders the data, while specific methods respond to user interactions like reordering and task creation. ```php TaskGroup::with('tasks')->orderBy('order')->get(), ]); } public function updateGroupOrder($groups) { // $groups = [ // [ // 'order' => 1, // 'value' => 'backlog', // 'items' => [...] // ], // ... // ] foreach ($groups as $groupData) { TaskGroup::where('id', $groupData['value']) ->update(['order' => $groupData['order']]); } } public function updateTaskOrder($groups) { // Called whenever items are reordered (group or item drag) foreach ($groups as $groupData) { foreach ($groupData['items'] as $itemData) { Task::where('id', $itemData['value']) ->update([ 'task_group_id' => $groupData['value'], 'order' => $itemData['order'], ]); } } } public function createTask($groupId) { if (empty($this->newTaskTitle)) { return; } Task::create([ 'task_group_id' => $groupId, 'title' => $this->newTaskTitle, 'order' => Task::where('task_group_id', $groupId)->max('order') + 1, ]); $this->newTaskTitle = ''; } public function deleteTask($id) { Task::destroy($id); } public function editTask($id) { $this->editingTaskId = $id; // Show modal, etc. } } ?> ``` -------------------------------- ### Ignore Elements During Drag Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md Apply 'wire:sortable.ignore' to elements or their ancestors to prevent dragging from starting when interacting with them. This is useful for buttons or forms within sortable items. ```html
  • {{ $task->title }}

  • ``` -------------------------------- ### Rollup Build Configuration (JavaScript) Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md Configuration file for Rollup, a module bundler used to build the Livewire Sortable library. It specifies entry points, output formats (UMD), and includes plugins for commonjs, resolution, filesize reporting, minification with Terser, and Babel transpilation. ```javascript export default { input: 'src/index.js', output: { name: 'Sortable', file: 'dist/livewire-sortable.js', format: 'umd', sourcemap: true, }, plugins: [ commonjs(), resolve(), filesize(), terser({ compress: { drop_debugger: false } }), babel({ exclude: 'node_modules/**' }) ] } ``` -------------------------------- ### Check Livewire Loading Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Verify if Livewire is loaded in the browser. If undefined, ensure `@livewireScripts` is included in your layout before the sortable script. ```javascript console.log(window.Livewire); ``` -------------------------------- ### Cancel Drag on Ignore Attribute or Parent Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md Listens for the 'drag:start' event from Shopify's Sortable. It cancels the drag operation if the target element or any of its ancestors have the 'wire:sortable.ignore' attribute. ```javascript sortable.on('drag:start', (event) => { const target = event.originalEvent.target; if (target.hasAttribute('wire:sortable.ignore') || findNearestParentByAttribute(target)) { event.cancel() } }); ``` -------------------------------- ### Initialize Shopify Sortable Instance Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Instantiate a new Sortable object with containers and options. This is an internal method used by the plugin. ```javascript const sortable = new Sortable(containers, options) ``` -------------------------------- ### Create Shopify Sortable Instance Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md Instantiates the Shopify Sortable class with the provided DOM element and options. The Sortable instance is managed internally by the Shopify library. ```javascript const sortable = new Sortable(el, options); ``` -------------------------------- ### Prevent Accidental Drag with Livewire Sortable Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Prevent accidental drag operations on sortable items by using `wire:sortable.ignore` on elements that should not initiate a drag, such as form inputs or submit buttons. This example shows how to ignore a form submission. ```html
  • {{ $title }}
  • ``` -------------------------------- ### Implement Database Update Logic Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Ensure your Livewire method iterates through the received items and updates the database accordingly. Log received items to verify. ```php public function updateTaskOrder($items) { // Are you actually updating? foreach ($items as $item) { Task::where('id', $item['value']) ->update(['order' => $item['order']]); } } Add logging: public function updateTaskOrder($items) { \Log::info('Received items:', $items); // Will show in storage/logs/laravel.log } ``` -------------------------------- ### Ignore Dragging with wire:sortable.ignore Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md Use the `wire:sortable.ignore` modifier on an element to prevent drag operations from starting on it, even if it's part of a sortable list or group. This is useful for elements like delete buttons within sortable items. ```html
  • {{ $task->title }}
  • ``` -------------------------------- ### Check Database Column and Tinker Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Verify that the 'order' column exists in your database table and is writable. Use `php artisan tinker` to test direct updates. ```bash php artisan tinker >>> Task::first()->update(['order' => 999]) >>> Task::first()->order ``` -------------------------------- ### Livewire Sortable Event Flow Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Illustrates the sequence of events triggered when a user interacts with a sortable list, from the initial drag to the final database update. ```text User drags item ↓ drag:start event (checked for ignore) ↓ Item moves visually ↓ User releases ↓ sortable:stop event ↓ setTimeout(..., 1) defers update ↓ component.$wire.call(methodName, items) ↓ Livewire sends HTTP request ↓ PHP method executes ↓ Database updated ``` -------------------------------- ### Kanban Board HTML Template (Blade) Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md This Blade template defines the structure of the Kanban board, including groups and tasks. It utilizes Livewire's `wire:sortable` and `wire:sortable-group` directives to enable drag-and-drop functionality for both group and item reordering. Each task and group has a unique key for Livewire's diffing. ```blade
    @foreach ($groups as $group)

    {{ $group->label }}

    ({{ $group->tasks->count() }})
      @foreach ($group->tasks()->orderBy('order')->get() as $task)
    • {{ $task->title }}

      {{ $task->description }}

      {{ $task->priority }} @if ($task->assignee) {{ $task->assignee->name }} @endif
    • @endforeach
    @endforeach
    ``` -------------------------------- ### Livewire Component Methods for Sorting Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md PHP code for a Livewire component demonstrating how to handle the reordering of groups and tasks. It includes methods to update the order in the database based on the data received from the front-end sorting events. ```php update(['order' => $groupData['order']]); } } public function updateTaskOrder($groups) { foreach ($groups as $groupData) { foreach ($groupData['items'] as $itemData) { Task::where('id', $itemData['value']) ->update(['order' => $itemData['order']]); } } } public function render() { return view('livewire.board-view', [ 'groups' => TaskGroup::with('tasks')->orderBy('order')->get() ]); } } ?> ``` -------------------------------- ### Paginate Tasks in Livewire Component Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Implement pagination to reduce the number of DOM elements when dealing with large lists. This limits the fetched tasks to a manageable number. ```php public function render() { return view('livewire.task-list', [ 'tasks' => Task::orderBy('order') ->limit(50) // Paginate ->get(), ]); } ``` -------------------------------- ### Livewire Component Methods for Order Updates Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Implement `updateGroupOrder` to reorder top-level groups and `updateTaskOrder` to reorder tasks within their groups. Both methods receive structured data representing the new order. ```php public function updateGroupOrder($groups) { foreach ($groups as $groupData) { TaskGroup::where('id', $groupData['value']) ->update(['order' => $groupData['order']]); } } ``` ```php public function updateTaskOrder($groups) { foreach ($groups as $groupData) { foreach ($groupData['items'] as $itemData) { Task::where('id', $itemData['value']) ->update([ 'task_group_id' => $groupData['value'], 'order' => $itemData['order'], ]); } } } ``` -------------------------------- ### Handle-Only Drag with Livewire Sortable Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Implement handle-only drag-and-drop by specifying a handle element using `wire:sortable.handle`. This allows only the designated handle to initiate the drag, while other elements like buttons can be ignored using `wire:sortable.ignore`. ```html
  • ⋮⋮ {{ $title }}
  • ``` -------------------------------- ### HTML Template for Sortable Task List Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md Defines the structure for a sortable task list using Livewire directives. Ensure each item has a unique `wire:key` and the list has a `wire:sortable` attribute. ```blade
    ``` -------------------------------- ### Verify Task Order in Tinker Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Use this Artisan Tinker command to check if the 'order' column in your database is being updated correctly after drag-and-drop operations. ```bash php artisan tinker >>> Task::orderBy('order')->get()->pluck('id', 'order') ``` -------------------------------- ### Handle Detection Logic Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md This JavaScript code demonstrates how the plugin checks for the presence of a handle element to configure drag behavior. ```javascript if (el.querySelector('[wire\:sortable\.handle]')) { options.handle = '[wire\:sortable\.handle]' } ``` -------------------------------- ### Check Method Signature Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md The Livewire sortable method must accept a single parameter, which is an array of the sorted items. ```php // Correct public function updateTaskOrder($items) { // Wrong (no parameters) public function updateTaskOrder() { ``` -------------------------------- ### CSS for Sortable Task List Styling Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md Provides styling for the sortable task list, including item appearance, drag handles, and delete buttons. Includes styles for the dragging state to provide visual feedback. ```css .task-item { padding: 12px; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 8px; background: white; display: flex; justify-content: space-between; align-items: center; } .task-item.draggable-source--is-dragging { opacity: 0.5; background: #f9f9f9; } .task-handle { cursor: move; flex: 1; display: flex; align-items: center; gap: 8px; } .task-handle:hover { color: #007bff; } .drag-icon { color: #999; font-size: 12px; } .btn-delete { background: none; border: none; color: #dc3545; cursor: pointer; padding: 4px 8px; font-size: 16px; } .btn-delete:hover { color: #c82333; } body.draggable--is-dragging { cursor: grabbing; } ``` -------------------------------- ### Optional Chaining for Livewire Access Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md Use optional chaining to safely access Livewire directives, preventing errors if Livewire is not loaded on the page. ```javascript window.Livewire?.directive(...) ``` -------------------------------- ### Check Method Visibility Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md The sortable method must be public. Private or protected methods will not be invoked by Livewire. ```php // Correct public function updateTaskOrder($items) { // Wrong (private or protected) private function updateTaskOrder($items) { ``` -------------------------------- ### PHP Livewire Receiver for Item Reordering Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md PHP method to update the order of items within groups when they are reordered. Assumes a `Task` model. ```php public function updateTaskOrder($groups) { // Called when items are reordered (may also receive full group structure) foreach ($groups as $groupData) { foreach ($groupData['items'] as $itemData) { Task::where('id', $itemData['value']) ->update(['order' => $itemData['order']]); } } } ``` -------------------------------- ### Verify Livewire Component Initialization Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Ensure the Livewire component is correctly initialized in your Blade view using the @livewire directive. ```blade
    @livewire('task-list')
    Not: @include('livewire.task-list') ``` -------------------------------- ### Correct Livewire Sortable Handle Attribute Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Demonstrates the correct HTML attribute usage for specifying a sortable handle. The `wire:sortable.handle` attribute should be placed directly on the element. ```html

    Title

    Title

    ``` -------------------------------- ### Simple Sortable List Source: https://github.com/livewire/sortable/blob/master/_autodocs/README.md Use this snippet to create a basic sortable list. The `wire:sortable` directive handles the sorting logic, and `wire:sortable.item` identifies individual sortable elements. ```html ``` -------------------------------- ### PHP Livewire Receiver for Group Reordering Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md PHP method to update the order of groups when they are reordered in the UI. Assumes a `TaskGroup` model. ```php public function updateGroupOrder($groups) { // Called when groups are reordered foreach ($groups as $groupData) { TaskGroup::where('id', $groupData['value']) ->update(['order' => $groupData['order']]); } } ``` -------------------------------- ### Livewire Method for Group Reordering Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md This is the expected signature for the Livewire method that handles reordering within nested sortable groups. It receives a structured array of groups, their order, and their nested items. ```php public function updateTaskOrder($groups) { // $groups = [ // [ // 'order' => 1, // 'value' => 'group-1', // 'items' => [ // ['order' => 1, 'value' => 'task-1'], // ['order' => 2, 'value' => 'task-2'] // ] // ], // ... // ] } ``` -------------------------------- ### Bulk Update Order with Livewire Sortable Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Handle bulk updates for sortable items by receiving an array of items with their values and orders. This PHP snippet demonstrates iterating through the received items and updating their order in the database. ```php public function updateTaskOrder($items) { foreach ($items as $item) { Task::where('id', (int)$item['value']) ->update(['order' => $item['order']]); } } ``` -------------------------------- ### Optimize Task Order Updates Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Improve the performance of updating task orders by consolidating multiple database queries into a more efficient batch update. Avoid slow individual updates within a loop. ```php // Slow foreach ($items as $item) { Task::where('id', $item['value'])->update(['order' => $item['order']]); } // Faster (single query) $updates = []; foreach ($items as $item) { $updates[$item['value']] = ['order' => $item['order']]; } foreach ($updates as $id => $data) { Task::where('id', $id)->update($data); } ``` -------------------------------- ### Trace Wire Method Calls in PHP Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md Add logging within a Livewire method to trace wire method calls, such as 'updateTaskOrder'. Check Laravel's log file for the logged information after sorting. ```php public function updateTaskOrder($items) { foreach ($items as $item) { Task::where('id', $item['value'])->update(['order' => $item['order']]); } } ``` -------------------------------- ### Initialize Nested Sortable Groups Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md Use `wire:sortable` and `wire:sortable-group` on the same root element to initialize nested sortable functionality. The `wire:sortable-group` method will be invoked for item reordering within groups. ```html
    ``` -------------------------------- ### JavaScript Extraction Logic Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md Demonstrates how the `order` and `value` properties are extracted from DOM elements to form the sortable item list. ```javascript el.querySelectorAll('[wire\:sortable\.item]').forEach((el, index) => { items.push({ order: index + 1, value: el.getAttribute('wire:sortable.item')}) }) ``` -------------------------------- ### Kanban Board CSS Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md Provides comprehensive CSS for styling a Kanban board, including layout, columns, task cards, and interactive elements. This CSS enables a visually appealing and functional drag-and-drop interface. ```css .kanban-board { display: flex; gap: 16px; padding: 16px; background: #f5f5f5; overflow-x: auto; min-height: 100vh; } .kanban-column { flex: 0 0 320px; background: white; border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .kanban-column.draggable-source--is-dragging { opacity: 0.6; } .column-header { padding: 16px; border-bottom: 2px solid #e0e0e0; cursor: move; user-select: none; } .column-header h3 { margin: 0; font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 8px; } .task-count { color: #999; font-size: 14px; } .task-list { list-style: none; padding: 12px; flex: 1; overflow-y: auto; min-height: 200px; } .task-card { background: #f9f9f9; border: 1px solid #e0e0e0; border-radius: 4px; padding: 12px; margin-bottom: 12px; cursor: move; display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; transition: all 0.2s; } .task-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.1); border-color: #007bff; } .task-card.draggable--over { background: #e3f2fd; border-color: #2196f3; } .task-content { flex: 1; min-width: 0; } .task-content h4 { margin: 0 0 4px 0; font-size: 14px; font-weight: 600; word-break: break-word; } .task-content p { margin: 0 0 8px 0; font-size: 12px; color: #666; line-height: 1.4; } .task-meta { display: flex; gap: 4px; align-items: center; } .badge { display: inline-block; padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: 600; text-transform: uppercase; } .badge { background: #fff3cd; color: #856404; } .badge:is(.high) { background: #f8d7da; color: #721c24; } .badge:is(.low) { background: #d1ecf1; color: #0c5460; } .avatar { width: 20px; height: 20px; border-radius: 50%; } .task-actions { display: flex; gap: 4px; opacity: 0; transition: opacity 0.2s; } .task-card:hover .task-actions { opacity: 1; } .btn-icon { background: none; border: none; padding: 4px; cursor: pointer; color: #999; font-size: 14px; } .btn-icon:hover { color: #007bff; } .add-task-form { padding: 12px; border-top: 1px solid #e0e0e0; display: flex; gap: 8px; } .input-task { flex: 1; border: 1px solid #ddd; border-radius: 4px; padding: 8px; font-size: 14px; } .input-task:focus { outline: none; border-color: #007bff; box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); } .btn-add { background: #007bff; color: white; border: none; border-radius: 4px; padding: 8px 12px; cursor: pointer; font-weight: 600; } .btn-add:hover { background: #0056b3; } body.draggable--is-dragging { cursor: grabbing; user-select: none; } ``` -------------------------------- ### Import Sortable Class Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md Import the Sortable class from '@shopify/draggable/lib/sortable'. This class is essential for managing sortable lists and groups. ```javascript import Sortable from '@shopify/draggable/lib/sortable' ``` -------------------------------- ### Handle Multi-User Concurrency with Locking Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md When multiple users might edit the same board, use lockForUpdate to prevent race conditions during task order updates. This locks the rows being updated. ```php public function updateTaskOrder($items) { foreach ($items as $item) { $task = Task::lockForUpdate()->find($item['value']); if ($task) { $task->update(['order' => $item['order']]); } } } ``` -------------------------------- ### Listen to Shopify Sortable Events Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md Attach an event handler to a Sortable instance for a specific event type. This is an internal method. ```javascript sortable.on(eventType, handler) ``` -------------------------------- ### Correct Livewire Sortable Directive Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md Ensure the `wire:sortable` directive includes a method name. The directive without a method name is incorrect. ```html