46 lines
1.4 KiB
JavaScript
46 lines
1.4 KiB
JavaScript
import { html } from 'htm/preact'
|
|
|
|
// A labelled text input. The <label> is always rendered and visible, and it is
|
|
// always tied to the input by `for`/`id`: an aria-label is never used instead.
|
|
// `onInput` emits the string, never the event, so input and output share one format.
|
|
// `children` is grafted inside .field-control, right after the input: that is where
|
|
// a suggestion list is mounted so it sits under the field it belongs to.
|
|
// Remaining props land on the input itself, which is how a combobox molecule adds
|
|
// its ARIA (role, aria-expanded, aria-controls, aria-activedescendant) and its
|
|
// keyboard handlers without the atom knowing anything about suggestions.
|
|
export function TextField({
|
|
id,
|
|
label,
|
|
value = '',
|
|
onInput,
|
|
placeholder,
|
|
type = 'text',
|
|
autocomplete,
|
|
inputMode,
|
|
required,
|
|
describedBy,
|
|
children,
|
|
...inputProps
|
|
}) {
|
|
return html`
|
|
<div class="field">
|
|
<label class="field-label" for=${id}>${label}</label>
|
|
<div class="field-control">
|
|
<input
|
|
class="field-input"
|
|
id=${id}
|
|
type=${type}
|
|
value=${value}
|
|
placeholder=${placeholder}
|
|
autocomplete=${autocomplete}
|
|
inputMode=${inputMode}
|
|
required=${required}
|
|
aria-describedby=${describedBy}
|
|
onInput=${(event) => onInput(event.target.value)}
|
|
...${inputProps}
|
|
/>
|
|
${children}
|
|
</div>
|
|
</div>
|
|
`
|
|
}
|