import { dynamic } from "@solidjs/web";
import { createMemo, createSignal, omit } from "solid-js";
import { FieldContext } from "../../internals/field-context.jsx";
import { fieldStateAttrs } from "../../internals/field-state-attrs.jsx";
import { useFieldsetContext } from "../../internals/fieldset-context.jsx";
import { LabelableProvider } from "../../internals/labelable-provider/labelable-provider.jsx";
import { readOption } from "../../internals/maybe-accessor.jsx";
import { mergeRootProps } from "../../internals/merge-root-props.jsx";
import { resolveClassStyle } from "../../internals/resolve-class-style.jsx";
import { createField } from "../create-field.jsx";
import { FieldMessagesContext } from "../field-messages-context.jsx";
/**
 * Groups all parts of the field. Renders a `<div>` element.
 *
 * Thin structural adapter over `createField` — composes the primitive and
 * bridges its api into the `FieldContext` shape that the descendant parts
 * (`<Field.Control>`, `<Field.Label>`, etc.) consume. Also renders a
 * `<LabelableProvider>` so label/control can discover each other without
 * manual id plumbing, and a `<FieldMessagesContext>` so description/error
 * elements can contribute their ids to the control's `aria-describedby`.
 */
export function FieldRoot(props) {
  const fieldset = useFieldsetContext();

  // disabled inherits from <Fieldset.Root>
  const disabledProp = createMemo(() => (readOption(props.disabled) ?? false) || fieldset.disabled());

  // Compose the primitive. All reactive options read through accessors so
  // createField can track them without re-creating on every render.
  const c = createField({
    disabled: disabledProp,
    invalid: () => readOption(props.invalid),
    name: () => readOption(props.name),
    // Getter, not an eager read: createField reads `options.validate`
    // lazily at validation time, and an eager `props.validate` read here
    // is untracked in the component body (`[STRICT_READ_UNTRACKED]`).
    get validate() {
      return props.validate;
    },
    validationMode: () => readOption(props.validationMode),
    validationDebounceTime: () => readOption(props.validationDebounceTime),
    dirty: () => readOption(props.dirty),
    touched: () => readOption(props.touched)
  });
  const i = c._internal;

  // Bridge registerFieldControl: <Field.Control> pushes its registration
  // here via useFieldControlRegistration. We sync the control's actual
  // DOM id into createField (so the form-fields-map key matches the
  // input's id, not createField's auto-generated controlId) and seed the
  // initial value into validityData.
  let activeSource = null;
  const registerFieldControl = (source, registration) => {
    if (!registration) {
      if (activeSource !== source) return;
      activeSource = null;
      return;
    }
    activeSource = source;
    if (registration.id) {
      i.setControlId(registration.id);
    }
    i.pushInitialValue(registration);
  };

  // Published FieldContext. Maps createField's api to the FieldContextValue
  // shape that all descendant parts read from.
  const contextValue = {
    invalid: c.invalid,
    name: () => readOption(props.name),
    disabled: c.disabled,
    validityData: c.validity,
    setValidityData: i.setValidityData,
    touched: c.touched,
    setTouched: c.setTouched,
    dirty: c.dirty,
    setDirty: c.setDirty,
    filled: c.filled,
    setFilled: c.setFilled,
    focused: c.focused,
    setFocused: c.setFocused,
    state: i.state,
    validate: i.validateFn,
    validationMode: i.validationMode,
    validationDebounceTime: i.validationDebounceTime,
    shouldValidateOnChange: i.shouldValidateOnChange,
    markedDirtyRef: i.markedDirtyRef,
    registerFieldControl,
    validation: i.validation,
    present: true
  };

  // Description/Error id registry. Keyed by symbol so a description AND an
  // error can coexist; getMessageIds() returns them in registration order.
  const messageRegistrations = new Map();
  const [messageIdsSignal, setMessageIdsSignal] = createSignal(Object.freeze([]), {
    ownedWrite: true,
    equals: false
  });
  const registerMessageId = (source, id) => {
    if (id === undefined) {
      if (!messageRegistrations.has(source)) return;
      messageRegistrations.delete(source);
    } else {
      const existing = messageRegistrations.get(source);
      if (existing === id) return;
      messageRegistrations.set(source, id);
    }
    setMessageIdsSignal(Object.freeze(Array.from(messageRegistrations.values())));
  };
  const messagesContextValue = {
    registerMessageId,
    getMessageIds: messageIdsSignal,
    present: true
  };
  const userHtmlProps = omit(props, "class", "style", "attrs", "as", "disabled", "name", "validate", "validationMode", "validationDebounceTime", "invalid", "dirty", "touched", "children");
  const stateAccessor = i.state;
  const userStyling = resolveClassStyle(props, () => stateAccessor());
  const internalProps = mergeRootProps(fieldStateAttrs(stateAccessor), {
    get "data-disabled"() {
      return stateAccessor().disabled ? "" : undefined;
    }
  });
  const styledUserProps = mergeRootProps(userStyling, userHtmlProps);
  const merged = mergeRootProps(internalProps, styledUserProps);
  const Tag = dynamic(() => props.as ?? "div");
  return <Tag {...merged}>
			<FieldContext value={contextValue}>
				<FieldMessagesContext value={messagesContextValue}>
					<LabelableProvider>{props.children}</LabelableProvider>
				</FieldMessagesContext>
			</FieldContext>
		</Tag>;
}
//# sourceMappingURL=field-root.jsx.map
