UNPKG

@navinc/base-react-components

Version:
460 lines (454 loc) 18.2 kB
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