'use strict';

var React = require('react');
var useButton = require('./useButton-cjs.js');
var useRenderElement = require('./useRenderElement-cjs.js');
var floatingUi_utils_dom = require('./floating-ui.utils.dom-cjs.js');

function _interopNamespaceDefault(e) {
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n.default = e;
  return Object.freeze(n);
}

var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);

let FieldControlDataAttributes = /*#__PURE__*/function (FieldControlDataAttributes) {
  /**
   * Present when the field is disabled.
   */
  FieldControlDataAttributes["disabled"] = "data-disabled";
  /**
   * Present when the field is in a valid state.
   */
  FieldControlDataAttributes["valid"] = "data-valid";
  /**
   * Present when the field is in an invalid state.
   */
  FieldControlDataAttributes["invalid"] = "data-invalid";
  /**
   * Present when the field has been touched.
   */
  FieldControlDataAttributes["touched"] = "data-touched";
  /**
   * Present when the field's value has changed.
   */
  FieldControlDataAttributes["dirty"] = "data-dirty";
  /**
   * Present when the field is filled.
   */
  FieldControlDataAttributes["filled"] = "data-filled";
  /**
   * Present when the field control is focused.
   */
  FieldControlDataAttributes["focused"] = "data-focused";
  return FieldControlDataAttributes;
}({});

const DEFAULT_VALIDITY_STATE = {
  badInput: false,
  customError: false,
  patternMismatch: false,
  rangeOverflow: false,
  rangeUnderflow: false,
  stepMismatch: false,
  tooLong: false,
  tooShort: false,
  typeMismatch: false,
  valid: null,
  valueMissing: false
};
const DEFAULT_FIELD_STATE_ATTRIBUTES = {
  valid: null,
  touched: false,
  dirty: false,
  filled: false,
  focused: false
};
const DEFAULT_FIELD_ROOT_STATE = {
  disabled: false,
  ...DEFAULT_FIELD_STATE_ATTRIBUTES
};
const fieldValidityMapping = {
  valid(value) {
    if (value === null) {
      return null;
    }
    if (value) {
      return {
        [FieldControlDataAttributes.valid]: ''
      };
    }
    return {
      [FieldControlDataAttributes.invalid]: ''
    };
  }
};

const DEFAULT_FIELD_ROOT_CONTEXT = {
  invalid: undefined,
  name: undefined,
  validityData: {
    state: DEFAULT_VALIDITY_STATE,
    errors: [],
    error: '',
    value: '',
    initialValue: null
  },
  setValidityData: useRenderElement.NOOP,
  disabled: undefined,
  touched: DEFAULT_FIELD_STATE_ATTRIBUTES.touched,
  setTouched: useRenderElement.NOOP,
  dirty: DEFAULT_FIELD_STATE_ATTRIBUTES.dirty,
  setDirty: useRenderElement.NOOP,
  filled: DEFAULT_FIELD_STATE_ATTRIBUTES.filled,
  setFilled: useRenderElement.NOOP,
  focused: DEFAULT_FIELD_STATE_ATTRIBUTES.focused,
  setFocused: useRenderElement.NOOP,
  validate: () => null,
  validationMode: 'onSubmit',
  validationDebounceTime: 0,
  shouldValidateOnChange: () => false,
  state: DEFAULT_FIELD_ROOT_STATE,
  markedDirtyRef: {
    current: false
  },
  registerFieldControl: useRenderElement.NOOP,
  validation: {
    getValidationProps: (_disabled, props = useRenderElement.EMPTY_OBJECT) => props,
    inputRef: {
      current: null
    },
    registerInput: useRenderElement.NOOP,
    commit: async () => {},
    change: useRenderElement.NOOP
  }
};
const FieldRootContext = /*#__PURE__*/React__namespace.createContext(DEFAULT_FIELD_ROOT_CONTEXT);
if (process.env.NODE_ENV !== "production") FieldRootContext.displayName = "FieldRootContext";
function useFieldRootContext(optional = true) {
  const context = React__namespace.useContext(FieldRootContext);
  if (context.setValidityData === useRenderElement.NOOP && !optional) {
    throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldRootContext is missing. Field parts must be placed within <Field.Root>.' : useRenderElement.formatErrorMessage(28));
  }
  return context;
}

function useRegisterFieldControl(controlRef, id, value, getFormValueOverride, enabled = true, name) {
  const {
    registerFieldControl
  } = useFieldRootContext();
  const sourceRef = React__namespace.useRef(null);
  if (!sourceRef.current) {
    sourceRef.current = Symbol();
  }
  useButton.useIsoLayoutEffect(() => {
    const source = sourceRef.current;
    if (!source || !enabled) {
      return undefined;
    }
    const registration = {
      controlRef,
      getValue: getFormValueOverride,
      id,
      name,
      value
    };
    registerFieldControl(source, registration);
    return () => {
      registerFieldControl(source, undefined);
    };
  }, [controlRef, enabled, getFormValueOverride, id, name, registerFieldControl, value]);
}

const FormContext = /*#__PURE__*/React__namespace.createContext({
  formRef: {
    current: {
      fields: new Map()
    }
  },
  errors: {},
  clearErrors: useRenderElement.NOOP,
  validationMode: 'onSubmit',
  submitAttemptedRef: {
    current: false
  }
});
if (process.env.NODE_ENV !== "production") FormContext.displayName = "FormContext";
function useFormContext() {
  return React__namespace.useContext(FormContext);
}

/**
 * A context for providing [labelable elements](https://html.spec.whatwg.org/multipage/forms.html#category-label)\
 * with an accessible name (label) and description.
 */
const LabelableContext = /*#__PURE__*/React__namespace.createContext({
  controlId: undefined,
  registerControlId: useRenderElement.NOOP,
  labelId: undefined,
  setLabelId: useRenderElement.NOOP,
  messageIds: [],
  setMessageIds: useRenderElement.NOOP,
  getDescriptionProps: externalProps => externalProps
});
if (process.env.NODE_ENV !== "production") LabelableContext.displayName = "LabelableContext";
function useLabelableContext() {
  return React__namespace.useContext(LabelableContext);
}

function useLabelableId(params = {}) {
  const {
    id,
    implicit = false,
    controlRef
  } = params;
  const {
    controlId,
    registerControlId
  } = useLabelableContext();
  const defaultId = useButton.useBaseUiId(id);
  const controlIdForEffect = implicit ? controlId : undefined;
  const controlSourceRef = useRenderElement.useRefWithInit(() => Symbol('labelable-control'));
  const hasRegisteredRef = React__namespace.useRef(false);
  const hadExplicitIdRef = React__namespace.useRef(id != null);
  const unregisterControlId = useButton.useStableCallback(() => {
    if (!hasRegisteredRef.current || registerControlId === useRenderElement.NOOP) {
      return;
    }
    hasRegisteredRef.current = false;
    registerControlId(controlSourceRef.current, undefined);
  });
  useButton.useIsoLayoutEffect(() => {
    if (registerControlId === useRenderElement.NOOP) {
      return undefined;
    }
    let nextId;
    if (implicit) {
      const elem = controlRef?.current;
      if (floatingUi_utils_dom.isElement(elem) && elem.closest('label') != null) {
        nextId = id ?? null;
      } else {
        nextId = controlIdForEffect ?? defaultId;
      }
    } else if (id != null) {
      hadExplicitIdRef.current = true;
      nextId = id;
    } else if (hadExplicitIdRef.current) {
      nextId = defaultId;
    } else {
      unregisterControlId();
      return undefined;
    }
    if (nextId === undefined) {
      unregisterControlId();
      return undefined;
    }
    hasRegisteredRef.current = true;
    registerControlId(controlSourceRef.current, nextId);
    return undefined;
  }, [id, controlRef, controlIdForEffect, registerControlId, implicit, defaultId, controlSourceRef, unregisterControlId]);
  React__namespace.useEffect(() => {
    return unregisterControlId;
  }, [unregisterControlId]);
  return controlId ?? defaultId;
}

exports.DEFAULT_FIELD_ROOT_CONTEXT = DEFAULT_FIELD_ROOT_CONTEXT;
exports.DEFAULT_FIELD_STATE_ATTRIBUTES = DEFAULT_FIELD_STATE_ATTRIBUTES;
exports.DEFAULT_VALIDITY_STATE = DEFAULT_VALIDITY_STATE;
exports.FieldRootContext = FieldRootContext;
exports.LabelableContext = LabelableContext;
exports.fieldValidityMapping = fieldValidityMapping;
exports.useFieldRootContext = useFieldRootContext;
exports.useFormContext = useFormContext;
exports.useLabelableContext = useLabelableContext;
exports.useLabelableId = useLabelableId;
exports.useRegisterFieldControl = useRegisterFieldControl;
