@zeix/ui-element
Version:
UIElement - a HTML-first library for reactive Web Components
65 lines (60 loc) • 1.47 kB
text/typescript
import {
asInteger,
type Component,
component,
fromDOM,
fromEvents,
getText,
setProperty,
setText,
show,
} from '../../..'
export type FormSpinbuttonProps = {
readonly value: number
}
export default component(
'form-spinbutton',
{
value: fromEvents<number>(
'button',
{
click: ({ target, value }) =>
value + (target.classList.contains('decrement') ? -1 : 1),
keydown: ({ event, value }) => {
const { key } = event as KeyboardEvent
if (['ArrowUp', 'ArrowDown', '-', '+'].includes(key)) {
event.stopPropagation()
event.preventDefault()
return (
value +
(key === 'ArrowDown' || key === '-' ? -1 : 1)
)
}
},
},
fromDOM({ '.value': getText() }, asInteger()),
),
},
(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('button.increment', [
setText(() => (nonZero() ? '+' : zeroLabel)),
setProperty('ariaLabel', () =>
nonZero() ? incrementLabel : zeroLabel,
),
setProperty('disabled', () => el.value >= max),
]),
]
},
)
declare global {
interface HTMLElementTagNameMap {
'form-spinbutton': Component<FormSpinbuttonProps>
}
}