@navinc/base-react-components
Version:
Nav's Pattern Library
460 lines (454 loc) • 18.2 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 { jsx as _jsx } from "react/jsx-runtime";
import { forwardRef } from 'react';
import styled from 'styled-components';
import { ButtonLinkIcon } from './button-link-icon.js';
import { Link } from './link.js';
import { LoadingDots } from './loading-dots.js';
const sizeVariants = {
small: {
padding: '0.5em 1.33em',
fontSize: '12px',
borderRadius: '8px',
lineHeight: '1',
},
medium: {
padding: '6px 16px 6px 16px',
fontSize: '14px',
borderRadius: '8px',
lineHeight: '1',
},
mediumFull: {
padding: '12px 24px',
fontSize: '16px',
borderRadius: '8px',
lineHeight: '1.5',
width: '100%',
},
large: {
padding: '8px 24px 8px 24px',
fontSize: '16px',
borderRadius: '8px',
lineHeight: '1',
},
largeFull: {
padding: '20px 24px',
fontSize: '16px',
borderRadius: '8px',
lineHeight: '1.5',
width: '100%',
},
extraLarge: {
padding: '16px 32px 16px 32px',
fontSize: '20px',
borderRadius: '8px',
lineHeight: '1',
},
cardButton: {
padding: '8px',
fontSize: '16px',
borderRadius: '12px',
lineHeight: '1',
},
};
const getSize = ({ size = 'medium' }) => {
var _a;
return (_a = sizeVariants[size]) !== null && _a !== void 0 ? _a : sizeVariants.medium;
};
const getVariation = ({ variation = 'main', theme, size = 'medium', iconPosition }) => {
var _a, _b, _c;
const lineHeightMap = {
small: '18px',
medium: '20px',
mediumFull: '20px',
large: '24px',
largeFull: '24px',
extraLarge: '28px',
};
const buttonLink = {
borderColor: 'transparent',
backgroundColor: theme.transparentWhite,
color: theme.navPrimary400,
padding: 0,
lineHeight: (_a = lineHeightMap[size]) !== null && _a !== void 0 ? _a : lineHeightMap.medium,
hover: {
color: theme.navPrimary500,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
borderRadius: '2px',
},
active: {
color: theme.navPrimary500,
},
};
const styleVariation = {
main: {
borderColor: 'transparent',
backgroundColor: theme.navPrimary,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navPrimary200} radial-gradient(circle, transparent 1%, ${theme.navPrimary700} 1%) center/15000%`,
/*
Despite remaining the same, the font color must be defined
for both hover/focus so as to override nested link styling
*/
color: theme.navNeutralLight,
hover: {
backgroundColor: theme.navPrimary500,
color: theme.navNeutralLight,
},
focus: {
backgroundColor: theme.navPrimary,
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
/* Tied to the background property, these will create the click impression effect */
backgroundColor: theme.navPrimary700,
backgroundSize: '100%',
transition: 'background 0s',
},
},
outline: {
borderColor: theme.navPrimary,
backgroundColor: theme.transparentWhite,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navPrimary200} radial-gradient(circle, transparent 1%, ${theme.navPrimary300} 1%) center/15000%`,
color: theme.navPrimary,
hover: {
backgroundColor: theme.navPrimary200,
},
focus: {
backgroundColor: theme.transparentWhite,
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navPrimary300,
/* Tied to the background property, these will create the click impression effect */
backgroundSize: '100%',
transition: 'background 0s',
},
},
shade: {
borderColor: 'transparent',
backgroundColor: theme.navPrimary200,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navPrimary200} radial-gradient(circle, transparent 1%, ${theme.navPrimary300} 1%) center/15000%`,
color: theme.navPrimary,
hover: {
backgroundColor: theme.navPrimary100,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navPrimary300,
/* Tied to the background property, these will create the click impression effect */
backgroundSize: '100%',
transition: 'background 0s',
},
},
white: {
borderColor: 'transparent',
backgroundColor: theme.navNeutralLight,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navPrimary200} radial-gradient(circle, transparent 1%, ${theme.navPrimary300} 1%) center/15000%`,
color: theme.navPrimary,
hover: {
backgroundColor: theme.navPrimary200,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navPrimary300,
/* Tied to the background property, these will create the click impression effect */
backgroundSize: '100%',
transition: 'background 0s',
},
},
tan: {
borderColor: 'transparent',
backgroundColor: theme.navSecondary,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navSecondary} radial-gradient(circle, transparent 1%, ${theme.navSecondary300} 1%) center/15000%`,
color: theme.navPrimary400,
hover: {
backgroundColor: theme.navSecondary100,
color: theme.navPrimary500,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navSecondary300,
color: theme.navPrimary500,
/* Tied to the background property, these will create the click impression effect */
backgroundSize: '100%',
transition: 'background 0s',
},
},
destructive: {
borderColor: 'transparent',
backgroundColor: theme.navStatusNegative,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navStatusNegative} radial-gradient(circle, transparent 1%, ${theme.navStatusNegative700} 1%) center/15000%`,
color: theme.navNeutralLight,
hover: {
backgroundColor: theme.navStatusNegative500,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navStatusNegative700,
/* Tied to the background property, these will create the click impression effect */
backgroundSize: '100%',
transition: 'background 0s',
},
},
accent: {
borderColor: 'transparent',
backgroundColor: theme.navStatusPositive,
/* Imposes a background radial gradient too small to detect, that upon activation will expand 100% of the container like a ripple from the click */
background: `${theme.navStatusPositive} radial-gradient(circle, transparent 1%, ${theme.navStatusPositive700} 1%) center/15000%`,
color: theme.navNeutralLight,
hover: {
backgroundColor: theme.navStatusPositive500,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navStatusPositive700,
/* Tied to the background property, these will create the click impression effect */
backgroundSize: '100%',
transition: 'background 0s',
},
},
buttonLink,
buttonLinkIcon: Object.assign(Object.assign({}, buttonLink), { padding: !iconPosition ? 0 : iconPosition === 'left' ? '0 2px 0 0' : '0 0 0 2px' }),
buttonAction: {
borderColor: 'transparent',
backgroundColor: theme.transparentWhite,
color: theme.navNeutral400,
padding: 0,
lineHeight: (_b = lineHeightMap[size]) !== null && _b !== void 0 ? _b : lineHeightMap.medium,
},
noOutline: {
borderColor: 'transparent',
backgroundColor: theme.transparentWhite,
color: theme.navPrimary400,
hover: {
color: theme.navPrimary500,
},
focus: {
borderColor: theme.navStatusPositive500,
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
color: theme.navPrimary500,
},
},
whiteOutline: {
borderColor: theme.navNeutralLight,
backgroundColor: theme.transparentWhite,
color: theme.navNeutralLight,
hover: {
backgroundColor: theme.navPrimary200,
color: theme.navPrimary,
},
focus: {
backgroundColor: theme.navPrimary200,
color: theme.navPrimary,
},
active: {
backgroundColor: theme.navPrimary300,
color: theme.navPrimary,
borderColor: 'transparent',
},
},
neutral: {
borderColor: 'transparent',
backgroundColor: theme.navNeutral100,
background: `${theme.navPrimary200} radial-gradient(circle, transparent 1%, ${theme.navPrimary200} 1%) center/15000%`,
color: theme.navPrimary400,
hover: {
backgroundColor: theme.navPrimary200,
},
focus: {
outline: 'none',
boxShadow: `0 0 0 4px ${theme.navStatusPositive500}`,
},
active: {
backgroundColor: theme.navPrimary300,
backgroundSize: '100%',
transition: 'background 0s',
borderColor: 'transparent',
},
},
filterActive: {
background: theme.navPrimary400,
borderStyle: 'solid',
borderWidth: '1px',
borderColor: theme.navPrimary400,
borderRadius: '6px',
padding: '8px 16px',
whiteSpace: 'nowrap',
color: theme.navNeutralLight,
fontWeight: '600',
fontSize: '16px',
lineHeight: '24px',
},
filterInactive: {
background: 'none',
borderStyle: 'solid',
borderWidth: '1px',
borderColor: theme.navNeutral300,
borderRadius: '6px',
padding: '8px 16px',
whiteSpace: 'nowrap',
color: theme.navNeutralDark,
fontWeight: '600',
fontSize: '16px',
lineHeight: '24px',
},
};
return (_c = styleVariation[variation]) !== null && _c !== void 0 ? _c : styleVariation.main;
};
const getRule = (rulePath) => ({ size, variation, theme, iconPosition }) => {
const rules = Object.assign(Object.assign({}, getSize({ size })), getVariation({ variation, theme, size, iconPosition }));
const rule = rulePath.split('.').reduce((rules, pathPart) => { var _a; return (_a = rules[pathPart]) !== null && _a !== void 0 ? _a : ''; }, rules);
return typeof rule === 'function' ? rule({ theme }) : rule;
};
const getDisabledStyleByVariation = ({ variation, theme }) => {
switch (variation) {
case 'buttonLink':
case 'noOutline':
return '';
case 'outline':
return '';
default:
return `background-color: ${theme.navNeutral100};`;
}
};
export const StyledButton = styled.button.withConfig({ displayName: "brc-sc-StyledButton", componentId: "brc-sc-bkuhcf" }) `
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-family: ${({ theme }) => theme.fontPrimary};
width: ${getRule('width')};
padding: ${getRule('padding')};
border: 1px solid ${getRule('borderColor')};
border-radius: ${getRule('borderRadius')};
background: ${getRule('background')};
background-color: ${getRule('backgroundColor')};
color: ${getRule('color')};
font-size: ${getRule('fontSize')};
line-height: ${getRule('lineHeight')};
text-align: center;
white-space: ${({ wrap }) => (wrap ? 'normal' : 'nowrap')};
cursor: pointer;
outline: none;
font-weight: 700;
transition: ease-out background 0.4s;
text-rendering: optimizelegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
&:focus {
background-color: ${getRule('focus.backgroundColor')};
color: ${getRule('focus.color')};
outline: ${getRule('focus.outline')};
box-shadow: ${getRule('focus.boxShadow')};
border-radius: ${getRule('focus.borderRadius')};
}
&[disabled] {
${({ $isLoading, variation = 'main', theme, size }) => $isLoading
? ''
: `
${getDisabledStyleByVariation({ variation, theme })}
opacity: 38%;
background: ${getRule('backgroundColor')({ size, variation, theme })} !important;
cursor: not-allowed;
`}
}
&:active {
background-color: ${getRule('active.backgroundColor')};
background-size: ${getRule('active.backgroundSize')};
transition: ${getRule('active.transition')};
}
&:focus:active {
outline: none;
box-shadow: none;
}
&:hover:not([disabled]) {
background-color: ${getRule('hover.backgroundColor')};
color: ${getRule('hover.color')};
border-color: ${getRule('hover.borderColor')};
}
/* Override hover styles, b/c when pressed the hover event is also active */
&:hover:active {
background-color: ${getRule('active.backgroundColor')};
color: ${getRule('active.color')};
border-color: ${getRule('active.borderColor')};
}
`;
const ButtonBase = forwardRef((_a, ref) => {
var { children, $isLoading, onClick = () => { }, iconFilename = 'tech/filter', iconPosition, variation } = _a, props = __rest(_a, ["children", "$isLoading", "onClick", "iconFilename", "iconPosition", "variation"]);
let dotColor = 'purple';
switch (variation) {
case 'main':
case 'destructive':
case 'accent':
case undefined:
dotColor = 'white';
break;
default:
break;
}
return (_jsx(StyledButton, Object.assign({ disabled: $isLoading, onClick: (event) => {
event.persist();
onClick(event);
} }, props, { variation, iconPosition, ref: ref, children: $isLoading ? (_jsx(LoadingDots, { dotColor: dotColor, "data-testid": "button-loading-dots" })) : (_jsx(ButtonLinkIcon, { name: iconFilename, iconPosition, variation, children: children })) })));
});
ButtonBase.displayName = 'ButtonBase';
const ButtonLink = styled(StyledButton).attrs(() => ({ as: Link })) `
text-decoration: none;
`;
ButtonLink.displayName = 'ButtonLink';
const ButtonAnchor = styled(StyledButton).attrs(() => ({ as: 'a' })).withConfig({ displayName: "brc-sc-ButtonAnchor", componentId: "brc-sc-1uee4oc" }) `
text-decoration: none;
`;
ButtonAnchor.displayName = 'ButtonAnchor';
const _Button = forwardRef((_a, ref) => {
var { href, asAnchor, isLoading } = _a, props = __rest(_a, ["href", "asAnchor", "isLoading"]);
if (!href) {
return _jsx(ButtonBase, Object.assign({ ref: ref, "$isLoading": isLoading }, props));
}
if (asAnchor) {
return _jsx(ButtonAnchor, Object.assign({ ref: ref, "$isLoading": isLoading, href: href }, props));
}
return _jsx(ButtonLink, Object.assign({ "$isLoading": isLoading, href: href }, props));
});
_Button.displayName = 'Button';
export const Button = styled(_Button).withConfig({ displayName: "brc-sc-Button", componentId: "brc-sc-8enbkn" }) ``;
//# sourceMappingURL=button.js.map