import { Accessibility, attachmentBehavior, AttachmentBehaviorProps } from '@fluentui/accessibility'; import { ComponentWithAs, compose, getElementType, mergeVariablesOverrides, useAccessibility, useStyles, useFluentContext, useTelemetry, useUnhandledProps, } from '@fluentui/react-bindings'; import * as customPropTypes from '@fluentui/react-proptypes'; import * as _ from 'lodash'; import * as PropTypes from 'prop-types'; import * as React from 'react'; import { ComponentEventHandler, ShorthandValue } from '../../types'; import { createShorthandFactory, commonPropTypes, UIComponentProps, ChildrenComponentProps, createShorthand, ShorthandFactory, } from '../../utils'; import { AttachmentAction, AttachmentActionProps } from './AttachmentAction'; import { AttachmentBody, AttachmentBodyProps } from './AttachmentBody'; import { AttachmentDescription, AttachmentDescriptionProps } from './AttachmentDescription'; import { AttachmentHeader, AttachmentHeaderProps } from './AttachmentHeader'; import { AttachmentIcon, AttachmentIconProps } from './AttachmentIcon'; export interface AttachmentProps extends UIComponentProps, ChildrenComponentProps { /** Accessibility behavior if overridden by the user. */ accessibility?: Accessibility; /** Button shorthand for the action slot. */ action?: ShorthandValue; /** An Attachment can be styled to indicate possible user interaction. */ actionable?: boolean; /** Contains a header and a description for an Attachment. */ body?: ShorthandValue; /** A string describing the attachment. */ description?: ShorthandValue; /** An attachment can show that it cannot be interacted with. */ disabled?: boolean; /** The name of the attachment. */ header?: ShorthandValue; /** Shorthand for the icon. */ icon?: ShorthandValue; /** Value indicating percent complete. */ progress?: string | number; /** * Called after user's click. * @param event - React's original SyntheticEvent. * @param data - All props. */ onClick?: ComponentEventHandler; } export type AttachmentStylesProps = Required>; export const attachmentClassName = 'ui-attachment'; /** * An Attachment represents a file or media attachment, which may contain some metadata or actions. */ export const Attachment = compose<'div', AttachmentProps, AttachmentStylesProps, {}, {}>( (props, ref, composeOptions) => { const context = useFluentContext(); const { setStart, setEnd } = useTelemetry(composeOptions.displayName, context.telemetry); setStart(); const { accessibility, action, actionable, body, className, description, design, disabled, header, icon, onClick, progress, styles, variables, } = props; const getA11Props = useAccessibility(accessibility, { debugName: composeOptions.displayName, actionHandlers: { performClick: e => { if (e.currentTarget === e.target) { e.stopPropagation(); handleClick(e); } }, }, rtl: context.rtl, }); const { classes } = useStyles(composeOptions.displayName, { className: attachmentClassName, mapPropsToStyles: () => ({ actionable: actionable || !!onClick, disabled, }), mapPropsToInlineStyles: () => ({ className, design, styles, variables, }), rtl: context.rtl, composeOptions, unstable_props: props, }); const slotProps = composeOptions.resolveSlotProps(props); const ElementType = getElementType(props); const unhandledProps = useUnhandledProps(composeOptions.handledProps, props); const handleClick = (e: React.KeyboardEvent | React.MouseEvent) => { if (disabled) { e.preventDefault(); return; } _.invoke(props, 'onClick', e, props); }; const element = getA11Props.unstable_wrapWithFocusZone( {createShorthand(composeOptions.slots.icon, icon, { defaultProps: () => slotProps.icon, overrideProps: predefinedProps => ({ variables: mergeVariablesOverrides(variables, predefinedProps.variables), }), })} {(header || description) && createShorthand(composeOptions.slots.body, body, { defaultProps: () => slotProps.body, overrideProps: predefinedProps => ({ content: ( <> {createShorthand(composeOptions.slots.header, header, { defaultProps: () => slotProps.header, overrideProps: predefinedProps => ({ variables: mergeVariablesOverrides(variables, predefinedProps.variables), }), })} {createShorthand(composeOptions.slots.description, description, { defaultProps: () => slotProps.description, overrideProps: predefinedProps => ({ variables: mergeVariablesOverrides(variables, predefinedProps.variables), }), })} ), variables: mergeVariablesOverrides(variables, predefinedProps.variables), }), })} {createShorthand(composeOptions.slots.action, action, { defaultProps: () => slotProps.action, overrideProps: predefinedProps => ({ variables: mergeVariablesOverrides(variables, predefinedProps.variables), }), })} {!_.isNil(progress) &&
} , ); setEnd(); return element; }, { className: attachmentClassName, displayName: 'Attachment', slots: { action: AttachmentAction, body: AttachmentBody, description: AttachmentDescription, header: AttachmentHeader, icon: AttachmentIcon, }, handledProps: [ 'accessibility', 'action', 'actionable', 'as', 'body', 'children', 'className', 'description', 'design', 'header', 'icon', 'onClick', 'progress', 'styles', 'variables', ], }, ) as ComponentWithAs<'div', AttachmentProps> & { create: ShorthandFactory; Action: typeof AttachmentAction; Body: typeof AttachmentBody; Description: typeof AttachmentDescription; Header: typeof AttachmentHeader; Icon: typeof AttachmentIcon; }; Attachment.create = createShorthandFactory({ Component: Attachment, mappedProp: 'header' }); Attachment.propTypes = { ...commonPropTypes.createCommon({ content: false, }), action: customPropTypes.itemShorthand, actionable: PropTypes.bool, body: customPropTypes.itemShorthand, description: customPropTypes.itemShorthand, header: customPropTypes.itemShorthand, icon: customPropTypes.shorthandAllowingChildren, onClick: PropTypes.func, progress: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), }; Attachment.defaultProps = { accessibility: attachmentBehavior, body: {}, }; Attachment.Action = AttachmentAction; Attachment.Body = AttachmentBody; Attachment.Description = AttachmentDescription; Attachment.Header = AttachmentHeader; Attachment.Icon = AttachmentIcon;