@cimpress/react-components
Version:
React components to support the MCP styleguide
223 lines (211 loc) • 7.27 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import React, { useState, useRef, useEffect } from 'react';
import { cx, css } from '@emotion/css';
import { BlockButton } from './internal';
import cvar from './theme/cvar';
import { ArrowAlt } from './accordion/ArrowAlt';
const nonDefaultVariants = ['simple', 'navtab'];
const dropdownContainerCss = css `
position: relative;
text-decoration: none;
display: inline-block;
`;
const getInnerDropdownCss = (variant, disabled) => {
const determineColor = () => {
if (disabled) {
return cvar('color-text-disabled');
}
if (nonDefaultVariants.includes(variant)) {
return cvar('color-button-primary');
}
return cvar('color-text-label');
};
const determineHoverBackgroundColor = () => {
if (disabled) {
return cvar('color-background-disabled');
}
if (variant === 'navtab') {
return cvar('color-background');
}
return cvar('color-hover');
};
return css `
background: ${cvar('color-background')};
background-color: ${cvar('color-background')};
border: 1px solid ${nonDefaultVariants.includes(variant) ? 'transparent' : cvar('color-border-default')};
border-radius: 2px;
box-shadow: none;
color: ${determineColor()};
cursor: ${disabled ? 'not-allowed' : 'pointer'};
display: inline-block;
font-size: 14px;
font-weight: 600;
line-height: 1.286;
margin-bottom: 0;
opacity: ${disabled ? 0.65 : 1};
padding: ${cvar('spacing-8')} ${cvar('spacing-16')};
text-align: center;
text-shadow: none;
touch-action: manipulation;
user-select: none;
vertical-align: middle;
white-space: nowrap;
&:hover {
color: ${variant === 'navtab' ? cvar('color-dropdown-label-active') : determineColor()};
background-color: ${determineHoverBackgroundColor()};
text-decoration: none;
}
&:active {
color: ${cvar('color-dropdown-active')};
}
`;
};
const getOpenDropdownCss = (variant) => css `
color: ${cvar('color-dropdown-active')};
border: 1px solid ${variant === 'navtab' ? 'transparent' : cvar('color-border-dropdown-active')};
box-shadow: none;
`;
const caretCss = css `
border: none;
box-sizing: border-box;
display: inline-block;
height: 100%;
margin: 0 ${cvar('spacing-8')};
vertical-align: middle;
width: 0;
`;
const getDropdownMenuContainerCss = (open) => {
if (!open) {
return css `
display: none;
`;
}
return css `
background-color: ${cvar('color-background')};
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 2px;
box-shadow: 0 6px 12px rgb(0 0 0 / 18%);
color: ${cvar('color-text-label')};
display: block;
float: left;
font-size: 14px;
font-weight: 400;
left: 0;
line-height: 24px;
list-style: none;
min-width: 160px;
margin: ${cvar('spacing-2')} 0 0;
position: absolute;
text-align: left;
top: 100%;
z-index: 1000;
padding-left: 0px;
`;
};
const dividerCss = css `
background-color: #e5e5e5;
height: 1px;
overflow: hidden;
`;
const itemCss = css `
cursor: pointer;
box-sizing: border-box;
&:has(> :disabled:only-child) {
cursor: not-allowed;
}
& :disabled {
cursor: not-allowed;
}
&:hover {
background-color: ${cvar('color-hover')};
}
a,
button {
width: 100%;
padding: ${cvar('spacing-12')} ${cvar('spacing-24')};
}
a {
display: block;
&:hover {
text-decoration: none;
}
}
button {
background: 0 0;
background-image: none;
border: none;
color: ${cvar('color-button-primary')};
text-decoration: none;
line-height: 18px;
outline: 0;
position: relative;
text-align: left;
width: 100%;
&:disabled {
color: ${cvar('color-icon-disabled')};
}
}
button:hover {
text-decoration: none;
}
.crc-anchor,
.crc-button {
text-align: left;
}
`;
const shouldShowCaret = (variant) => variant !== 'simple';
export const Dropdown = (_a) => {
var { className, variant = 'default', as: AsComponentProp = 'div', disabled = false, title } = _a, passthruProps = __rest(_a, ["className", "variant", "as", "disabled", "title"]);
const [open, setIsOpen] = useState(false);
const ref = useRef(null);
const toggle = () => setIsOpen(!open);
const detectOutsideClick = (e) => {
var _a;
if (!((_a = ref.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
setIsOpen(false);
}
};
// Listen for outside clicks
useEffect(() => {
document.addEventListener('click', detectOutsideClick, true);
return () => document.removeEventListener('click', detectOutsideClick, true);
});
let InnerAsComponent = 'button';
let AsComponent = AsComponentProp;
if (variant === 'navtab') {
AsComponent = 'li';
InnerAsComponent = 'a';
}
// Filter out props we don't want to pass through to child components
const { eventTypes, outsideClickIgnoreClass, preventDefault, stopPropagation, disableOnClickOutside, enableOnClickOutside, children } = passthruProps, validPassthruProps = __rest(passthruProps, ["eventTypes", "outsideClickIgnoreClass", "preventDefault", "stopPropagation", "disableOnClickOutside", "enableOnClickOutside", "children"]);
const innerClassName = cx(getInnerDropdownCss(variant, disabled), {
[getOpenDropdownCss(variant)]: open,
});
return (React.createElement(AsComponent, Object.assign({ ref: ref, className: cx('crc-dropdown', dropdownContainerCss, className, { open }) }, validPassthruProps),
React.createElement(InnerAsComponent, { disabled: !children || !React.Children.count(children) || disabled, onClick: toggle, className: innerClassName },
title,
' ',
shouldShowCaret(variant) && (React.createElement("span", { className: cx(caretCss) },
React.createElement(ArrowAlt, { size: 10, color: cvar('color-button-primary') })))),
React.createElement(BlockButton, { tabIndex: -1, className: cx(getDropdownMenuContainerCss(open)), as: "ul", onClick: toggle }, React.Children.map(children, child => {
if (!child) {
return null;
}
if (child.type === 'hr') {
return React.createElement("li", { className: cx(dividerCss), key: child.key });
}
return (React.createElement(BlockButton, { tabIndex: -1, as: "li", className: cx(itemCss, { disabled: child.props.disabled }), key: child.key, onClick: child.props.disabled ? e => e.stopPropagation() : undefined }, child));
}))));
};
//# sourceMappingURL=Dropdown.js.map