listInput = ({
input = defaultInput,
min = 0,
max = 0,
value = null,
defaultValue = '',
} = {}) => {
let values = value !== null ? value : new Array(Math.max(min, 1)).fill(defaultValue)
const inputRow = (v, i) => html.fragment`<tr>
<td onchange=${e => changeValueAt(i, e.target.value)}>${input(v, i, values)}</td>
<td>
<button onclick=${e => removeRow(i)} disabled=${values.length <= min}>×</button>
</td>
</tr>`
const footerRow = () => html.fragment`<tr>
<td></td>
<td>
<button onclick=${addRow} disabled=${values.length >= max && max !== 0}>+</button>
</td>
</tr>`
const rerenderTbody = () => {
const tbody = output.querySelector('tbody')
tbody.innerHTML = ''
tbody.appendChild(html.fragment`${values.map(inputRow)}`)
}
const rerenderTfoot = () => {
const tfoot = output.querySelector('tfoot')
tfoot.innerHTML = ''
tfoot.appendChild(footerRow())
}
const rerender = () => {
rerenderTbody()
rerenderTfoot()
}
const dispatchInputEvent = () => {
output.value = values
output.dispatchEvent(new CustomEvent('input'))
}
const addRow = () => {
values.push(defaultValue)
rerender()
dispatchInputEvent()
}
const removeRow = removeIdx => {
values = values.filter((_, i) => i !== removeIdx)
rerender()
dispatchInputEvent()
}
const changeValueAt = (i, value) => {
values[i] = value
rerender()
dispatchInputEvent()
}
const output = html`<table style=${{ width: 'auto' }}>
<tbody>
${values.map(inputRow)}
</tbody>
<tfoot>
${footerRow()}
</tfoot>
</table>`
output.value = values
return output
}