UNPKG

@conform-to/react

Version:

Conform view adapter for react

227 lines (213 loc) 6.99 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var future = require('@conform-to/dom/future'); var intent = require('./intent.js'); function getFormElement(formRef) { var _element$form; if (typeof formRef === 'string') { return document.forms.namedItem(formRef); } var element = formRef === null || formRef === void 0 ? void 0 : formRef.current; if (element instanceof HTMLFormElement) { return element; } return (_element$form = element === null || element === void 0 ? void 0 : element.form) !== null && _element$form !== void 0 ? _element$form : null; } function getSubmitEvent(event) { if (event.type !== 'submit') { throw new Error('The event is not a submit event'); } return event.nativeEvent; } function initializeField(element, options) { var _options$value; if (element.dataset.conform) { return; } var defaultValue = typeof (options === null || options === void 0 ? void 0 : options.value) === 'string' || typeof (options === null || options === void 0 ? void 0 : options.defaultChecked) === 'boolean' ? options.defaultChecked ? (_options$value = options.value) !== null && _options$value !== void 0 ? _options$value : 'on' : null : options === null || options === void 0 ? void 0 : options.defaultValue; // Update the value of the element, including the default value future.updateField(element, { value: defaultValue, defaultValue }); element.dataset.conform = 'initialized'; } /** * Makes hidden form inputs focusable with visually hidden styles */ function makeInputFocusable(element) { if (!element.hidden && element.type !== 'hidden') { return; } // Style the element to be visually hidden element.style.position = 'absolute'; element.style.width = '1px'; element.style.height = '1px'; element.style.padding = '0'; element.style.margin = '-1px'; element.style.overflow = 'hidden'; element.style.clip = 'rect(0,0,0,0)'; element.style.whiteSpace = 'nowrap'; element.style.border = '0'; // Hide the element from screen readers element.setAttribute('aria-hidden', 'true'); // Make sure people won't tab to this element element.tabIndex = -1; // Set the element to be visible again so it can be focused if (element.hidden) { element.hidden = false; } if (element.type === 'hidden') { element.setAttribute('type', 'text'); } } function getRadioGroupValue(inputs) { for (var input of inputs) { if (input.type === 'radio' && input.checked) { return input.value; } } } function getCheckboxGroupValue(inputs) { var values; for (var input of inputs) { if (input.type === 'checkbox') { var _values; (_values = values) !== null && _values !== void 0 ? _values : values = []; if (input.checked) { values.push(input.value); } } } return values; } function getInputSnapshot(input) { if (input instanceof HTMLInputElement) { switch (input.type) { case 'file': return { files: input.files ? Array.from(input.files) : undefined }; case 'radio': case 'checkbox': return { value: input.value, checked: input.checked }; } } else if (input instanceof HTMLSelectElement && input.multiple) { return { options: Array.from(input.selectedOptions).map(option => option.value) }; } return { value: input.value }; } /** * Creates an InputSnapshot based on the provided options: * - checkbox/radio: value / defaultChecked * - file inputs: defaultValue is File or FileList * - select multiple: defaultValue is string array * - others: defaultValue is string */ function createDefaultSnapshot(defaultValue, defaultChecked, value) { if (typeof value === 'string' || typeof defaultChecked === 'boolean') { return { value: value !== null && value !== void 0 ? value : 'on', checked: defaultChecked }; } if (typeof defaultValue === 'string') { return { value: defaultValue }; } if (Array.isArray(defaultValue)) { if (defaultValue.every(item => typeof item === 'string')) { return { options: defaultValue }; } else { return { files: defaultValue }; } } if (future.isGlobalInstance(defaultValue, 'File')) { return { files: [defaultValue] }; } if (future.isGlobalInstance(defaultValue, 'FileList')) { return { files: Array.from(defaultValue) }; } return {}; } /** * Focuses the first field with validation errors on default form submission. * Does nothing if the submission was triggered with a specific intent (e.g. validate / insert) */ function focusFirstInvalidField(ctx) { if (ctx.intent) { return; } for (var element of ctx.formElement.elements) { var _ctx$error$fieldError; if (future.isFieldElement(element) && (_ctx$error$fieldError = ctx.error.fieldErrors[element.name]) !== null && _ctx$error$fieldError !== void 0 && _ctx$error$fieldError.length) { element.focus(); break; } } } function updateFormValue(form, intendedValue, serialize) { for (var element of form.elements) { if (future.isFieldElement(element) && element.name) { var value = future.getValueAtPath(intendedValue, element.name); var serializedValue = serialize(value); if (typeof serializedValue !== 'undefined') { future.change(element, serializedValue, { preventDefault: true }); } } } } /** * Creates a proxy that dynamically generates intent dispatch functions. * Each property access returns a function that submits the intent to the form. */ function createIntentDispatcher(formElement, intentName) { return new Proxy({}, { get(target, type, receiver) { if (typeof type === 'string') { var _target$type; // @ts-expect-error (_target$type = target[type]) !== null && _target$type !== void 0 ? _target$type : target[type] = payload => { var form = typeof formElement === 'function' ? formElement() : formElement; if (!form) { throw new Error("Dispatching \"".concat(type, "\" intent failed; No form element found.")); } future.requestIntent(form, intentName, intent.serializeIntent({ type, payload })); }; } return Reflect.get(target, type, receiver); } }); } exports.createDefaultSnapshot = createDefaultSnapshot; exports.createIntentDispatcher = createIntentDispatcher; exports.focusFirstInvalidField = focusFirstInvalidField; exports.getCheckboxGroupValue = getCheckboxGroupValue; exports.getFormElement = getFormElement; exports.getInputSnapshot = getInputSnapshot; exports.getRadioGroupValue = getRadioGroupValue; exports.getSubmitEvent = getSubmitEvent; exports.initializeField = initializeField; exports.makeInputFocusable = makeInputFocusable; exports.updateFormValue = updateFormValue;