UNPKG

6.69 kBJavaScriptView Raw
1'use client';
2
3import _extends from "@babel/runtime/helpers/esm/extends";
4import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
5const _excluded = ["defaultValue", "children", "disabled", "error", "onChange", "required", "slotProps", "slots", "value"];
6import * as React from 'react';
7import PropTypes from 'prop-types';
8import useControlled from '@mui/utils/useControlled';
9import { FormControlContext } from './FormControlContext';
10import { getFormControlUtilityClass } from './formControlClasses';
11import { useSlotProps } from '../utils';
12import { unstable_composeClasses as composeClasses } from '../composeClasses';
13import { useClassNamesOverride } from '../utils/ClassNameConfigurator';
14import { jsx as _jsx } from "react/jsx-runtime";
15function hasValue(value) {
16 return value != null && !(Array.isArray(value) && value.length === 0) && value !== '';
17}
18function useUtilityClasses(ownerState) {
19 const {
20 disabled,
21 error,
22 filled,
23 focused,
24 required
25 } = ownerState;
26 const slots = {
27 root: ['root', disabled && 'disabled', focused && 'focused', error && 'error', filled && 'filled', required && 'required']
28 };
29 return composeClasses(slots, useClassNamesOverride(getFormControlUtilityClass));
30}
31
32/**
33 * Provides context such as filled/focused/error/required for form inputs.
34 * Relying on the context provides high flexibility and ensures that the state always stays
35 * consistent across the children of the `FormControl`.
36 * This context is used by the following components:
37 *
38 * * FormLabel
39 * * FormHelperText
40 * * Input
41 * * InputLabel
42 *
43 * You can find one composition example below and more going to [the demos](https://mui.com/material-ui/react-text-field/#components).
44 *
45 * ```jsx
46 * <FormControl>
47 * <InputLabel htmlFor="my-input">Email address</InputLabel>
48 * <Input id="my-input" aria-describedby="my-helper-text" />
49 * <FormHelperText id="my-helper-text">We'll never share your email.</FormHelperText>
50 * </FormControl>
51 * ```
52 *
53 * ⚠️ Only one `Input` can be used within a FormControl because it create visual inconsistencies.
54 * For instance, only one input can be focused at the same time, the state shouldn't be shared.
55 *
56 * Demos:
57 *
58 * - [Form Control](https://mui.com/base-ui/react-form-control/)
59 * - [Input](https://mui.com/joy-ui/react-input/)
60 * - [Checkbox](https://mui.com/material-ui/react-checkbox/)
61 * - [Radio Group](https://mui.com/material-ui/react-radio-button/)
62 * - [Switch](https://mui.com/material-ui/react-switch/)
63 * - [Text Field](https://mui.com/material-ui/react-text-field/)
64 *
65 * API:
66 *
67 * - [FormControl API](https://mui.com/base-ui/react-form-control/components-api/#form-control)
68 */
69const FormControl = /*#__PURE__*/React.forwardRef(function FormControl(props, forwardedRef) {
70 const {
71 defaultValue,
72 children,
73 disabled = false,
74 error = false,
75 onChange,
76 required = false,
77 slotProps = {},
78 slots = {},
79 value: incomingValue
80 } = props,
81 other = _objectWithoutPropertiesLoose(props, _excluded);
82 const [value, setValue] = useControlled({
83 controlled: incomingValue,
84 default: defaultValue,
85 name: 'FormControl',
86 state: 'value'
87 });
88 const filled = hasValue(value);
89 const [focusedState, setFocused] = React.useState(false);
90 const focused = focusedState && !disabled;
91 React.useEffect(() => setFocused(isFocused => disabled ? false : isFocused), [disabled]);
92 const ownerState = _extends({}, props, {
93 disabled,
94 error,
95 filled,
96 focused,
97 required
98 });
99 const childContext = React.useMemo(() => {
100 return {
101 disabled,
102 error,
103 filled,
104 focused,
105 onBlur: () => {
106 setFocused(false);
107 },
108 onChange: event => {
109 setValue(event.target.value);
110 onChange?.(event);
111 },
112 onFocus: () => {
113 setFocused(true);
114 },
115 required,
116 value: value ?? ''
117 };
118 }, [disabled, error, filled, focused, onChange, required, setValue, value]);
119 const classes = useUtilityClasses(ownerState);
120 const renderChildren = () => {
121 if (typeof children === 'function') {
122 return children(childContext);
123 }
124 return children;
125 };
126 const Root = slots.root ?? 'div';
127 const rootProps = useSlotProps({
128 elementType: Root,
129 externalSlotProps: slotProps.root,
130 externalForwardedProps: other,
131 additionalProps: {
132 ref: forwardedRef,
133 children: renderChildren()
134 },
135 ownerState,
136 className: classes.root
137 });
138 return /*#__PURE__*/_jsx(FormControlContext.Provider, {
139 value: childContext,
140 children: /*#__PURE__*/_jsx(Root, _extends({}, rootProps))
141 });
142});
143process.env.NODE_ENV !== "production" ? FormControl.propTypes /* remove-proptypes */ = {
144 // ┌────────────────────────────── Warning ──────────────────────────────┐
145 // │ These PropTypes are generated from the TypeScript type definitions. │
146 // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
147 // └─────────────────────────────────────────────────────────────────────┘
148 /**
149 * The content of the component.
150 */
151 children: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.node, PropTypes.func]),
152 /**
153 * Class name applied to the root element.
154 */
155 className: PropTypes.string,
156 /**
157 * @ignore
158 */
159 defaultValue: PropTypes.any,
160 /**
161 * If `true`, the label, input and helper text should be displayed in a disabled state.
162 * @default false
163 */
164 disabled: PropTypes.bool,
165 /**
166 * If `true`, the label is displayed in an error state.
167 * @default false
168 */
169 error: PropTypes.bool,
170 /**
171 * Callback fired when the form element's value is modified.
172 */
173 onChange: PropTypes.func,
174 /**
175 * If `true`, the label will indicate that the `input` is required.
176 * @default false
177 */
178 required: PropTypes.bool,
179 /**
180 * The props used for each slot inside the FormControl.
181 * @default {}
182 */
183 slotProps: PropTypes.shape({
184 root: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
185 }),
186 /**
187 * The components used for each slot inside the FormControl.
188 * Either a string to use a HTML element or a component.
189 * @default {}
190 */
191 slots: PropTypes.shape({
192 root: PropTypes.elementType
193 }),
194 /**
195 * The value of the form element.
196 */
197 value: PropTypes.any
198} : void 0;
199export { FormControl };
\No newline at end of file