UNPKG

vvcomponent

Version:
158 lines (137 loc) 5.68 kB
class aSlider extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.min = parseFloat(this.getAttribute('min')) || 0; this.max = parseFloat(this.getAttribute('max')) || 100; this.value = parseFloat(this.getAttribute('value')) || 0; this.step = parseFloat(this.getAttribute('step')) || 1; this.render(); } static get observedAttributes() { return ['min', 'max', 'value', 'step']; } attributeChangedCallback(name, oldValue, newValue) { if (oldValue !== newValue) { this[name] = parseFloat(newValue); if (name === 'value') { this.value = Math.max(this.min, Math.min(this.value, this.max)); } this.updateThumbPosition(this.sliderThumb, this.sliderTrack, this.value); } } render() { const sliderContainer = document.createElement('div'); sliderContainer.classList.add('slider-container'); const sliderTrack = document.createElement('div'); sliderTrack.classList.add('slider-track'); const sliderThumb = document.createElement('div'); sliderThumb.classList.add('slider-thumb'); sliderContainer.appendChild(sliderTrack); sliderTrack.appendChild(sliderThumb); this.shadowRoot.appendChild(sliderContainer); const style = document.createElement('style'); style.textContent = this.getStyles(); this.shadowRoot.appendChild(style); this.sliderTrack = sliderTrack; this.sliderThumb = sliderThumb; this.updateThumbPosition(sliderThumb, sliderTrack, this.value); this.addDragEvents(sliderTrack, sliderThumb); } getStyles() { return ` .slider-container { width: 100%; padding: 10px; position: relative; } .slider-track { width: 100%; height: 8px; background: #d3d3d3; /* Light gray background */ border-radius: 5px; position: relative; } .slider-thumb { width: 20px; height: 20px; background: #ffffff; /* White slider thumb */ border: 2px solid #007bff; /* Blue border */ border-radius: 50%; position: absolute; top: 50%; transform: translate(-50%, -50%); cursor: pointer; } .slider-track::before { content: ''; position: absolute; height: 100%; background: #007bff; /* Blue for the left side */ border-radius: 5px; width: var(--value, 0%); } `; } addDragEvents(track, thumb) { let isDragging = false; const getEventClientX = (event) => { return event.touches ? event.touches[0].clientX : event.clientX; }; const updateThumbPosition = (event) => { const rect = track.getBoundingClientRect(); let offsetX = getEventClientX(event) - rect.left; offsetX = Math.max(0, Math.min(offsetX, rect.width)); const percentage = (offsetX / rect.width) * 100; const rawValue = this.min + (percentage / 100) * (this.max - this.min); const steppedValue = Math.round(rawValue / this.step) * this.step; this.value = Math.max(this.min, Math.min(steppedValue, this.max)); thumb.style.left = `${((this.value - this.min) / (this.max - this.min)) * 100}%`; track.style.setProperty('--value', `${((this.value - this.min) / (this.max - this.min)) * 100}%`); }; const dispatchStartEvent = () => { const startEvent = new CustomEvent('start', { detail: { value: this.value }, }); this.dispatchEvent(startEvent); }; const dispatchChangeEvent = () => { const changeEvent = new CustomEvent('change', { detail: { value: this.value }, }); this.dispatchEvent(changeEvent); }; const startDrag = (event) => { isDragging = true; dispatchStartEvent(); }; const moveDrag = (event) => { if (isDragging) { updateThumbPosition(event); } }; const endDrag = () => { if (isDragging) { isDragging = false; dispatchChangeEvent(); } }; thumb.addEventListener('mousedown', startDrag); thumb.addEventListener('touchstart', startDrag, { passive: true }); document.addEventListener('mousemove', moveDrag); document.addEventListener('touchmove', moveDrag, { passive: true }); document.addEventListener('mouseup', endDrag); document.addEventListener('touchend', endDrag); track.addEventListener('click', (event) => { updateThumbPosition(event); dispatchChangeEvent(); }); } updateThumbPosition(thumb, track, value) { const percentage = ((value - this.min) / (this.max - this.min)) * 100; thumb.style.left = `${percentage}%`; track.style.setProperty('--value', `${percentage}%`); } } globalThis.Slider = aSlider; customElements.define('iftc-slider', aSlider);