1 2export default { 3 name: "before-after-slider", 4 displayName: "Before/After Slider", 5 version: "1.0.2", 6 settings: {"startPosition":{"min":0,"unit":"%","max":100,"label":"Starting Position","step":1,"type":"range","default":40},"orientation":{"label":"Orientation","options":[{"label":"Horizontal","value":"horizontal"},{"label":"Vertical","value":"vertical"}],"type":"select","default":"horizontal"},"showLabels":{"label":"Show Labels","type":"boolean","default":true}}, 7 8 mount: function (element, options) { 9 const container = element.querySelector(".ba-container"); 10 const slider = element.querySelector(".ba-slider"); 11 const beforeDiv = element.querySelector(".ba-before"); 12 const handle = element.querySelector(".ba-handle"); 13 14 if ( 15 !container || 16 !slider || 17 !beforeDiv || 18 !handle 19 ) { 20 return {}; 21 } 22 23 const isVertical = options.orientation === "vertical"; 24 const startPos = Number.isFinite(parseInt(options.startPosition)) ? parseInt(options.startPosition) : 40; 25 26 // Utility: pointer coords (mouse or touch) 27 const getPoint = (e) => { 28 if ( 29 e.touches && 30 e.touches.length 31 ) { 32 return { 33 x: e.touches[0].clientX, 34 y: e.touches[0].clientY 35 }; 36 } 37 38 return { 39 x: e.clientX, 40 y: e.clientY 41 }; 42 }; 43 44 // Apply clip based on percentage (0..100) 45 46 const applyClip = (percent) => { 47 const p = Math.max(0, Math.min(100, percent)); 48 49 if (isVertical) { 50 // Clip from bottom 51 const val = `inset(0 0 ${100 - p}% 0)`; 52 53 beforeDiv.style.clipPath = val; 54 beforeDiv.style.webkitClipPath = val; 55 56 slider.style.top = `${p}%`; 57 } 58 else { 59 // Clip from right 60 const val = `inset(0 ${100 - p}% 0 0)`; 61 62 beforeDiv.style.clipPath = val; 63 beforeDiv.style.webkitClipPath = val; 64 65 slider.style.left = `${p}%`; 66 } 67 }; 68 69 // Initial position 70 applyClip(startPos); 71 72 // Labels visibility (defensive) 73 const labels = element.querySelectorAll(".ba-label-before, .ba-label-after"); 74 const showLabels = options.showLabels === true || options.showLabels === "true"; 75 76 labels.forEach(label => { 77 label.style.display = showLabels ? "block" : "none"; 78 }); 79 80 let isDragging = false; 81 82 const updateFromEvent = (e) => { 83 if (!isDragging) { 84 return; 85 } 86 87 const rect = container.getBoundingClientRect(); 88 const pt = getPoint(e); 89 let position; 90 91 if (isVertical) { 92 // down -> bigger % 93 position = ((pt.y - rect.top) / rect.height) * 100; 94 } 95 else { 96 // right -> bigger % 97 position = ((pt.x - rect.left) / rect.width) * 100; 98 } 99 100 applyClip(position); 101 102 // Prevent scroll on touch while dragging 103 if (e.cancelable) { 104 e.preventDefault(); 105 } 106 }; 107 108 const startDrag = (e) => { 109 isDragging = true; 110 111 if (e.cancelable) { 112 e.preventDefault(); 113 } 114 115 updateFromEvent(e); 116 }; 117 118 const stopDrag = () => { 119 isDragging = false; 120 }; 121 122 // Accessibility 123 element.setAttribute("role", "group"); 124 element.setAttribute("aria-label", "Before/After Slider"); 125 126 // Events 127 handle.addEventListener("mousedown", startDrag); 128 handle.addEventListener("touchstart", startDrag, { passive: false }); 129 130 document.addEventListener("mousemove", updateFromEvent); 131 document.addEventListener("touchmove", updateFromEvent, { passive: false }); 132 document.addEventListener("mouseup", stopDrag); 133 document.addEventListener("touchend", stopDrag, { passive: true }); 134 document.addEventListener("touchcancel", stopDrag, { passive: true }); 135 136 // Cleanup 137 return { 138 unmount: () => { 139 handle.removeEventListener("mousedown", startDrag); 140 handle.removeEventListener("touchstart", startDrag, { passive: false }); 141 142 document.removeEventListener("mousemove", updateFromEvent); 143 document.removeEventListener("touchmove", updateFromEvent, { passive: false }); 144 document.removeEventListener("mouseup", stopDrag); 145 document.removeEventListener("touchend", stopDrag, { passive: true }); 146 document.removeEventListener("touchcancel", stopDrag, { passive: true }); 147 } 148 }; 149 } 150};
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.