'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
var dom = require('@conform-to/dom');
var react = require('react');
var jsxRuntime = require('react/jsx-runtime');

var _excluded = ["onSubmit"];
var Form = /*#__PURE__*/react.createContext([]);

// To hide the FormContext type from the public API
var wrappedSymbol = Symbol('wrapped');
function getWrappedFormContext(context) {
  return context[wrappedSymbol];
}
function useFormContext(formId) {
  var contexts = react.useContext(Form);
  var form = formId ? contexts.find(context => context.formId === formId) : contexts[0];
  if (!form) {
    throw new Error('Form context is not available');
  }
  return form;
}
function useFormState(form, subjectRef) {
  var subscribe = react.useCallback(callback => form.subscribe(callback, () => subjectRef === null || subjectRef === void 0 ? void 0 : subjectRef.current), [form, subjectRef]);
  return react.useSyncExternalStore(subscribe, form.getState, form.getState);
}
function FormProvider(props) {
  var forms = react.useContext(Form);
  var context = getWrappedFormContext(props.context);
  var value = react.useMemo(() => [context].concat(forms),
  // Put the latest form context first
  [forms, context]);
  return /*#__PURE__*/jsxRuntime.jsx(Form.Provider, {
    value: value,
    children: props.children
  });
}
function FormStateInput(props) {
  var context = useFormContext(props.formId);
  return /*#__PURE__*/jsxRuntime.jsx("input", {
    type: "hidden",
    name: dom.STATE,
    value: context.getSerializedState(),
    form: props.formId
  });
}
function useSubjectRef() {
  var initialSubject = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var subjectRef = react.useRef(initialSubject);

  // Reset the subject everytime the component is rerendered
  // This let us subscribe to data used in the last render only
  subjectRef.current = initialSubject;
  return subjectRef;
}
function updateSubjectRef(ref, name, subject, scope) {
  if (subject === 'status') {
    ref.current[subject] = true;
  } else {
    var _ref$current$subject$, _ref$current$subject;
    ref.current[subject] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, ref.current[subject]), {}, {
      [scope]: ((_ref$current$subject$ = (_ref$current$subject = ref.current[subject]) === null || _ref$current$subject === void 0 ? void 0 : _ref$current$subject[scope]) !== null && _ref$current$subject$ !== void 0 ? _ref$current$subject$ : []).concat(name)
    });
  }
}
function getMetadata(formId, state, subjectRef) {
  var name = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
  var id = name ? "".concat(formId, "-").concat(name) : formId;
  return new Proxy({
    id,
    name,
    errorId: "".concat(id, "-error"),
    descriptionId: "".concat(id, "-description"),
    get initialValue() {
      return state.initialValue[name];
    },
    get value() {
      return state.value[name];
    },
    get errors() {
      return state.error[name];
    },
    get key() {
      return state.key[name];
    },
    get valid() {
      return state.valid[name];
    },
    get dirty() {
      return state.dirty[name];
    },
    get allErrors() {
      if (name === '') {
        return state.error;
      }
      var result = {};
      for (var [key, error] of Object.entries(state.error)) {
        if (dom.isPrefix(key, name)) {
          result[key] = error;
        }
      }
      return result;
    },
    get getFieldset() {
      return () => new Proxy({}, {
        get(target, key, receiver) {
          if (typeof key === 'string') {
            return getFieldMetadata(formId, state, subjectRef, name, key);
          }
          return Reflect.get(target, key, receiver);
        }
      });
    }
  }, {
    get(target, key, receiver) {
      switch (key) {
        case 'key':
        case 'initialValue':
        case 'value':
        case 'valid':
        case 'dirty':
          updateSubjectRef(subjectRef, name, key, 'name');
          break;
        case 'errors':
        case 'allErrors':
          updateSubjectRef(subjectRef, name, 'error', key === 'errors' ? 'name' : 'prefix');
          break;
      }
      return Reflect.get(target, key, receiver);
    }
  });
}
function getFieldMetadata(formId, state, subjectRef) {
  var prefix = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
  var key = arguments.length > 4 ? arguments[4] : undefined;
  var name = typeof key === 'undefined' ? prefix : dom.formatPaths([...dom.getPaths(prefix), key]);
  var metadata = getMetadata(formId, state, subjectRef, name);
  return new Proxy({}, {
    get(_, key, receiver) {
      var _state$constraint$nam;
      switch (key) {
        case 'formId':
          return formId;
        case 'required':
        case 'minLength':
        case 'maxLength':
        case 'min':
        case 'max':
        case 'pattern':
        case 'step':
        case 'multiple':
          return (_state$constraint$nam = state.constraint[name]) === null || _state$constraint$nam === void 0 ? void 0 : _state$constraint$nam[key];
        case 'getFieldList':
          {
            return () => {
              var _state$initialValue$n;
              var initialValue = (_state$initialValue$n = state.initialValue[name]) !== null && _state$initialValue$n !== void 0 ? _state$initialValue$n : [];
              updateSubjectRef(subjectRef, name, 'initialValue', 'name');
              if (!Array.isArray(initialValue)) {
                throw new Error('The initial value at the given name is not a list');
              }
              return Array(initialValue.length).fill(0).map((_, index) => getFieldMetadata(formId, state, subjectRef, name, index));
            };
          }
      }
      return Reflect.get(metadata, key, receiver);
    }
  });
}
function getFormMetadata(formId, state, subjectRef, context, noValidate) {
  var metadata = getMetadata(formId, state, subjectRef);
  return new Proxy({}, {
    get(_, key, receiver) {
      switch (key) {
        case 'context':
          return {
            [wrappedSymbol]: context
          };
        case 'status':
          return state.submissionStatus;
        case 'validate':
        case 'update':
        case 'reset':
        case 'insert':
        case 'remove':
        case 'reorder':
          return context[key];
        case 'onSubmit':
          return context.submit;
        case 'noValidate':
          return noValidate;
      }
      return Reflect.get(metadata, key, receiver);
    }
  });
}
function createFormContext(options) {
  var {
      onSubmit
    } = options,
    rest = _rollupPluginBabelHelpers.objectWithoutProperties(options, _excluded);
  var context = dom.unstable_createFormContext(rest);
  return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, context), {}, {
    submit(event) {
      var submitEvent = event.nativeEvent;
      var result = context.submit(submitEvent);
      if (result.submission && result.submission.status !== 'success' && result.submission.error !== null) {
        event.preventDefault();
      } else {
        var _onSubmit;
        (_onSubmit = onSubmit) === null || _onSubmit === void 0 || _onSubmit(event, result);
      }
    },
    onUpdate(options) {
      onSubmit = options.onSubmit;
      context.onUpdate(options);
    }
  });
}

exports.Form = Form;
exports.FormProvider = FormProvider;
exports.FormStateInput = FormStateInput;
exports.createFormContext = createFormContext;
exports.getFieldMetadata = getFieldMetadata;
exports.getFormMetadata = getFormMetadata;
exports.getMetadata = getMetadata;
exports.getWrappedFormContext = getWrappedFormContext;
exports.updateSubjectRef = updateSubjectRef;
exports.useFormContext = useFormContext;
exports.useFormState = useFormState;
exports.useSubjectRef = useSubjectRef;
