github.com/resonatecoop/id@v1.1.0-43/frontend/src/components/links-input.js (about) 1 const html = require('choo/html') 2 const Component = require('choo/component') 3 const validateFormdata = require('validate-formdata') 4 const input = require('@resonate/input-element') 5 const isURL = require('validator/lib/isURL') 6 const button = require('@resonate/button') 7 8 // LinksInput class 9 class LinksInput extends Component { 10 constructor (id, state, emit) { 11 super(id) 12 13 this.emit = emit 14 this.state = state 15 16 this.local = state.components[id] = {} 17 18 this.removeLink = this.removeLink.bind(this) 19 this.addLink = this.addLink.bind(this) 20 21 this.local.links = [] 22 23 this.validator = validateFormdata() 24 this.form = this.validator.state 25 26 this._onchange = this._onchange.bind(this) 27 } 28 29 createElement (props) { 30 this.onchange = typeof props.onchange === 'function' ? props.onchange.bind(this) : this._onchange 31 this.validator = props.validator || this.validator 32 this.form = props.form || this.form || { 33 changed: false, 34 valid: true, 35 pristine: {}, 36 required: {}, 37 values: {}, 38 errors: {} 39 } 40 41 this.local.required = props.required || false 42 43 const pristine = this.form.pristine 44 const errors = this.form.errors 45 const values = this.form.values 46 47 return html` 48 <div class="flex flex-column"> 49 <p>Website, Instagram, Twitter, Mastodon, etc.</p> 50 <div class="flex items-center mb1"> 51 ${input({ 52 type: 'url', 53 name: 'link', 54 invalid: errors.link && !pristine.link, 55 required: false, 56 placeholder: 'URL', 57 value: values.link, 58 onchange: (e) => { 59 this.validator.validate(e.target.name, e.target.value) 60 this.rerender() 61 } 62 })} 63 ${button({ 64 onclick: (e) => this.addLink(values.link, errors.link), 65 prefix: 'db bg-white bw b--black-20 h-100 ml1 pa3 grow', 66 style: 'none', 67 size: 'none', 68 iconName: 'add', 69 iconSize: 'sm' 70 })} 71 ${!this.local.required ? html`<p class="lh-copy f5 pl2 grey">Optional</p>` : ''} 72 </div> 73 74 <p class="ma0 pa0 message warning"> 75 ${errors.link && !pristine.link ? errors.link.message : ''} 76 </p> 77 78 <ul class="list ma0 pa0"> 79 ${this.local.links.map((link, index) => { 80 return html` 81 <li class="flex items-center relative"> 82 ${link} 83 ${button({ 84 onclick: (e) => this.removeLink(index), 85 prefix: 'bg-transparent bn ml2 pa0 grow', 86 iconName: 'close-fat', 87 iconSize: 'xxs', 88 style: 'none', 89 size: 'none' 90 })} 91 </li> 92 ` 93 })} 94 </ul> 95 </div> 96 ` 97 } 98 99 _onchange () {} 100 101 removeLink (index) { 102 if (index > -1) { 103 this.local.links.splice(index, 1) 104 this.onchange(this.local.links) 105 this.rerender() 106 } 107 } 108 109 addLink (value, error) { 110 if (value && !this.local.links.includes(value) && !error) { 111 this.local.links.push(value) 112 this.onchange(this.local.links) 113 this.rerender() 114 } 115 } 116 117 load () { 118 this.validator.field('link', { required: this.local.required }, (data) => { 119 if (!isURL(data, { require_protocol: false })) { return new Error('Link is not valid url') } 120 }) 121 } 122 123 update () { 124 return false 125 } 126 } 127 128 module.exports = LinksInput