1class FLStepperInput extends HTMLElement { 2 constructor() { 3 super() 4 this.attachShadow( { mode: 'open' } ) 5 this.template = document.createElement( 'template' ) 6 } 7 8 connectedCallback() { 9 this.template.innerHTML = this.render( this.props ) 10 this.shadowRoot.replaceChildren( this.template.content.cloneNode( true ) ) 11 this.bindEvents() 12 } 13 14 getHiddenInput() { 15 const name = this.getAttribute( 'data-name' ) 16 const input = this.querySelector(`input[name="${name}"]`) 17 return input 18 } 19 20 setHiddenInput( value ) { 21 const input = this.getHiddenInput() 22 input.value = value 23 input.dispatchEvent( new Event( 'change' ) ) 24 } 25 26 onHiddenChanged(e) { 27 const value = e.target.value 28 const numberInput = this.shadowRoot.querySelector('input') 29 if ( value !== numberInput.value ) { 30 numberInput.value = value 31 numberInput.dispatchEvent( new Event( 'change' ) ) 32 } 33 } 34 35 bindEvents() { 36 37 // Increment buttons 38 const buttons = this.shadowRoot.querySelectorAll('button') 39 buttons.forEach( button => { 40 button.addEventListener( 'click', this.onStepClick.bind(this) ) 41 } ) 42 43 // Hidden Input 44 this.getHiddenInput().addEventListener( 'change', this.onHiddenChanged.bind(this) ) 45 46 // Number Input 47 this.shadowRoot.querySelector('input[type=number]').addEventListener( 'keyup', this.onNumberInputChanged.bind(this) ) 48 } 49 50 onNumberInputChanged( e ) { 51 const v = e.target.value 52 this.setHiddenInput( v ) 53 } 54 55 onStepClick( e ) { 56 const hidden = this.getHiddenInput() 57 const operation = e.target.getAttribute('data-operation') 58 let value = this.step( hidden.value, operation ) 59 this.setHiddenInput( value ) 60 } 61 62 step( v = 0, op = '+' ) { 63 const step = this.hasAttribute('step') ? parseInt( this.getAttribute('step') ) : 1 64 const min = this.hasAttribute('min') ? parseInt( this.getAttribute('min') ) : null 65 const max = this.hasAttribute('max') ? parseInt( this.getAttribute('max') ) : null 66 const value = ! v ? 0 : v 67 const steppedValue = '-' === op ? parseInt( value ) - step : parseInt( value ) + step 68 69 if ( null !== min && steppedValue < min ) { 70 return min 71 } else if ( null !== max && steppedValue > max ) { 72 return max 73 } 74 return steppedValue 75 } 76 77 render() { 78 const value = this.getHiddenInput().value 79 const step = this.hasAttribute('step') ? parseInt( this.getAttribute('step') ) : 1 80 const min = this.hasAttribute('min') ? parseInt( this.getAttribute('min') ) : null 81 const max = this.hasAttribute('max') ? parseInt( this.getAttribute('max') ) : null 82 return ` 83 <style> 84 :host { 85 flex-grow: 1; 86 color: inherit; 87 display: grid; 88 } 89 .wrap { 90 display: flex; 91 min-height: var(--fl-builder-target-size); 92 justify-content: space-evenly; 93 align-items: center; 94 color: inherit; 95 } 96 .wrap:hover button, 97 .wrap:focus-within button { 98 opacity: 1; 99 } 100 input { 101 min-width: 2ch; 102 max-width: 4ch; 103 border: none; 104 outline: none; 105 text-align: center; 106 padding: 0; 107 place-self: stretch; 108 background: transparent; 109 color: inherit; 110 } 111 /* Chrome, Safari, Edge, Opera */ 112 input::-webkit-outer-spin-button, 113 input::-webkit-inner-spin-button { 114 -webkit-appearance: none; 115 margin: 0; 116 } 117 /* Firefox */ 118 input[type=number] { 119 -moz-appearance: textfield; 120 } 121 button { 122 color: inherit; 123 background: transparent; 124 border: none; 125 outline: none; 126 width: 24px; 127 height: 24px; 128 display: flex; 129 justify-content: center; 130 align-items: center; 131 opacity: 0; 132 border-radius: 50%; 133 padding: 0; 134 } 135 button > * { 136 pointer-events: none; 137 } 138 button:hover { 139 background: var(--fl-builder-platter-bg-color); 140 } 141 </style> 142 <div class="wrap"> 143 <button data-operation="-"> 144 <svg width="20" height="20" viewBox="0 0 20 20" fill="none"> 145 <path d="M15.6569 10.0001H4.34315" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> 146 </svg> 147 </button> 148 <input 149 type="number" 150 min="${min}" 151 max="${max}" 152 step="${step}" 153 value="${value}" 154 /> 155 <button data-operation="+"> 156 <svg width="20" height="20" viewBox="0 0 20 20" fill="none"> 157 <path d="M15.6569 10.0001H4.34315" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> 158 <path d="M10 4.34326V15.657" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> 159 </svg> 160 </button> 161 </div> 162 ` 163 } 164} 165customElements.define( "fl-stepper", FLStepperInput )
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.