@fluent-windows/core
Version:
React components that inspired by Microsoft's Fluent Design System.
128 lines (118 loc) • 4.4 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import * as React from 'react';
import { MoreLine as MoreLineIcon } from '@fluent-windows/icons'; // TODO treeShaking
import { useClickOutside, useReveal, usePopper } from '@fluent-windows/hooks'; // TODO treeShaking
import { omit } from '../utils';
import Box from '../Box';
import { styles } from './Command.styled';
import Secondary from './components/Secondary';
import Content from './components/Content';
import Portal from '../Portal';
import Item from '../Item';
import Transition from '../Transition';
import { CommandPropTypes } from './Command.type';
import { createUseStyles } from 'react-jss';
import classNames from 'classnames';
export const name = 'Command';
const useStyles = createUseStyles(styles, {
name
});
export const CommandContext = React.createContext(false);
const Command = React.forwardRef((props, ref) => {
const {
as = 'div',
className: classNameProp,
acrylic = false,
reveal = false,
children,
...rest
} = props;
const classes = useStyles(props);
const className = classNames(classes.root, classNameProp);
const container = React.useMemo(() => React.Children.toArray(children).reduce((acc, cur) => {
if (cur.type.displayName === 'FCommandContent') {
return { ...acc,
content: [...acc.content, cur]
};
} else if (cur.type.displayName === 'FCommandSecondary') {
return { ...acc,
secondary: cur.props.children
};
}
return { ...acc,
standard: [...acc.standard, cur]
};
}, {
content: [],
standard: [],
secondary: null
}), [children]); // Reveal does not take effect when using acrylic
const _reveal = React.useMemo(() => acrylic ? false : reveal, [acrylic, reveal]);
const [RevealWrapper] = useReveal(); // Secondary Popup related
const [secondaryVisible, setSecondaryVisible] = React.useState(false);
const handleSecondaryVisible = React.useCallback(() => {
if (secondaryVisible) return;
setSecondaryVisible(visible => !visible);
}, [secondaryVisible]); // Click on the area outside the More menu to close the More menu.
const [referenceRef, popperRef] = usePopper({
placement: 'bottom-end'
});
useClickOutside(popperRef, event => {
// @ts-ignore
if (!referenceRef.current || referenceRef.current.contains(event.target)) return;
setSecondaryVisible(visible => !visible);
});
const otherProps = omit(rest, ['display', 'backgroundColor', 'color']);
return React.createElement(Box, _extends({
ref: ref,
as: as,
acrylic: acrylic,
className: className,
backgroundColor: "standard.light2"
}, otherProps), React.createElement(CommandContext.Provider, {
value: _reveal
}, !!container.content.length && React.createElement("div", {
className: classes.content
}, container.content), React.createElement("div", {
className: classes.primary
}, _reveal ? container.standard.map((child, i) => React.createElement(RevealWrapper, {
key: i
}, child)) : container.standard), container.secondary !== null && (_reveal ? React.createElement(RevealWrapper, null, React.createElement(Item, {
ref: referenceRef,
style: {
height: '100%'
},
onClick: handleSecondaryVisible,
prefix: React.createElement(MoreLineIcon, null)
})) : React.createElement(Item, {
ref: referenceRef,
onClick: handleSecondaryVisible,
prefix: React.createElement(MoreLineIcon, null)
})), React.createElement(Portal, null, React.createElement(Transition, {
visible: secondaryVisible,
wrapper: true,
mountOnEnter: true,
unmountOnExit: true
}, React.createElement(Box, {
ref: popperRef,
acrylic: acrylic,
backgroundColor: "standard.light2",
className: classes.secondaryRoot
}, container.secondary)))));
});
Object.defineProperty(Command, 'Secondary', {
get() {
return Secondary;
}
});
Object.defineProperty(Command, 'Content', {
get() {
return Content;
}
});
Command.displayName = `F${name}`;
Command.propTypes = CommandPropTypes;
Command.defaultProps = {
reveal: false
};
export default Command;