Functional Weave
Code in Rust

react.form.text-field@1.0.1

impl/typescript.tsx

2,206 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

"use client";

import { useId, type JSX, type ReactNode } from "react";
import { FormField, fieldIds } from "./react_form_form_field.ts";  ← from react.form.form-field ^1.0.0 · built alongside by fune
import type { TextFieldProps } from "./react_form_text_field_types.ts";

function present(node: ReactNode): boolean {
  return node !== null && node !== undefined && node !== false && node !== "";
}

/**
 * The GOV.UK text input: a label, an optional hint and error message, and the
 * input, described by both. A prefix or suffix sits in a wrapper beside the
 * input and is aria-hidden, as GOV.UK does, so the label has to say it too
 * ("Cost, in pounds").
 */
export function TextField(props: TextFieldProps): JSX.Element {
  const auto = useId();
  const { label, hint, error, value, defaultValue, onChange, onBlur, autoComplete, inputMode, spellCheck, prefix, suffix, required, disabled, className } = props;
  const id = props.id ?? auto;
  const ids = fieldIds(id, present(hint), present(error));
  const input = (
    <input
      className={ids.error ? "fune-input fune-input--error" : "fune-input"}
      id={ids.control}
      name={props.name ?? id}
      type={props.type ?? "text"}
      value={value}
      defaultValue={defaultValue}
      autoComplete={autoComplete}
      inputMode={inputMode as JSX.IntrinsicElements["input"]["inputMode"]}
      spellCheck={spellCheck}
      required={required}
      disabled={disabled}
      aria-describedby={ids.describedBy ?? undefined}
      aria-invalid={ids.error ? true : undefined}
      onChange={(event) => onChange?.(event.target.value)}
      onBlur={onBlur ? () => onBlur() : undefined}
    />
  );
  return (
    <FormField id={id} label={label} hint={hint} error={error} className={className}>
      {present(prefix) || present(suffix) ? (
        <div className="fune-input-wrapper">
          {present(prefix) ? (
            <div className="fune-input-prefix" aria-hidden="true">
              {prefix}
            </div>
          ) : null}
          {input}
          {present(suffix) ? (
            <div className="fune-input-suffix" aria-hidden="true">
              {suffix}
            </div>
          ) : null}
        </div>
      ) : (
        input
      )}
    </FormField>
  );
}