1import { Controller } from "@hotwired/stimulus" 2 3// Handles the block type palette - listing available blocks and drag-to-add 4export default class extends Controller { 5 static targets = ["container", "blockTypeTemplate"] 6 7 connect() { 8 this.blockTypes = [] 9 this.isDragging = false 10 this.draggedBlockType = null 11 } 12 13 setup(blockTypes) { 14 this.blockTypes = blockTypes 15 this.render() 16 } 17 18 render() { 19 this.containerTarget.innerHTML = "" 20 const template = this.blockTypeTemplateTarget 21 22 this.blockTypes.forEach(blockType => { 23 const clone = template.content.cloneNode(true) 24 const item = clone.firstElementChild 25 item.dataset.blockType = blockType.type 26 27 const iconSlot = clone.querySelector("[data-slot=\"icon\"]") 28 iconSlot.innerHTML = blockType.icon 29 30 const nameSlot = clone.querySelector("[data-slot=\"name\"]") 31 nameSlot.textContent = blockType.name 32 33 this.containerTarget.appendChild(clone) 34 }) 35 } 36 37 // Tiles are role="button" divs (see the palette partial), so Enter and Space 38 // have to be wired up by hand to match what a real button would do. 39 keydown(event) { 40 if (event.key !== "Enter" && event.key !== " " && event.key !== "Spacebar") return 41 42 event.preventDefault() 43 this.addBlock(event) 44 } 45 46 // Click to add block at end 47 addBlock(event) { 48 if (this.isDragging) return 49 50 const button = event.currentTarget 51 const blockType = button.dataset.blockType 52 53 this.dispatch("request-add", { 54 detail: { blockType }, 55 bubbles: true 56 }) 57 } 58 59 // Drag handlers 60 dragStart(event) { 61 this.isDragging = true 62 this.draggedBlockType = event.currentTarget.dataset.blockType 63 64 event.dataTransfer.effectAllowed = "copy" 65 event.dataTransfer.setData("text/plain", this.draggedBlockType) 66 67 event.currentTarget.classList.add("opacity-50") 68 69 // Notify parent that drag started 70 this.dispatch("drag-state-change", { 71 detail: { isDragging: true, blockType: this.draggedBlockType }, 72 bubbles: true 73 }) 74 } 75 76 dragEnd(event) { 77 this.isDragging = false 78 this.draggedBlockType = null 79 event.currentTarget.classList.remove("opacity-50") 80 81 // Notify parent that drag ended 82 this.dispatch("drag-state-change", { 83 detail: { isDragging: false }, 84 bubbles: true 85 }) 86 } 87 88 getDraggedBlockType() { 89 return this.draggedBlockType 90 } 91 92 isDraggingBlock() { 93 return this.isDragging 94 } 95}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.