'use strict';

var tslib_es6 = require('./tslib.es6-cjs.js');
var React = require('react');
var classnames = require('classnames');
var ActivityIndicator = require('./ActivityIndicator-cjs.js');
var Button = require('./Button-cjs.js');
var Icon = require('./Icon-cjs.js');
var useRenderElement = require('./useRenderElement-cjs.js');
var useButton = require('./useButton-cjs.js');
var useLabelableId = require('./useLabelableId-cjs.js');
var jsxRuntime = require('react/jsx-runtime');
var NumberFieldInput = require('./NumberFieldInput-cjs.js');
var useLabel = require('./useLabel-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);

const FieldItemContext = /*#__PURE__*/React__namespace.createContext({
  disabled: false
});
if (process.env.NODE_ENV !== "production") FieldItemContext.displayName = "FieldItemContext";
function useFieldItemContext() {
  const context = React__namespace.useContext(FieldItemContext);
  return context;
}

const FieldsetRootContext = /*#__PURE__*/React__namespace.createContext(undefined);
if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
function useFieldsetRootContext(optional = false) {
  const context = React__namespace.useContext(FieldsetRootContext);
  if (!context && !optional) {
    throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : useRenderElement.formatErrorMessage(86));
  }
  return context;
}

const LabelableProvider = function LabelableProvider(props) {
  const defaultId = useButton.useBaseUiId();
  const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
  const [controlId, setControlIdState] = React__namespace.useState(initialControlId);
  const [labelId, setLabelId] = React__namespace.useState(props.labelId);
  const [messageIds, setMessageIds] = React__namespace.useState([]);
  const registrationsRef = useRenderElement.useRefWithInit(() => new Map());
  const {
    messageIds: parentMessageIds
  } = useLabelableId.useLabelableContext();
  const registerControlId = useButton.useStableCallback((source, nextId) => {
    const registrations = registrationsRef.current;
    if (nextId === undefined) {
      registrations.delete(source);
      return;
    }
    registrations.set(source, nextId);

    // Only flush when registering, not when unregistering.
    // This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
    // The next registration will pick up the correct state.
    setControlIdState(prev => {
      if (registrations.size === 0) {
        return undefined;
      }
      let nextControlId;
      for (const id of registrations.values()) {
        if (prev !== undefined && id === prev) {
          return prev;
        }
        if (nextControlId === undefined) {
          nextControlId = id;
        }
      }
      return nextControlId;
    });
  });
  const getDescriptionProps = React__namespace.useCallback(externalProps => {
    const ids = externalProps['aria-describedby'] ? externalProps['aria-describedby'].split(' ') : [];
    ids.push(...parentMessageIds, ...messageIds);
    return {
      ...externalProps,
      'aria-describedby': Array.from(new Set(ids)).join(' ') || undefined
    };
  }, [parentMessageIds, messageIds]);
  const contextValue = React__namespace.useMemo(() => ({
    controlId,
    registerControlId,
    labelId,
    setLabelId,
    messageIds,
    setMessageIds,
    getDescriptionProps
  }), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
  return /*#__PURE__*/jsxRuntime.jsx(useLabelableId.LabelableContext.Provider, {
    value: contextValue,
    children: props.children
  });
};
if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";

/**
 * Combines the field's client-side, stateful validity data with the external invalid state to
 * determine the field's true validity.
 */
function getCombinedFieldValidityData(validityData, invalid) {
  return {
    ...validityData,
    state: {
      ...validityData.state,
      valid: !invalid && validityData.state.valid
    }
  };
}

const validityKeys = Object.keys(useLabelableId.DEFAULT_VALIDITY_STATE);
function isOnlyValueMissing(state) {
  if (!state || state.valid || !state.valueMissing) {
    return false;
  }
  let onlyValueMissing = false;
  for (const key of validityKeys) {
    if (key === 'valid') {
      continue;
    }
    if (key === 'valueMissing') {
      onlyValueMissing = state[key];
    } else if (state[key]) {
      onlyValueMissing = false;
    }
  }
  return onlyValueMissing;
}

/**
 * Picks the input whose native validity should represent a field that owns several inputs (such as a
 * checkbox group). Prefers the first enabled currently-invalid input, where "first" follows Set
 * insertion order (mount order), and otherwise returns the first enabled input. Disabled inputs are
 * skipped because they don't participate in native constraint validation.
 */
function findRepresentativeInput(inputs) {
  let fallback = null;
  for (const input of inputs) {
    if (input.disabled) {
      continue;
    }
    if (!input.validity.valid) {
      return input;
    }
    fallback ??= input;
  }
  return fallback;
}
function clearCustomValidity(element, inputs) {
  let didClearElement = false;
  for (const input of inputs) {
    input.setCustomValidity('');
    didClearElement ||= input === element;
  }
  if (!didClearElement) {
    element.setCustomValidity('');
  }
}
function useFieldValidation(params) {
  const {
    formRef
  } = useLabelableId.useFormContext();
  const {
    setValidityData,
    validate,
    validityData,
    validationDebounceTime,
    invalid,
    markedDirtyRef,
    state,
    shouldValidateOnChange,
    getRegisteredFieldId
  } = params;
  const {
    controlId,
    getDescriptionProps
  } = useLabelableId.useLabelableContext();
  const timeout = useButton.useTimeout();
  const inputRef = React__namespace.useRef(null);
  const registeredInputs = useRenderElement.useRefWithInit(() => new Set()).current;
  const validationCommitIdRef = React__namespace.useRef(0);

  // Checkbox groups register several inputs against a single field. Track them so a `required`
  // checkbox can't be satisfied by another input in the group, matching native per-checkbox behavior.
  const registerInput = React__namespace.useCallback(element => {
    if (!element) {
      return undefined;
    }
    registeredInputs.add(element);
    return () => {
      registeredInputs.delete(element);
    };
  }, [registeredInputs]);
  const commit = useButton.useStableCallback(async (value, revalidate = false) => {
    // A field can own several inputs (a checkbox group), but only the last-mounted one wins the shared
    // `inputRef`. Validate against the registry instead so every input counts; `inputRef` is the
    // fallback only when no registered input applies (none registered, or all of them disabled).
    const element = findRepresentativeInput(registeredInputs) ?? inputRef.current;
    if (!element) {
      return;
    }
    validationCommitIdRef.current += 1;
    const validationCommitId = validationCommitIdRef.current;
    function updateRegisteredFieldValidity(nextValidityData, externalInvalid = invalid) {
      const fieldId = getRegisteredFieldId() ?? controlId;
      if (fieldId == null) {
        return;
      }
      const currentFieldData = formRef.current.fields.get(fieldId);
      if (!currentFieldData) {
        return;
      }
      const validityDataWithFormErrors = getCombinedFieldValidityData(nextValidityData, externalInvalid);
      formRef.current.fields.set(fieldId, {
        ...currentFieldData,
        validityData: validityDataWithFormErrors
      });
    }
    if (revalidate) {
      if (state.valid !== false) {
        return;
      }
      const currentNativeValidity = element.validity;
      if (!currentNativeValidity.valueMissing) {
        // The 'valueMissing' (required) condition has been resolved by the user typing.
        // Temporarily mark the field as valid for this onChange event.
        // Other native errors (e.g., typeMismatch) will be caught by full validation on blur or submit.
        const nextValidityData = {
          value,
          state: {
            ...useLabelableId.DEFAULT_VALIDITY_STATE,
            valid: true
          },
          error: '',
          errors: [],
          initialValue: validityData.initialValue
        };
        clearCustomValidity(element, registeredInputs);

        // The required value is now present; ignore stale external invalid state for this pass.
        updateRegisteredFieldValidity(nextValidityData, false);
        setValidityData(nextValidityData);
        return;
      }

      // Value is still missing, or other conditions apply.
      // Let's use a representation of current validity for isOnlyValueMissing.
      const currentNativeValidityObject = validityKeys.reduce((acc, key) => {
        acc[key] = currentNativeValidity[key];
        return acc;
      }, {});

      // If it's (still) natively invalid due to something other than just valueMissing,
      // then bail from this revalidation on change to avoid "scolding" for other errors.
      if (!currentNativeValidityObject.valid && !isOnlyValueMissing(currentNativeValidityObject)) {
        return;
      }

      // If valueMissing is still true AND it's the only issue, or if the field is now natively valid,
      // let it fall through to the main validation logic below.
    }
    function getState(el) {
      const computedState = validityKeys.reduce((acc, key) => {
        acc[key] = el.validity[key];
        return acc;
      }, {});
      let hasOnlyValueMissingError = false;
      for (const key of validityKeys) {
        if (key === 'valid') {
          continue;
        }
        if (key === 'valueMissing' && computedState[key]) {
          hasOnlyValueMissingError = true;
        } else if (computedState[key]) {
          return computedState;
        }
      }

      // Only make `valueMissing` mark the field invalid if it's been changed
      // to reduce error noise.
      if (hasOnlyValueMissingError && !markedDirtyRef.current) {
        computedState.valid = true;
        computedState.valueMissing = false;
      }
      return computedState;
    }
    timeout.clear();
    let result = null;
    let validationErrors = [];
    const nextState = getState(element);
    let defaultValidationMessage;
    const isValidatingOnChange = shouldValidateOnChange();
    if (element.validationMessage && !isValidatingOnChange) {
      // not validating on change, if there is a `validationMessage` from
      // native validity, set errors and skip calling the custom validate fn
      defaultValidationMessage = element.validationMessage;
      validationErrors = [element.validationMessage];
    } else {
      // call the validate function because either
      // - validating on change, or
      // - native constraint validations passed, custom validity check is next
      const formValues = Array.from(formRef.current.fields.values()).reduce((acc, field) => {
        if (field.name) {
          acc[field.name] = field.getValue();
        }
        return acc;
      }, {});
      const resultOrPromise = validate(value, formValues);
      if (typeof resultOrPromise === 'object' && resultOrPromise !== null && 'then' in resultOrPromise) {
        result = await resultOrPromise;
        if (validationCommitId !== validationCommitIdRef.current) {
          return;
        }
      } else {
        result = resultOrPromise;
      }
      if (result !== null) {
        nextState.valid = false;
        nextState.customError = true;
        if (Array.isArray(result)) {
          validationErrors = result;
          element.setCustomValidity(result.join('\n'));
        } else if (result) {
          validationErrors = [result];
          element.setCustomValidity(result);
        }
      } else if (isValidatingOnChange) {
        // validate function returned no errors, if validating on change
        // we need to clear the custom validity state
        clearCustomValidity(element, registeredInputs);
        nextState.customError = false;
        if (element.validationMessage) {
          defaultValidationMessage = element.validationMessage;
          validationErrors = [element.validationMessage];
        } else if (element.validity.valid && !nextState.valid) {
          nextState.valid = true;
        }
      }
    }
    const nextValidityData = {
      value,
      state: nextState,
      error: defaultValidationMessage ?? (Array.isArray(result) ? result[0] : result ?? ''),
      errors: validationErrors,
      initialValue: validityData.initialValue
    };

    // Keep Form-level errors part of overall field validity for submit blocking/focus logic.
    updateRegisteredFieldValidity(nextValidityData);
    setValidityData(nextValidityData);
  });
  const change = useButton.useStableCallback(value => {
    timeout.clear();
    const validateOnChange = shouldValidateOnChange();
    if (validateOnChange && value !== '' && validationDebounceTime) {
      validationCommitIdRef.current += 1;
      timeout.start(validationDebounceTime, () => {
        commit(value);
      });
    } else {
      commit(value, !validateOnChange);
    }
  });
  const getValidationProps = React__namespace.useCallback((disabled, externalProps = {}) => useRenderElement.mergeProps(getDescriptionProps(externalProps), state.valid === false && !state.disabled && !disabled ? {
    'aria-invalid': true
  } : useRenderElement.EMPTY_OBJECT), [getDescriptionProps, state.disabled, state.valid]);
  return React__namespace.useMemo(() => ({
    getValidationProps,
    inputRef,
    registerInput,
    commit,
    change
  }), [getValidationProps, registerInput, commit, change]);
}

function useFieldControlRegistration(params) {
  const {
    commit,
    invalid,
    markedDirtyRef,
    name,
    setRegisteredFieldName,
    setRegisteredFieldId,
    setValidityData,
    validityData
  } = params;
  const {
    formRef
  } = useLabelableId.useFormContext();
  const activeFieldControlSourceRef = React__namespace.useRef(null);
  const registrationRef = React__namespace.useRef(null);
  const fallbackControlRef = React__namespace.useRef(null);
  const getValueForForm = useButton.useStableCallback(() => {
    const registration = registrationRef.current;
    if (!registration) {
      return undefined;
    }
    if (registration.getValue) {
      return registration.getValue();
    }
    return registration.value;
  });
  function getRegistrationValue(registration) {
    return registration.value === undefined ? getValueForForm() : registration.value;
  }
  const validate = useButton.useStableCallback(() => {
    const registration = registrationRef.current;
    markedDirtyRef.current = true;
    if (!registration) {
      commit(validityData.value);
      return;
    }
    commit(getRegistrationValue(registration));
  });
  function refreshRegistration() {
    const registration = registrationRef.current;
    if (!registration || !registration.id) {
      return;
    }
    formRef.current.fields.set(registration.id, {
      getValue: getValueForForm,
      name: name ?? registration.name,
      controlRef: registration.controlRef ?? fallbackControlRef,
      validityData: getCombinedFieldValidityData(validityData, invalid),
      validate
    });
  }
  function deleteRegistration(id = registrationRef.current?.id) {
    if (id) {
      formRef.current.fields.delete(id);
    }
  }
  function syncInitialValue() {
    const registration = registrationRef.current;
    if (!registration) {
      return;
    }
    const initialValue = getRegistrationValue(registration);
    if (validityData.initialValue === null && initialValue !== null) {
      setValidityData(prev => ({
        ...prev,
        initialValue
      }));
    }
  }
  useButton.useIsoLayoutEffect(() => {
    const registration = registrationRef.current;
    if (!registration || !registration.id) {
      return;
    }
    setRegisteredFieldName(name ? undefined : registration.name);
    formRef.current.fields.set(registration.id, {
      getValue: getValueForForm,
      name: name ?? registration.name,
      controlRef: registration.controlRef ?? fallbackControlRef,
      validityData: getCombinedFieldValidityData(validityData, invalid),
      validate
    });
  }, [formRef, getValueForForm, invalid, name, setRegisteredFieldName, validate, validityData]);
  useButton.useIsoLayoutEffect(() => {
    const fields = formRef.current.fields;
    return () => {
      const id = registrationRef.current?.id;
      if (id) {
        fields.delete(id);
      }
    };
  }, [formRef]);
  const register = useButton.useStableCallback((source, registration) => {
    if (!registration) {
      if (activeFieldControlSourceRef.current === source) {
        activeFieldControlSourceRef.current = null;
        deleteRegistration();
        registrationRef.current = null;
        setRegisteredFieldName(undefined);
        setRegisteredFieldId(undefined);
      }
      return;
    }
    const previousId = registrationRef.current?.id;
    activeFieldControlSourceRef.current = source;
    registrationRef.current = registration;
    if (!name) {
      setRegisteredFieldName(registration.name);
    }
    setRegisteredFieldId(registration.id);
    if (previousId && previousId !== registration.id) {
      deleteRegistration(previousId);
    }
    syncInitialValue();
    refreshRegistration();
  });
  return [validate, register];
}

const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRootInner(componentProps, forwardedRef) {
  const {
    errors,
    validationMode: formValidationMode,
    submitAttemptedRef
  } = useLabelableId.useFormContext();
  const {
    render,
    className,
    validate: validateProp,
    validationDebounceTime = 0,
    validationMode = formValidationMode,
    name,
    disabled: disabledProp = false,
    invalid: invalidProp,
    dirty: dirtyProp,
    touched: touchedProp,
    actionsRef,
    style,
    ...elementProps
  } = componentProps;
  const disabledFieldset = useFieldsetRootContext(true)?.disabled;
  const validate = useButton.useStableCallback(validateProp || (() => null));
  const disabled = disabledFieldset || disabledProp;
  const [touchedState, setTouchedUnwrapped] = React__namespace.useState(false);
  const [dirtyState, setDirtyUnwrapped] = React__namespace.useState(false);
  const [filled, setFilled] = React__namespace.useState(false);
  const [focused, setFocused] = React__namespace.useState(false);
  const dirty = dirtyProp ?? dirtyState;
  const touched = touchedProp ?? touchedState;
  const markedDirtyRef = React__namespace.useRef(dirty);
  const registeredFieldIdRef = React__namespace.useRef(undefined);
  const [registeredFieldName, setRegisteredFieldName] = React__namespace.useState();
  const effectiveName = name ?? registeredFieldName;
  useButton.useIsoLayoutEffect(() => {
    if (dirtyProp !== undefined) {
      markedDirtyRef.current = dirtyProp;
    }
  }, [dirtyProp]);
  const getRegisteredFieldId = React__namespace.useCallback(() => registeredFieldIdRef.current, []);
  const setRegisteredFieldId = React__namespace.useCallback(id => {
    registeredFieldIdRef.current = id;
  }, []);
  const setDirty = useButton.useStableCallback(value => {
    if (dirtyProp !== undefined) {
      return;
    }
    if (value) {
      markedDirtyRef.current = true;
    }
    setDirtyUnwrapped(value);
  });
  const setTouched = useButton.useStableCallback(value => {
    if (touchedProp !== undefined) {
      return;
    }
    setTouchedUnwrapped(value);
  });
  const shouldValidateOnChange = useButton.useStableCallback(() => validationMode === 'onChange' || validationMode === 'onSubmit' && submitAttemptedRef.current);
  const formError = effectiveName && Object.hasOwn(errors, effectiveName) ? errors[effectiveName] : null;
  const hasFormError = !!(Array.isArray(formError) ? formError.length : formError);
  const invalid = invalidProp === true || hasFormError;
  const [validityData, setValidityData] = React__namespace.useState({
    state: useLabelableId.DEFAULT_VALIDITY_STATE,
    error: '',
    errors: [],
    value: null,
    initialValue: null
  });
  const valid = disabled ? null : !invalid && validityData.state.valid;
  const state = React__namespace.useMemo(() => ({
    disabled,
    touched,
    dirty,
    valid,
    filled,
    focused
  }), [disabled, touched, dirty, valid, filled, focused]);
  const validation = useFieldValidation({
    setValidityData,
    validate,
    validityData,
    validationDebounceTime,
    invalid,
    markedDirtyRef,
    state,
    shouldValidateOnChange,
    getRegisteredFieldId
  });
  const [validateFieldControl, registerFieldControl] = useFieldControlRegistration({
    commit: validation.commit,
    invalid,
    markedDirtyRef,
    name,
    setRegisteredFieldName,
    setRegisteredFieldId,
    setValidityData,
    validityData
  });
  React__namespace.useImperativeHandle(actionsRef, () => ({
    validate: validateFieldControl
  }), [validateFieldControl]);
  const contextValue = React__namespace.useMemo(() => ({
    invalid,
    name: effectiveName,
    validityData,
    setValidityData,
    disabled,
    touched,
    setTouched,
    dirty,
    setDirty,
    filled,
    setFilled,
    focused,
    setFocused,
    validate,
    validationMode,
    validationDebounceTime,
    shouldValidateOnChange,
    state,
    markedDirtyRef,
    registerFieldControl,
    validation
  }), [invalid, effectiveName, validityData, disabled, touched, setTouched, dirty, setDirty, filled, setFilled, focused, setFocused, validate, validationMode, validationDebounceTime, shouldValidateOnChange, state, registerFieldControl, validation]);
  const element = useRenderElement.useRenderElement('div', componentProps, {
    ref: forwardedRef,
    state,
    props: elementProps,
    stateAttributesMapping: useLabelableId.fieldValidityMapping
  });
  return /*#__PURE__*/jsxRuntime.jsx(useLabelableId.FieldRootContext.Provider, {
    value: contextValue,
    children: element
  });
});

/**
 * Groups all parts of the field.
 * Renders a `<div>` element.
 *
 * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
 */
if (process.env.NODE_ENV !== "production") FieldRootInner.displayName = "FieldRootInner";
const FieldRoot = /*#__PURE__*/React__namespace.forwardRef(function FieldRoot(componentProps, forwardedRef) {
  return /*#__PURE__*/jsxRuntime.jsx(LabelableProvider, {
    children: /*#__PURE__*/jsxRuntime.jsx(FieldRootInner, {
      ...componentProps,
      ref: forwardedRef
    })
  });
});
if (process.env.NODE_ENV !== "production") FieldRoot.displayName = "FieldRoot";

/**
 * An accessible label that is automatically associated with the field control.
 * Renders a `<label>` element.
 *
 * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
 */
const FieldLabel = /*#__PURE__*/React__namespace.forwardRef(function FieldLabel(componentProps, forwardedRef) {
  const {
    render,
    className,
    style,
    id: idProp,
    nativeLabel = true,
    ...elementProps
  } = componentProps;
  const fieldRootContext = useLabelableId.useFieldRootContext(false);
  const fieldItemContext = useFieldItemContext();
  const {
    labelId
  } = useLabelableId.useLabelableContext();
  const state = {
    ...fieldRootContext.state,
    disabled: fieldRootContext.disabled || fieldItemContext.disabled
  };
  const labelRef = React__namespace.useRef(null);
  const labelProps = useLabel.useLabel({
    id: labelId ?? idProp,
    native: nativeLabel
  });
  if (process.env.NODE_ENV !== 'production') {
    // eslint-disable-next-line react-hooks/rules-of-hooks
    React__namespace.useEffect(() => {
      if (!labelRef.current) {
        return;
      }
      const isLabelTag = labelRef.current.tagName === 'LABEL';
      if (nativeLabel) {
        if (!isLabelTag) {
          const ownerStackMessage = useButton.SafeReact.captureOwnerStack?.() || '';
          const message = '<Field.Label> expected a <label> element because the `nativeLabel` prop is true. ' + 'Rendering a non-<label> disables native label association, so `htmlFor` will not ' + 'work. Use a real <label> in the `render` prop, or set `nativeLabel` to `false`.';
          useButton.error(`${message}${ownerStackMessage}`);
        }
      } else if (isLabelTag) {
        const ownerStackMessage = useButton.SafeReact.captureOwnerStack?.() || '';
        const message = '<Field.Label> expected a non-<label> element because the `nativeLabel` prop is false. ' + 'Rendering a <label> assumes native label behavior while Base UI treats it as ' + 'non-native, which can cause unexpected pointer behavior. Use a non-<label> in the ' + '`render` prop, or set `nativeLabel` to `true`.';
        useButton.error(`${message}${ownerStackMessage}`);
      }
    }, [nativeLabel]);
  }
  const element = useRenderElement.useRenderElement('label', componentProps, {
    ref: [forwardedRef, labelRef],
    state,
    props: [labelProps, elementProps],
    stateAttributesMapping: useLabelableId.fieldValidityMapping
  });
  return element;
});
if (process.env.NODE_ENV !== "production") FieldLabel.displayName = "FieldLabel";

const stateAttributesMapping = {
  ...useLabelableId.fieldValidityMapping,
  ...useButton.transitionStatusMapping
};

/**
 * An error message displayed if the field control fails validation.
 * Renders a `<div>` element.
 *
 * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
 */
const FieldError = /*#__PURE__*/React__namespace.forwardRef(function FieldError(componentProps, forwardedRef) {
  const {
    render,
    id: idProp,
    className,
    match,
    style,
    ...elementProps
  } = componentProps;
  const id = useButton.useBaseUiId(idProp);
  const {
    validityData,
    state: fieldState,
    name
  } = useLabelableId.useFieldRootContext(false);
  const {
    setMessageIds
  } = useLabelableId.useLabelableContext();
  const {
    errors
  } = useLabelableId.useFormContext();
  const formError = name && Object.hasOwn(errors, name) ? errors[name] : null;
  const hasFormError = !!(Array.isArray(formError) ? formError.length : formError);
  const hasSpecificMatch = typeof match === 'string';
  let rendered = false;
  if (match === true) {
    rendered = true;
  } else if (fieldState.disabled) {
    rendered = false;
  } else if (hasSpecificMatch) {
    rendered = Boolean(validityData.state[match]);
  } else {
    rendered = hasFormError || validityData.state.valid === false;
  }
  const {
    mounted,
    transitionStatus,
    setMounted
  } = useButton.useTransitionStatus(rendered);
  useButton.useIsoLayoutEffect(() => {
    if (!rendered || !id) {
      return undefined;
    }
    setMessageIds(v => v.concat(id));
    return () => {
      setMessageIds(v => v.filter(item => item !== id));
    };
  }, [rendered, id, setMessageIds]);
  const errorRef = React__namespace.useRef(null);
  const [lastRenderedMessage, setLastRenderedMessage] = React__namespace.useState(null);
  const [lastRenderedMessageKey, setLastRenderedMessageKey] = React__namespace.useState(null);
  let error = validityData.error;
  if (!hasSpecificMatch && hasFormError) {
    error = formError;
  } else if (validityData.errors.length > 1) {
    error = validityData.errors;
  }
  let errorMessage = error ?? '';
  if (Array.isArray(error)) {
    errorMessage = error.length > 1 ? /*#__PURE__*/jsxRuntime.jsx("ul", {
      children: error.map(message => /*#__PURE__*/jsxRuntime.jsx("li", {
        children: message
      }, message))
    }) : error[0] ?? '';
  }
  const errorKey = Array.isArray(error) ? JSON.stringify(error) : error;
  if (rendered && errorKey !== lastRenderedMessageKey) {
    setLastRenderedMessageKey(errorKey);
    setLastRenderedMessage(errorMessage);
  }
  useButton.useOpenChangeComplete({
    open: rendered,
    ref: errorRef,
    onComplete() {
      if (!rendered) {
        setMounted(false);
      }
    }
  });
  const state = {
    ...fieldState,
    transitionStatus
  };
  const element = useRenderElement.useRenderElement('div', componentProps, {
    ref: [forwardedRef, errorRef],
    state,
    props: [{
      id,
      children: rendered ? errorMessage : lastRenderedMessage
    }, elementProps],
    stateAttributesMapping,
    enabled: mounted
  });
  if (!mounted) {
    return null;
  }
  return element;
});
if (process.env.NODE_ENV !== "production") FieldError.displayName = "FieldError";

/**
 * A paragraph with additional information about the field.
 * Renders a `<p>` element.
 *
 * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
 */
const FieldDescription = /*#__PURE__*/React__namespace.forwardRef(function FieldDescription(componentProps, forwardedRef) {
  const {
    render,
    id: idProp,
    className,
    style,
    ...elementProps
  } = componentProps;
  const id = useButton.useBaseUiId(idProp);
  const fieldRootContext = useLabelableId.useFieldRootContext(false);
  const fieldItemContext = useFieldItemContext();
  const {
    setMessageIds
  } = useLabelableId.useLabelableContext();
  const state = {
    ...fieldRootContext.state,
    disabled: fieldRootContext.disabled || fieldItemContext.disabled
  };
  useButton.useIsoLayoutEffect(() => {
    if (!id) {
      return undefined;
    }
    setMessageIds(v => v.concat(id));
    return () => {
      setMessageIds(v => v.filter(item => item !== id));
    };
  }, [id, setMessageIds]);
  const element = useRenderElement.useRenderElement('p', componentProps, {
    ref: forwardedRef,
    state,
    props: [{
      id
    }, elementProps],
    stateAttributesMapping: useLabelableId.fieldValidityMapping
  });
  return element;
});
if (process.env.NODE_ENV !== "production") FieldDescription.displayName = "FieldDescription";

var styles = {"container":"_6HZLFIOZh4s-","inline":"_-6ndFYNKKaM-","wrapper":"c20czk-FSyY-","disabled":"_-2INirAxaU4-","small":"NsFBA5oqRAA-","large":"ExKqck-6xVs-","center":"UWiqNi57G8g-","right":"po25PZwJpe4-","inputWrapper":"k9dAO6d010o-","input":"D-PmE-l-hZU-","stepper":"t42w4ZDiDyI-","loadingIndicator":"NLptJ1t9Pj4-","label":"Ggk3aaMcIJU-","hideLabel":"C7d6qmoZiKU-","affixLabel":"_4u1JHjUYvkY-","prefix":"rEWH41rUUEE-","suffix":"_4-iNl6jdfmM-","affixIcon":"_5-Iw-2c-wXk-","compoundAffix":"tZjZRRcAShY-","affixLabelText":"mbEcqyBQoEg-","stepperButton":"zzrCzYF-8u0-","belowField":"_0mcAZAtwQ2o-","description":"xxp2uGc-B6o-","fieldError":"q-WsOi6joGo-","spinning":"d0TEiLWObKU-"};

/**
 * Default formatting used only when the consumer does not pass `format`.
 * Base UI rounds committed values to `maximumFractionDigits`, so this cap also
 * scrubs IEEE-754 step drift (keeps `3.14 + 1` from committing
 * `4.140000000000001`). 12 sits below that noise floor while keeping more
 * precision than a numeric field needs.
 */
const DEFAULT_FORMAT = {
    useGrouping: false,
    maximumFractionDigits: 12,
};
const InputNumberExperimentalContext = React.createContext(null);
function useInputNumberExperimentalContext(consumer) {
    const context = React.useContext(InputNumberExperimentalContext);
    if (context === null) {
        throw new Error(`<InputNumberExperimental.${consumer}> must be used inside <InputNumberExperimental.Wrapper>.`);
    }
    return context;
}
function InputNumberExperimentalWrapper(_a) {
    var { ref } = _a, props = tslib_es6.__rest(_a, ["ref"]);
    const { align, autoComplete, children, className, disabled, format, id: idProp, inline, inputMode, invalid, loading, max, min, name, onBlur, onEnter, onFocus, onKeyDown, onKeyUp, onValueChange, onValueCommitted, readOnly, showMiniLabel = true, size = "default", step = 1, style, value, } = props;
    const generatedId = React.useId();
    const id = idProp !== null && idProp !== void 0 ? idProp : generatedId;
    const innerInputRef = React.useRef(null);
    React.useImperativeHandle(ref, () => ({
        focus: () => { var _a; return (_a = innerInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
        blur: () => { var _a; return (_a = innerInputRef.current) === null || _a === void 0 ? void 0 : _a.blur(); },
    }), []);
    const handleValueCommitted = React.useCallback((newValue) => onValueCommitted === null || onValueCommitted === void 0 ? void 0 : onValueCommitted(newValue), [onValueCommitted]);
    const handleValueChange = React.useCallback((newValue) => onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(newValue), [onValueChange]);
    const handleKeyDown = React.useCallback((event) => {
        onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
        if (event.key === "Enter" &&
            !event.shiftKey &&
            !event.ctrlKey &&
            !event.metaKey) {
            onEnter === null || onEnter === void 0 ? void 0 : onEnter(event);
            // Commit on Enter. Base UI commits on blur, not Enter, so round-trip
            // focus to fire onValueCommitted via blur and restore focus immediately.
            const target = event.currentTarget;
            target.blur();
            target.focus();
        }
    }, [onKeyDown, onEnter]);
    // `handleKeyDown` transitively tracks `onKeyDown`/`onEnter` via its own deps,
    // so they are intentionally not listed separately here.
    const contextValue = React.useMemo(() => ({
        align,
        autoComplete,
        disabled,
        format,
        id,
        innerInputRef,
        inputMode,
        loading,
        max,
        min,
        onBlur,
        onFocus,
        onKeyDown: handleKeyDown,
        onKeyUp,
        onValueChange: handleValueChange,
        onValueCommitted: handleValueCommitted,
        readOnly,
        showMiniLabel,
        showStepper: !disabled && !readOnly,
        size,
        step,
        value,
    }), [
        align,
        autoComplete,
        disabled,
        format,
        id,
        inputMode,
        loading,
        max,
        min,
        onBlur,
        onFocus,
        handleKeyDown,
        onKeyUp,
        handleValueChange,
        handleValueCommitted,
        readOnly,
        showMiniLabel,
        size,
        step,
        value,
    ]);
    const rootProps = useRenderElement.mergeProps({ className: classnames(styles.container, inline && styles.inline) }, { className, style });
    return (React.createElement(FieldRoot, Object.assign({}, rootProps, { disabled: disabled, invalid: invalid || undefined, name: name }),
        React.createElement(InputNumberExperimentalContext.Provider, { value: contextValue }, children)));
}
function InputNumberExperimentalGroup({ children, className, style, }) {
    var _a, _b;
    const ctx = useInputNumberExperimentalContext("Group");
    const groupProps = useRenderElement.mergeProps({
        className: classnames(styles.wrapper, ctx.align && styles[ctx.align], ctx.disabled && styles.disabled, ctx.size !== "default" && styles[ctx.size]),
    }, { className, style });
    return (React.createElement(NumberFieldInput.NumberFieldRoot, { allowOutOfRange: true, format: (_a = ctx.format) !== null && _a !== void 0 ? _a : DEFAULT_FORMAT, id: ctx.id, max: ctx.max, min: ctx.min, onValueChange: ctx.onValueChange, onValueCommitted: ctx.onValueCommitted, readOnly: ctx.readOnly, step: ctx.step, value: (_b = ctx.value) !== null && _b !== void 0 ? _b : null },
        React.createElement(NumberFieldInput.NumberFieldGroup, Object.assign({}, groupProps), children)));
}
function InputNumberExperimentalFooter({ children, className, style, }) {
    useInputNumberExperimentalContext("Footer");
    const rootProps = useRenderElement.mergeProps({ className: styles.belowField }, { className, style });
    return React.createElement("div", Object.assign({}, rootProps), children);
}
function InputNumberExperimentalInput({ children, className, style, }) {
    const ctx = useInputNumberExperimentalContext("Input");
    const rootProps = useRenderElement.mergeProps({
        className: classnames(styles.inputWrapper, !ctx.showMiniLabel && styles.hideLabel, ctx.size !== "default" && styles[ctx.size], ctx.disabled && styles.disabled),
    }, { className, style });
    return (React.createElement("div", Object.assign({}, rootProps),
        React.createElement(NumberFieldInput.NumberFieldInput, { "aria-busy": ctx.loading || undefined, autoComplete: resolveAutoComplete(ctx.autoComplete), className: styles.input, inputMode: ctx.inputMode, onBlur: ctx.onBlur, onFocus: ctx.onFocus, onKeyDown: ctx.onKeyDown, onKeyUp: ctx.onKeyUp, placeholder: " ", ref: ctx.innerInputRef }),
        children));
}
function InputNumberExperimentalLabel({ children, className, style, }) {
    const ctx = useInputNumberExperimentalContext("Label");
    if (!children)
        return null;
    return (React.createElement(FieldLabel, { className: classnames(styles.label, className), htmlFor: ctx.id, style: style }, children));
}
function InputNumberExperimentalDescription({ children, className, style, }) {
    useInputNumberExperimentalContext("Description");
    if (!children)
        return null;
    return (React.createElement(FieldDescription, { className: classnames(styles.description, className), style: style }, children));
}
function InputNumberExperimentalError({ children, className, style, }) {
    useInputNumberExperimentalContext("Error");
    if (!children)
        return null;
    return (React.createElement(FieldError, { className: classnames(styles.fieldError, className), match: true, role: "alert", style: style }, children));
}
function InputNumberExperimentalLoading({ children, className, style, }) {
    useInputNumberExperimentalContext("Loading");
    const rootProps = useRenderElement.mergeProps({ className: styles.loadingIndicator }, { className, style });
    return (React.createElement("div", Object.assign({}, rootProps), children !== null && children !== void 0 ? children : React.createElement(ActivityIndicator.ActivityIndicator, { size: "small" })));
}
function InputNumberExperimentalStepper({ children, incrementLabel, decrementLabel, className, style, }) {
    const ctx = useInputNumberExperimentalContext("Stepper");
    if (ctx.loading || !ctx.showStepper) {
        return null;
    }
    const rootProps = useRenderElement.mergeProps({ className: styles.stepper }, { className, style });
    return (React.createElement("div", Object.assign({}, rootProps), children !== null && children !== void 0 ? children : (React.createElement(React.Fragment, null,
        React.createElement(InputNumberExperimentalIncrement, { ariaLabel: incrementLabel }),
        React.createElement(InputNumberExperimentalDecrement, { ariaLabel: decrementLabel })))));
}
function InputNumberExperimentalIncrement({ children, ariaLabel, className, style, }) {
    useInputNumberExperimentalContext("Increment");
    const rootProps = useRenderElement.mergeProps({ className: styles.stepperButton }, { className, style });
    return (React.createElement(NumberFieldInput.NumberFieldIncrement, Object.assign({ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "Increase value" }, rootProps), children !== null && children !== void 0 ? children : (React.createElement(Icon.Icon, { name: "arrowUp", size: "small", customColor: "currentColor" }))));
}
function InputNumberExperimentalDecrement({ children, ariaLabel, className, style, }) {
    useInputNumberExperimentalContext("Decrement");
    const rootProps = useRenderElement.mergeProps({ className: styles.stepperButton }, { className, style });
    return (React.createElement(NumberFieldInput.NumberFieldDecrement, Object.assign({ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "Decrease value" }, rootProps), children !== null && children !== void 0 ? children : (React.createElement(Icon.Icon, { name: "arrowDown", size: "small", customColor: "currentColor" }))));
}
function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, children, className, style, }) {
    const ctx = useInputNumberExperimentalContext("Affix");
    if (!icon && !label && !children) {
        return null;
    }
    const rootProps = useRenderElement.mergeProps({
        className: classnames(styles.compoundAffix, variation === "suffix" && styles.suffix),
    }, { className, style });
    return (React.createElement("div", Object.assign({}, rootProps),
        icon && (React.createElement(AffixIconContent, { icon: icon, size: ctx.size, onClick: onClick, ariaLabel: ariaLabel })),
        label && React.createElement("span", { className: styles.affixLabelText }, label),
        children));
}
/**
 * Renders the prop-driven `prefix`/`suffix` affixes for the sugar component.
 * Icons sit outside the input area; labels render next to the typed value
 * (suffix mirrors the order). The composable `.Affix` part is the alternative
 * when composing the field directly.
 */
function renderDefaultAffix(variation, affix, size) {
    const icon = affix.icon && (React.createElement(AffixIconSlot, { variation: variation, icon: affix.icon, size: size, ariaLabel: "ariaLabel" in affix ? affix.ariaLabel : undefined, onClick: "onClick" in affix ? affix.onClick : undefined }));
    const affixLabel = affix.label && (React.createElement(AffixLabelSlot, { variation: variation, label: affix.label }));
    return variation === "prefix" ? (React.createElement(React.Fragment, null,
        icon,
        affixLabel)) : (React.createElement(React.Fragment, null,
        affixLabel,
        icon));
}
function AffixIconSlot({ variation, icon, size, onClick, ariaLabel, }) {
    return (React.createElement("div", { className: classnames(styles.affixIcon, variation === "suffix" && styles.suffix) },
        React.createElement(AffixIconContent, { icon: icon, size: size, onClick: onClick, ariaLabel: ariaLabel })));
}
function AffixIconContent({ icon, size, onClick, ariaLabel, }) {
    const iconSize = size === "small" ? "small" : "base";
    if (onClick) {
        return (React.createElement(Button.Button, { ariaLabel: ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "Action", icon: icon, onClick: onClick, size: iconSize, type: "tertiary", variation: "subtle" }));
    }
    return React.createElement(Icon.Icon, { name: icon, size: iconSize, color: "greyBlue" });
}
function AffixLabelSlot({ variation, label }) {
    return (React.createElement("div", { className: classnames(styles.affixLabel, variation === "prefix" && styles.prefix, variation === "suffix" && styles.suffix) }, label));
}
function resolveAutoComplete(autoComplete) {
    if (autoComplete === false)
        return "off";
    if (autoComplete === true || autoComplete === undefined)
        return undefined;
    return autoComplete;
}
/**
 * Sugar layer: composes the parts from props. This is the same composition a
 * consumer would write by hand with `<InputNumberExperimental.Wrapper>` and the
 * parts — to customize a single piece, copy this tree and swap that part.
 */
function InputNumberExperimental(_a) {
    var _b;
    var { ref } = _a, props = tslib_es6.__rest(_a, ["ref"]);
    const { label, description, error, prefix, suffix } = props, config = tslib_es6.__rest(props, ["label", "description", "error", "prefix", "suffix"]);
    const size = (_b = config.size) !== null && _b !== void 0 ? _b : "default";
    return (React.createElement(InputNumberExperimentalWrapper, Object.assign({}, config, { invalid: config.invalid || Boolean(error), ref: ref }),
        React.createElement(InputNumberExperimentalGroup, null,
            prefix && renderDefaultAffix("prefix", prefix, size),
            React.createElement(InputNumberExperimentalInput, null,
                React.createElement(InputNumberExperimentalLabel, null, label),
                config.loading ? (React.createElement(InputNumberExperimentalLoading, null)) : (React.createElement(InputNumberExperimentalStepper, { incrementLabel: `Increase ${label !== null && label !== void 0 ? label : "value"}`, decrementLabel: `Decrease ${label !== null && label !== void 0 ? label : "value"}` }))),
            suffix && renderDefaultAffix("suffix", suffix, size)),
        (description || error) && (React.createElement(InputNumberExperimentalFooter, null,
            React.createElement(InputNumberExperimentalDescription, null, description),
            React.createElement(InputNumberExperimentalError, null, error)))));
}
InputNumberExperimentalWrapper.displayName = "InputNumberExperimental.Wrapper";
InputNumberExperimental.displayName = "InputNumberExperimental";
InputNumberExperimentalGroup.displayName = "InputNumberExperimental.Group";
InputNumberExperimentalFooter.displayName = "InputNumberExperimental.Footer";
InputNumberExperimentalInput.displayName = "InputNumberExperimental.Input";
InputNumberExperimentalLabel.displayName = "InputNumberExperimental.Label";
InputNumberExperimentalDescription.displayName =
    "InputNumberExperimental.Description";
InputNumberExperimentalError.displayName = "InputNumberExperimental.Error";
InputNumberExperimentalLoading.displayName = "InputNumberExperimental.Loading";
InputNumberExperimentalStepper.displayName = "InputNumberExperimental.Stepper";
InputNumberExperimentalIncrement.displayName =
    "InputNumberExperimental.Increment";
InputNumberExperimentalDecrement.displayName =
    "InputNumberExperimental.Decrement";
InputNumberExperimentalAffixCompound.displayName =
    "InputNumberExperimental.Affix";
InputNumberExperimental.Wrapper = InputNumberExperimentalWrapper;
InputNumberExperimental.Group = InputNumberExperimentalGroup;
InputNumberExperimental.Footer = InputNumberExperimentalFooter;
InputNumberExperimental.Input = InputNumberExperimentalInput;
InputNumberExperimental.Label = InputNumberExperimentalLabel;
InputNumberExperimental.Description = InputNumberExperimentalDescription;
InputNumberExperimental.Error = InputNumberExperimentalError;
InputNumberExperimental.Loading = InputNumberExperimentalLoading;
InputNumberExperimental.Stepper = InputNumberExperimentalStepper;
InputNumberExperimental.Increment = InputNumberExperimentalIncrement;
InputNumberExperimental.Decrement = InputNumberExperimentalDecrement;
InputNumberExperimental.Affix = InputNumberExperimentalAffixCompound;

exports.InputNumberExperimental = InputNumberExperimental;
