@zeix/ui-element
Version:
UIElement - a HTML-first library for reactive Web Components
65 lines (58 loc) • 1.48 kB
text/typescript
import {
type Component,
asInteger,
component,
fromEvents,
setProperty,
setText,
show,
} from '../../..'
export type FormSpinbuttonProps = {
value: number
}
const clickHandler = ({ target, value }) =>
value + (target.classList.contains('decrement') ? -1 : 1)
const keydownHandler = ({ event, value }) => {
const { key } = event as KeyboardEvent
if (['ArrowUp', 'ArrowDown', '-', '+'].includes(key)) {
event.stopPropagation()
event.preventDefault()
return value + (key === 'ArrowDown' || key === '-' ? -1 : 1)
}
}
export default component(
'form-spinbutton',
{
value: fromEvents(
el => asInteger()(el, el.querySelector('value')?.textContent),
'button',
{
click: clickHandler,
keydown: keydownHandler,
},
),
},
(el, { first }) => {
const zeroLabel = el.getAttribute('zero-label') || 'Add to Cart'
const incrementLabel = el.getAttribute('increment-label') || 'Increment'
const max = asInteger(9)(el, el.getAttribute('max'))
const nonZero = () => el.value !== 0
return [
first('.value', setText('value'), show(nonZero)),
first('.decrement', show(nonZero)),
first<HTMLButtonElement>(
'.increment',
setText(() => (nonZero() ? '+' : zeroLabel)),
setProperty('ariaLabel', () =>
nonZero() ? incrementLabel : zeroLabel,
),
setProperty('disabled', () => el.value >= max),
),
]
},
)
declare global {
interface HTMLElementTagNameMap {
'form-spinbutton': Component<FormSpinbuttonProps>
}
}