import { Accessibility, treeTitleBehavior, TreeTitleBehaviorProps } from '@fluentui/accessibility'; import { ComponentWithAs, getElementType, useUnhandledProps, useAccessibility, useStyles, useFluentContext, useTelemetry, } from '@fluentui/react-bindings'; import { Box, BoxProps } from '../Box/Box'; import { SupportedIntrinsicInputProps } from '../../utils/htmlPropsUtils'; import * as customPropTypes from '@fluentui/react-proptypes'; import * as _ from 'lodash'; import * as PropTypes from 'prop-types'; import * as React from 'react'; import { childrenExist, createShorthandFactory, commonPropTypes, UIComponentProps, ChildrenComponentProps, ContentComponentProps, rtlTextContainer, } from '../../utils'; import { ComponentEventHandler, FluentComponentStaticProps, ShorthandValue } from '../../types'; export interface TreeTitleSlotClassNames { indicator: string; } export interface TreeTitleProps extends UIComponentProps, ChildrenComponentProps, ContentComponentProps { /** Accessibility behavior if overridden by the user. */ accessibility?: Accessibility; /** Whether or not the title has a subtree. */ hasSubtree?: boolean; /** The index of the title among its siblings. Count starts at 1. */ index?: number; /** Level of the tree/subtree that contains this title. */ level?: number; /** * Called on click. * * @param event - React's original SyntheticEvent. * @param data - All props. */ onClick?: ComponentEventHandler; /** Whether or not the subtree of the title is in the open state. */ expanded?: boolean; /** Size of the tree containing this title without any children. */ treeSize?: number; /** Whether or not tree title is part of the selectable parent. */ selectableParent?: boolean; /** A selection indicator icon can be customized. */ selectionIndicator?: ShorthandValue; /** A selection indicator can appear disabled and be unable to change states. */ disabled?: SupportedIntrinsicInputProps['disabled']; /** A state of selection indicator. */ selected?: boolean; /** Whether or not tree title is selectable. */ selectable?: boolean; /** For selectable parents define if all nested children are checked */ indeterminate?: boolean; } export type TreeTitleStylesProps = Pick< TreeTitleProps, 'selected' | 'selectable' | 'disabled' | 'selectableParent' | 'indeterminate' >; export const treeTitleClassName = 'ui-tree__title'; export const treeTitleSlotClassNames = { indicator: `${treeTitleClassName}__selection-indicator`, }; /** * A TreeTitle renders a title of TreeItem. */ export const TreeTitle: ComponentWithAs<'a', TreeTitleProps> & FluentComponentStaticProps = props => { const context = useFluentContext(); const { setStart, setEnd } = useTelemetry(TreeTitle.displayName, context.telemetry); setStart(); const { accessibility, children, className, content, design, hasSubtree, level, index, styles, treeSize, variables, selectionIndicator, disabled, selected, selectable, selectableParent, expanded, indeterminate, } = props; const getA11Props = useAccessibility(accessibility, { debugName: TreeTitle.displayName, actionHandlers: { performClick: e => { e.preventDefault(); e.stopPropagation(); handleClick(e); }, performSelection: e => { e.preventDefault(); e.stopPropagation(); handleClick(e); }, }, mapPropsToBehavior: () => ({ hasSubtree, level, index, treeSize, selected, selectable, selectableParent, }), rtl: context.rtl, }); const { classes, styles: resolvedStyles } = useStyles(TreeTitle.displayName, { className: treeTitleClassName, mapPropsToStyles: () => ({ selected, selectableParent, disabled, selectable, indeterminate, }), mapPropsToInlineStyles: () => ({ className, design, styles, variables, }), rtl: context.rtl, }); const ElementType = getElementType(props); const unhandledProps = useUnhandledProps(TreeTitle.handledProps, props); const handleClick = e => { _.invoke(props, 'onClick', e, props); }; const selectIndicator = Box.create(selectionIndicator, { defaultProps: () => ({ as: 'span', selected, ...(selectableParent && !_.isEmpty(selectionIndicator) && { expanded }), ...getA11Props('indicator', { className: treeTitleSlotClassNames.indicator, ...(((selectable && !hasSubtree) || (selectableParent && expanded)) && _.isEmpty(selectionIndicator) && { styles: resolvedStyles.selectionIndicator, }), }), }), }); const element = ( {childrenExist(children) ? children : content} {selectable && selectIndicator} ); setEnd(); return element; }; TreeTitle.displayName = 'TreeTitle'; TreeTitle.propTypes = { ...commonPropTypes.createCommon(), hasSubtree: PropTypes.bool, index: PropTypes.number, level: PropTypes.number, onClick: PropTypes.func, expanded: PropTypes.bool, selected: PropTypes.bool, selectable: PropTypes.bool, selectableParent: PropTypes.bool, treeSize: PropTypes.number, selectionIndicator: customPropTypes.shorthandAllowingChildren, indeterminate: PropTypes.bool, }; TreeTitle.defaultProps = { as: 'a', selectionIndicator: {}, accessibility: treeTitleBehavior, }; TreeTitle.handledProps = Object.keys(TreeTitle.propTypes) as any; TreeTitle.create = createShorthandFactory({ Component: TreeTitle, mappedProp: 'content', });