import type { JSX, ValidComponent } from "@solidjs/web"; import { dynamic } from "@solidjs/web"; import { omit, untrack } from "solid-js"; import { composeRefs, userRef } from "../internals/compose-refs"; import { mergeRootProps } from "../internals/merge-root-props"; import { resolveClassStyle } from "../internals/resolve-class-style"; import type { BaseUIComponentProps } from "../internals/types"; import { createInput, type InputState } from "./create-input.tsx"; export type { InputState }; export interface InputProps extends BaseUIComponentProps<"input", InputState> { /** * Tag/component to render. Defaults to `"input"`. Replaces the * pre-spike `render` prop (axis G). */ as?: ValidComponent; } /** * A native input element that automatically works with a surrounding * ``. Renders an `` element (or `as` override). * * Thin structural adapter over {@link createInput} — the field wiring * (labelable id, value registration, `aria-labelledby` / `aria-describedby` / * `aria-invalid` composition, touched / dirty / filled / focused setters and * the validation pipeline) lives in the primitive. Outside a `` * the primitive's contexts resolve to their NOOP form and this still renders * a plain `` with the forwarded consumer props. */ export function Input(props: InputProps): JSX.Element { const c = createInput({ value: () => props.value, disabled: () => props.disabled === true, // Setup-time read (useLabelableId consumes it once) — untrack so it // doesn't trip `[STRICT_READ_UNTRACKED]`. id: untrack(() => (typeof props.id === "string" ? props.id : undefined)), name: () => (typeof props.name === "string" ? props.name : undefined), }); // Bind the slot bag to a `const` before the JSX spread — hydration-critical. // Spreading an inline call (`{...c.control(...)}`) makes the Solid SSR // compiler wrap it in a lazy thunk whose server-side resolution diverges // from the client's, dropping attributes from the SSR markup and shifting // hydration keys. A pre-bound variable spread is passed straight through. // See `collapsible-root.tsx` for the full explanation. const userStyling = resolveClassStyle(props, () => c.state()); const userProps = omit(props, "class", "style", "attrs", "as", "id"); const styledUserProps = mergeRootProps(userStyling, userProps); const controlProps = c.control(styledUserProps); const Tag = dynamic(() => props.as ?? "input"); return ( ); }