import { Accessibility } from '@fluentui/accessibility'; import * as customPropTypes from '@fluentui/react-proptypes'; import * as PropTypes from 'prop-types'; import * as React from 'react'; import * as _ from 'lodash'; import { childrenExist, UIComponentProps, ChildrenComponentProps, commonPropTypes, rtlTextContainer, createShorthandFactory, } from '../../utils'; import { ComponentEventHandler, ShorthandCollection, FluentComponentStaticProps } from '../../types'; import { FormField, FormFieldProps } from './FormField'; import { ComponentWithAs, useTelemetry, getElementType, useUnhandledProps, useStyles, useFluentContext, useAccessibility, } from '@fluentui/react-bindings'; import { FormLabel } from './FormLabel'; import { FormMessage } from './FormMessage'; import { FormInput } from './FormInput'; import { FormCheckbox } from './FormCheckbox'; import { FormDropdown } from './FormDropdown'; import { FormButton } from './FormButton'; import { FormRadioGroup } from './FormRadioGroup'; import { FormSlider } from './FormSlider'; import { FormFieldCustom } from './FormFieldCustom'; export interface FormProps extends UIComponentProps, ChildrenComponentProps { /** * Accessibility behavior if overridden by the user. */ accessibility?: Accessibility; /** The HTML form action. */ action?: string; /** Shorthand array of props for the Form.Fields inside the Form. */ fields?: ShorthandCollection; /** * The HTML form submit handler. * @param event - React's original SyntheticEvent. * @param data - All props. */ onSubmit?: ComponentEventHandler; } export const formClassName = 'ui-form'; export type FormStylesProps = never; /** * A Form is used to collect, oprionally validate, and submit the user input, in a structured way. */ export const Form: ComponentWithAs<'form', FormProps> & FluentComponentStaticProps & { Field: typeof FormField; Label: typeof FormLabel; Message: typeof FormMessage; Input: typeof FormInput; Checkbox: typeof FormCheckbox; Dropdown: typeof FormDropdown; Button: typeof FormButton; RadioGroup: typeof FormRadioGroup; Slider: typeof FormSlider; FieldCustom: typeof FormFieldCustom; } = props => { const context = useFluentContext(); const { setStart, setEnd } = useTelemetry(Form.displayName, context.telemetry); setStart(); const { className, design, styles, variables, action, children, accessibility } = props; const ElementType = getElementType(props); const unhandledProps = useUnhandledProps(Form.handledProps, props); const { classes } = useStyles(Form.displayName, { className: formClassName, mapPropsToInlineStyles: () => ({ className, design, styles, variables, }), rtl: context.rtl, }); const getA11yProps = useAccessibility(accessibility, { debugName: Form.displayName, rtl: context.rtl, }); const handleSubmit = (e, ...args) => { const { action } = props; // Heads up! Third party libs can pass own data as first argument, we need to check that it has preventDefault() // method. if (!action) _.invoke(e, 'preventDefault'); _.invoke(props, 'onSubmit', e, props, ...args); }; const renderFields = () => { const { fields } = props; return _.map(fields, field => FormField.create(field)); }; const element = ( {childrenExist(children) ? children : renderFields()} ); setEnd(); return element; }; Form.displayName = 'Form'; Form.propTypes = { ...commonPropTypes.createCommon({ content: false, }), action: PropTypes.string, fields: customPropTypes.collectionShorthand, onSubmit: PropTypes.func, }; Form.defaultProps = { as: 'form', }; Form.handledProps = Object.keys(Form.propTypes) as any; Form.create = createShorthandFactory({ Component: Form, }); Form.Field = FormField; Form.FieldCustom = FormFieldCustom; Form.Label = FormLabel; Form.Message = FormMessage; Form.Input = FormInput; Form.Checkbox = FormCheckbox; Form.Dropdown = FormDropdown; Form.Button = FormButton; Form.RadioGroup = FormRadioGroup; Form.Slider = FormSlider;