import { dynamic } from "@solidjs/web";
import { createEffect, createMemo, omit, onCleanup, Show, untrack } from "solid-js";
import { useBaseUiId } from "../../internals/base-ui-id.jsx";
import { useFieldRootContext } from "../../internals/field-context.jsx";
import { fieldStateAttrs } from "../../internals/field-state-attrs.jsx";
import { useFormContext } from "../../internals/form-context.jsx";
import { mergeRootProps } from "../../internals/merge-root-props.jsx";
import { resolveClassStyle } from "../../internals/resolve-class-style.jsx";
import { useFieldMessagesContext } from "../field-messages-context.jsx";
/**
 * An error message displayed when the field control fails validation.
 * Renders a `<div role="alert">` element (inline — the caller can override
 * via `render`).
 *
 * Conditionally rendered via `<Show>`: no DOM node is produced when the
 * field is valid (and no override match hits). The error id is registered
 * with the surrounding `<Field.Root>`'s message registry ONLY while the
 * element is actually rendered — unmounting cleans up `onCleanup` + the
 * `<Show>` block's tear-down.
 */
export function FieldError(props) {
  const field = useFieldRootContext();
  const form = useFormContext();
  const messages = useFieldMessagesContext();

  // Stable id for the error element. Shared across the mount/unmount cycles
  // triggered by `<Show>` — the registry is what tracks presence, the id
  // itself is fixed for the component's lifetime.
  const id = useBaseUiId(untrack(() => typeof props.id === "string" ? props.id : undefined));

  // Accessor-friendly reads for `match` and `name` — any of these can drive
  // the `rendered` memo; reading them via accessors instead of at the top of
  // the component keeps Solid 2's STRICT_READ_UNTRACKED rule happy.
  const match = () => props.match;
  const name = () => field.name();
  const formError = createMemo(() => {
    const n = name();
    if (!n) return null;
    const errs = form.errors();
    const e = errs[n];
    return e === undefined ? null : e;
  });
  const rendered = createMemo(() => {
    const m = match();
    if (m === true) return true;
    if (typeof m === "string") {
      const v = field.validityData().state;
      return Boolean(v[m]);
    }
    if (formError() !== null) return true;
    return field.validityData().state.valid === false;
  });

  // Track the rendered-state transition and register/unregister the id with
  // the message registry accordingly. The registration is what makes the
  // control's `aria-describedby` pick us up.
  //
  // A split `createEffect(compute, apply)` is the right Solid 2 primitive:
  // the compute phase observes `rendered()` (tracked); the apply phase
  // writes into the registry (side effect, unowned scope, safe). Using
  // `onCleanup` in the apply is legal — it's unowned and the cleanup fires
  // on the NEXT apply OR on owner disposal.
  const source = Symbol("field-error");
  createEffect(() => rendered(), shown => {
    if (shown) {
      messages.registerMessageId(source, id);
      return () => {
        messages.registerMessageId(source, undefined);
      };
    }
  });
  // Extra safety: also unregister on root disposal. (The split-effect
  // cleanup already handles the "rendered → not rendered" transition; this
  // catches the "still rendered on disposal" case.)
  onCleanup(() => {
    messages.registerMessageId(source, undefined);
  });
  const errorMessage = createMemo(() => {
    const m = match();
    const formErr = formError();
    const validity = field.validityData();
    const hasSpecificMatch = typeof m === "string";
    const clientMessage = validity.errors.length > 1 ? <ul>
					{validity.errors.map(message => <li>{message}</li>)}
				</ul> : validity.error;
    if (hasSpecificMatch) return clientMessage;
    if (formErr != null) {
      // `formErr` may be string or string[]; match React: join arrays
      // with a newline (the consumer typically only renders the first,
      // but we surface the whole thing).
      return Array.isArray(formErr) ? formErr.join("\n") : formErr;
    }
    return clientMessage;
  });
  const userStyling = resolveClassStyle(props, () => field.state());
  const userHtmlProps = omit(props, "class", "style", "attrs", "as", "id", "match", "children");
  const internalProps = mergeRootProps(fieldStateAttrs(field.state), {
    id,
    role: "alert",
    get "data-disabled"() {
      return field.state().disabled ? "" : undefined;
    }
  });
  const styledUserProps = mergeRootProps(userStyling, userHtmlProps);
  const merged = mergeRootProps(internalProps, styledUserProps);
  const Tag = dynamic(() => props.as ?? "div");
  const element = () => <Tag {...merged}>{props.children ?? errorMessage()}</Tag>;
  return <Show when={rendered()}>{_item => element()}</Show>;
}
//# sourceMappingURL=field-error.jsx.map
