UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

134 lines (133 loc) 5.28 kB
"use strict"; 'use client'; Object.defineProperty(exports, "__esModule", { value: true }); exports.useFieldControlValidation = useFieldControlValidation; var React = _interopRequireWildcard(require("react")); var _useEventCallback = require("../../utils/useEventCallback"); var _FieldRootContext = require("../root/FieldRootContext"); var _mergeReactProps = require("../../utils/mergeReactProps"); var _constants = require("../utils/constants"); var _FormContext = require("../../form/FormContext"); var _getCombinedFieldValidityData = require("../utils/getCombinedFieldValidityData"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } const validityKeys = Object.keys(_constants.DEFAULT_VALIDITY_STATE); function useFieldControlValidation() { const { setValidityData, validate, messageIds, validityData, validationMode, validationDebounceTime, invalid, markedDirtyRef, controlId, state } = (0, _FieldRootContext.useFieldRootContext)(); const { formRef } = (0, _FormContext.useFormContext)(); const timeoutRef = React.useRef(-1); const inputRef = React.useRef(null); React.useEffect(() => { return () => { window.clearTimeout(timeoutRef.current); }; }, []); const commitValidation = (0, _useEventCallback.useEventCallback)(async value => { const element = inputRef.current; if (!element) { return; } function getState(el) { return validityKeys.reduce((acc, key) => { acc[key] = el.validity[key]; if (!el.validity.customError && !markedDirtyRef.current) { acc[key] = key === 'valid'; } return acc; }, {}); } window.clearTimeout(timeoutRef.current); const resultOrPromise = validate(value); let result = null; if (typeof resultOrPromise === 'object' && resultOrPromise !== null && 'then' in resultOrPromise) { result = await resultOrPromise; } else { result = resultOrPromise; } let errorMessage = ''; if (result !== null) { errorMessage = Array.isArray(result) ? result.join('\n') : result; } element.setCustomValidity(errorMessage); const nextState = getState(element); let validationErrors = []; if (Array.isArray(result)) { validationErrors = result; } else if (result) { validationErrors = [result]; } else if (element.validationMessage) { validationErrors = [element.validationMessage]; } const nextValidityData = { value, state: nextState, error: Array.isArray(result) ? result[0] : result ?? element.validationMessage, errors: validationErrors, initialValue: validityData.initialValue }; if (controlId) { const currentFieldData = formRef.current.fields.get(controlId); if (currentFieldData) { formRef.current.fields.set(controlId, { ...currentFieldData, ...(0, _getCombinedFieldValidityData.getCombinedFieldValidityData)(nextValidityData, invalid) }); } } setValidityData(nextValidityData); }); const getValidationProps = React.useCallback((externalProps = {}) => (0, _mergeReactProps.mergeReactProps)(externalProps, { ...(messageIds.length && { 'aria-describedby': messageIds.join(' ') }), ...(state.valid === false && { 'aria-invalid': true }) }), [messageIds, state.valid]); const getInputValidationProps = React.useCallback((externalProps = {}) => (0, _mergeReactProps.mergeReactProps)(getValidationProps(externalProps), { onChange(event) { // Workaround for https://github.com/facebook/react/issues/9023 if (event.nativeEvent.defaultPrevented) { return; } if (invalid || validationMode !== 'onChange') { return; } const element = event.currentTarget; if (element.value === '') { // Ignore the debounce time for empty values. commitValidation(element.value); return; } window.clearTimeout(timeoutRef.current); if (validationDebounceTime) { timeoutRef.current = window.setTimeout(() => { commitValidation(element.value); }, validationDebounceTime); } else { commitValidation(element.value); } } }), [getValidationProps, invalid, validationMode, validationDebounceTime, commitValidation]); return React.useMemo(() => ({ getValidationProps, getInputValidationProps, inputRef, commitValidation }), [getValidationProps, getInputValidationProps, commitValidation]); }