@primer/react
Version:
An implementation of GitHub's Primer Design System using React
172 lines (166 loc) • 10.5 kB
JavaScript
'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;