UNPKG

@material-ui/core

Version:

React components that implement Google's Material Design.

287 lines (251 loc) 8.89 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; import * as React from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import { isFilled, isAdornedStart } from '../InputBase/utils'; import withStyles from '../styles/withStyles'; import capitalize from '../utils/capitalize'; import isMuiElement from '../utils/isMuiElement'; import FormControlContext from './FormControlContext'; export var styles = { /* Styles applied to the root element. */ root: { display: 'inline-flex', flexDirection: 'column', position: 'relative', // Reset fieldset default style. minWidth: 0, padding: 0, margin: 0, border: 0, verticalAlign: 'top' // Fix alignment issue on Safari. }, /* Styles applied to the root element if `margin="normal"`. */ marginNormal: { marginTop: 16, marginBottom: 8 }, /* Styles applied to the root element if `margin="dense"`. */ marginDense: { marginTop: 8, marginBottom: 4 }, /* Styles applied to the root element if `fullWidth={true}`. */ fullWidth: { width: '100%' } }; /** * Provides context such as filled/focused/error/required for form inputs. * Relying on the context provides high flexibility and ensures that the state always stays * consistent across the children of the `FormControl`. * This context is used by the following components: * * - FormLabel * - FormHelperText * - Input * - InputLabel * * You can find one composition example below and more going to [the demos](/components/text-fields/#components). * * ```jsx * <FormControl> * <InputLabel htmlFor="my-input">Email address</InputLabel> * <Input id="my-input" aria-describedby="my-helper-text" /> * <FormHelperText id="my-helper-text">We'll never share your email.</FormHelperText> * </FormControl> * ``` * * ⚠️Only one input can be used within a FormControl. */ var FormControl = /*#__PURE__*/React.forwardRef(function FormControl(props, ref) { var children = props.children, classes = props.classes, className = props.className, _props$color = props.color, color = _props$color === void 0 ? 'primary' : _props$color, _props$component = props.component, Component = _props$component === void 0 ? 'div' : _props$component, _props$disabled = props.disabled, disabled = _props$disabled === void 0 ? false : _props$disabled, _props$error = props.error, error = _props$error === void 0 ? false : _props$error, _props$fullWidth = props.fullWidth, fullWidth = _props$fullWidth === void 0 ? false : _props$fullWidth, visuallyFocused = props.focused, _props$hiddenLabel = props.hiddenLabel, hiddenLabel = _props$hiddenLabel === void 0 ? false : _props$hiddenLabel, _props$margin = props.margin, margin = _props$margin === void 0 ? 'none' : _props$margin, _props$required = props.required, required = _props$required === void 0 ? false : _props$required, size = props.size, _props$variant = props.variant, variant = _props$variant === void 0 ? 'standard' : _props$variant, other = _objectWithoutProperties(props, ["children", "classes", "className", "color", "component", "disabled", "error", "fullWidth", "focused", "hiddenLabel", "margin", "required", "size", "variant"]); var _React$useState = React.useState(function () { // We need to iterate through the children and find the Input in order // to fully support server-side rendering. var initialAdornedStart = false; if (children) { React.Children.forEach(children, function (child) { if (!isMuiElement(child, ['Input', 'Select'])) { return; } var input = isMuiElement(child, ['Select']) ? child.props.input : child; if (input && isAdornedStart(input.props)) { initialAdornedStart = true; } }); } return initialAdornedStart; }), adornedStart = _React$useState[0], setAdornedStart = _React$useState[1]; var _React$useState2 = React.useState(function () { // We need to iterate through the children and find the Input in order // to fully support server-side rendering. var initialFilled = false; if (children) { React.Children.forEach(children, function (child) { if (!isMuiElement(child, ['Input', 'Select'])) { return; } if (isFilled(child.props, true)) { initialFilled = true; } }); } return initialFilled; }), filled = _React$useState2[0], setFilled = _React$useState2[1]; var _React$useState3 = React.useState(false), _focused = _React$useState3[0], setFocused = _React$useState3[1]; var focused = visuallyFocused !== undefined ? visuallyFocused : _focused; if (disabled && focused) { setFocused(false); } var registerEffect; if (process.env.NODE_ENV !== 'production') { // eslint-disable-next-line react-hooks/rules-of-hooks var registeredInput = React.useRef(false); registerEffect = function registerEffect() { if (registeredInput.current) { console.error(['Material-UI: There are multiple InputBase components inside a FormControl.', 'This is not supported. It might cause infinite rendering loops.', 'Only use one InputBase.'].join('\n')); } registeredInput.current = true; return function () { registeredInput.current = false; }; }; } var onFilled = React.useCallback(function () { setFilled(true); }, []); var onEmpty = React.useCallback(function () { setFilled(false); }, []); var childContext = { adornedStart: adornedStart, setAdornedStart: setAdornedStart, color: color, disabled: disabled, error: error, filled: filled, focused: focused, fullWidth: fullWidth, hiddenLabel: hiddenLabel, margin: (size === 'small' ? 'dense' : undefined) || margin, onBlur: function onBlur() { setFocused(false); }, onEmpty: onEmpty, onFilled: onFilled, onFocus: function onFocus() { setFocused(true); }, registerEffect: registerEffect, required: required, variant: variant }; return /*#__PURE__*/React.createElement(FormControlContext.Provider, { value: childContext }, /*#__PURE__*/React.createElement(Component, _extends({ className: clsx(classes.root, className, margin !== 'none' && classes["margin".concat(capitalize(margin))], fullWidth && classes.fullWidth), ref: ref }, other), children)); }); process.env.NODE_ENV !== "production" ? FormControl.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the d.ts file and run "yarn proptypes" | // ---------------------------------------------------------------------- /** * The contents of the form control. */ children: PropTypes.node, /** * Override or extend the styles applied to the component. * See [CSS API](#css) below for more details. */ classes: PropTypes.object, /** * @ignore */ className: PropTypes.string, /** * The color of the component. It supports those theme colors that make sense for this component. */ color: PropTypes.oneOf(['primary', 'secondary']), /** * The component used for the root node. * Either a string to use a HTML element or a component. */ component: PropTypes /* @typescript-to-proptypes-ignore */ .elementType, /** * If `true`, the label, input and helper text should be displayed in a disabled state. */ disabled: PropTypes.bool, /** * If `true`, the label should be displayed in an error state. */ error: PropTypes.bool, /** * If `true`, the component will be displayed in focused state. */ focused: PropTypes.bool, /** * If `true`, the component will take up the full width of its container. */ fullWidth: PropTypes.bool, /** * If `true`, the label will be hidden. * This is used to increase density for a `FilledInput`. * Be sure to add `aria-label` to the `input` element. */ hiddenLabel: PropTypes.bool, /** * If `dense` or `normal`, will adjust vertical spacing of this and contained components. */ margin: PropTypes.oneOf(['dense', 'none', 'normal']), /** * If `true`, the label will indicate that the input is required. */ required: PropTypes.bool, /** * The size of the text field. */ size: PropTypes.oneOf(['medium', 'small']), /** * The variant to use. */ variant: PropTypes.oneOf(['filled', 'outlined', 'standard']) } : void 0; export default withStyles(styles, { name: 'MuiFormControl' })(FormControl);