UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

172 lines (166 loc) • 10.5 kB
'use strict'; var clsx = require('clsx'); var React = require('react'); var Autocomplete = require('../Autocomplete/Autocomplete.js'); var Checkbox = require('../Checkbox/Checkbox.js'); var Radio = require('../Radio/Radio.js'); var Select = require('../Select/Select.js'); var SelectPanel = require('../SelectPanel/SelectPanel.js'); var TextInput = require('../TextInput/TextInput.js'); var TextInputWithTokens = require('../TextInputWithTokens/TextInputWithTokens.js'); var Textarea = require('../Textarea/Textarea.js'); var Box = require('../Box/Box.js'); require('../internal/components/CheckboxOrRadioGroup/CheckboxOrRadioGroup.js'); var CheckboxOrRadioGroupContext = require('../internal/components/CheckboxOrRadioGroup/CheckboxOrRadioGroupContext.js'); var ValidationAnimationContainer = require('../internal/components/ValidationAnimationContainer.js'); var useSlots = require('../hooks/useSlots.js'); var useId = require('../hooks/useId.js'); var FormControlCaption = require('./FormControlCaption.js'); var FormControlLabel = require('./FormControlLabel.js'); var FormControlLeadingVisual = require('./FormControlLeadingVisual.js'); var _FormControlValidation = require('./_FormControlValidation.js'); var _FormControlContext = require('./_FormControlContext.js'); var warning = require('../utils/warning.js'); var styled = require('styled-components'); var sx = require('../sx.js'); var toggleStyledComponent = require('../internal/utils/toggleStyledComponent.js'); var featureFlags = require('./feature-flags.js'); require('../FeatureFlags/FeatureFlags.js'); var useFeatureFlag = require('../FeatureFlags/useFeatureFlag.js'); require('../FeatureFlags/DefaultFeatureFlags.js'); var FormControl_module = require('./FormControl.module.css.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); var styled__default = /*#__PURE__*/_interopDefault(styled); const FormControl = /*#__PURE__*/React__default.default.forwardRef(({ children, disabled: disabledProp, layout = 'vertical', id: idProp, required, sx, className }, ref) => { var _slots$validation, _slots$label; const enabled = useFeatureFlag.useFeatureFlag(featureFlags.cssModulesFlag); const [slots, childrenWithoutSlots] = useSlots.useSlots(children, { caption: FormControlCaption.FormControlCaption, label: FormControlLabel, leadingVisual: FormControlLeadingVisual, validation: _FormControlValidation }); const expectedInputComponents = [Autocomplete, Checkbox, Radio, Select, TextInput, TextInputWithTokens, Textarea.default, SelectPanel.SelectPanel]; const choiceGroupContext = React.useContext(CheckboxOrRadioGroupContext); const disabled = choiceGroupContext.disabled || disabledProp; const id = useId.useId(idProp); const validationMessageId = slots.validation ? `${id}-validationMessage` : undefined; const captionId = slots.caption ? `${id}-caption` : undefined; const validationStatus = (_slots$validation = slots.validation) === null || _slots$validation === undefined ? undefined : _slots$validation.props.variant; const InputComponent = childrenWithoutSlots.find(child => expectedInputComponents.some(inputComponent => /*#__PURE__*/React__default.default.isValidElement(child) && child.type === inputComponent)); const inputProps = /*#__PURE__*/React__default.default.isValidElement(InputComponent) && InputComponent.props; const isChoiceInput = /*#__PURE__*/React__default.default.isValidElement(InputComponent) && (InputComponent.type === Checkbox || InputComponent.type === Radio); const isRadioInput = /*#__PURE__*/React__default.default.isValidElement(InputComponent) && InputComponent.type === Radio; if (InputComponent) { process.env.NODE_ENV !== "production" ? warning.warning(inputProps === null || inputProps === undefined ? undefined : inputProps.id, `instead of passing the 'id' prop directly to the input component, it should be passed to the parent component, <FormControl>`) : undefined; process.env.NODE_ENV !== "production" ? warning.warning(inputProps === null || inputProps === undefined ? undefined : inputProps.disabled, `instead of passing the 'disabled' prop directly to the input component, it should be passed to the parent component, <FormControl>`) : undefined; process.env.NODE_ENV !== "production" ? warning.warning(inputProps === null || inputProps === undefined ? undefined : inputProps.required, `instead of passing the 'required' prop directly to the input component, it should be passed to the parent component, <FormControl>`) : undefined; } if (!slots.label) { // eslint-disable-next-line no-console console.error(`The input field with the id ${id} MUST have a FormControl.Label child.\n\nIf you want to hide the label, pass the 'visuallyHidden' prop to the FormControl.Label component.`); } if (isChoiceInput) { process.env.NODE_ENV !== "production" ? warning.warning(!!slots.validation, 'Validation messages are not rendered for an individual checkbox or radio. The validation message should be shown for all options.') : undefined; process.env.NODE_ENV !== "production" ? warning.warning(isRadioInput && childrenWithoutSlots.find(child => { var _child$props; return /*#__PURE__*/React__default.default.isValidElement(child) && ((_child$props = child.props) === null || _child$props === undefined ? undefined : _child$props.required); }), 'An individual radio cannot be a required field.') : undefined; } else { process.env.NODE_ENV !== "production" ? warning.warning(!!slots.leadingVisual, 'A leading visual is only rendered for a checkbox or radio form control. If you want to render a leading visual inside of your input, check if your input supports a leading visual.') : undefined; } const isLabelHidden = (_slots$label = slots.label) === null || _slots$label === undefined ? undefined : _slots$label.props.visuallyHidden; return /*#__PURE__*/React__default.default.createElement(_FormControlContext.FormControlContextProvider, { value: { captionId, disabled, id, required, validationMessageId } }, isChoiceInput || layout === 'horizontal' ? /*#__PURE__*/React__default.default.createElement(StyledHorizontalLayout, { ref: ref, "data-has-leading-visual": slots.leadingVisual ? '' : undefined, sx: sx, className: clsx.clsx(className, { [FormControl_module.ControlHorizontalLayout]: enabled }) }, /*#__PURE__*/React__default.default.createElement(StyledChoiceInputs, { className: FormControl_module.ControlChoiceInputs }, /*#__PURE__*/React__default.default.isValidElement(InputComponent) ? /*#__PURE__*/React__default.default.cloneElement(InputComponent, { id, disabled, // allow checkboxes to be required required: required && !isRadioInput, ['aria-describedby']: captionId }) : null, childrenWithoutSlots.filter(child => /*#__PURE__*/React__default.default.isValidElement(child) && ![Checkbox, Radio].some(inputComponent => child.type === inputComponent))), slots.leadingVisual ? /*#__PURE__*/React__default.default.createElement(StyledLeadingVisual, { className: clsx.clsx({ [FormControl_module.LeadingVisual]: enabled }), "data-disabled": disabled ? '' : undefined, "data-has-caption": slots.caption ? '' : undefined }, slots.leadingVisual) : null, /*#__PURE__*/React__default.default.createElement(StyledLabelContainer, { className: FormControl_module.LabelContainer }, slots.label, slots.caption)) : /*#__PURE__*/React__default.default.createElement(Box, { ref: ref, "data-has-label": !isLabelHidden ? '' : undefined, display: "flex", flexDirection: "column", alignItems: "flex-start", sx: enabled ? sx : { ...(isLabelHidden ? { '> *:not(label) + *': { marginTop: 1 } } : { '> * + *': { marginTop: 1 } }), ...sx }, className: clsx.clsx(className, { [FormControl_module.ControlVerticalLayout]: enabled }) }, slots.label, /*#__PURE__*/React__default.default.isValidElement(InputComponent) && /*#__PURE__*/React__default.default.cloneElement(InputComponent, Object.assign({ id, required, disabled, validationStatus, ['aria-describedby']: [validationMessageId, captionId].filter(Boolean).join(' ') }, InputComponent.props)), childrenWithoutSlots.filter(child => /*#__PURE__*/React__default.default.isValidElement(child) && !expectedInputComponents.some(inputComponent => child.type === inputComponent)), slots.validation ? /*#__PURE__*/React__default.default.createElement(ValidationAnimationContainer, { show: true }, slots.validation) : null, slots.caption)); }); const StyledHorizontalLayout = toggleStyledComponent.toggleStyledComponent(featureFlags.cssModulesFlag, 'div', styled__default.default.div.withConfig({ displayName: "FormControl__StyledHorizontalLayout", componentId: "sc-1t6d2k4-0" })(["display:flex;&:where([data-has-leading-visual]){align-items:center;}", ""], sx.default)); const StyledChoiceInputs = toggleStyledComponent.toggleStyledComponent(featureFlags.cssModulesFlag, 'div', styled__default.default.div.withConfig({ displayName: "FormControl__StyledChoiceInputs", componentId: "sc-1t6d2k4-1" })(["> input{margin-left:0;margin-right:0;}"])); const StyledLabelContainer = toggleStyledComponent.toggleStyledComponent(featureFlags.cssModulesFlag, 'div', styled__default.default.div.withConfig({ displayName: "FormControl__StyledLabelContainer", componentId: "sc-1t6d2k4-2" })(["> *{padding-left:var(--stack-gap-condensed);}> label{font-weight:var(--base-text-weight-normal);}"])); const StyledLeadingVisual = toggleStyledComponent.toggleStyledComponent(featureFlags.cssModulesFlag, 'div', styled__default.default.div.withConfig({ displayName: "FormControl__StyledLeadingVisual", componentId: "sc-1t6d2k4-3" })(["color:var(--fgColor-default);margin-left:var(--base-size-8);&:where([data-disabled]){color:var(--fgColor-muted);}> *{fill:currentColor;min-width:var(--text-body-size-large);min-height:var(--text-body-size-large);}> *:where([data-has-caption]){min-width:var(--base-size-24);min-height:var(--base-size-24);}"])); var FormControl$1 = Object.assign(FormControl, { Caption: FormControlCaption.FormControlCaption, Label: FormControlLabel, LeadingVisual: FormControlLeadingVisual, Validation: _FormControlValidation }); module.exports = FormControl$1;