@greensight/gds
Version:
Greensight Design System
238 lines (227 loc) • 10 kB
JavaScript
import { c as _objectWithoutProperties, a as _objectSpread2, b as _defineProperty } from './_rollupPluginBabelHelpers-D0Wa2C7U.js';
import { j as jsx } from './emotion-react.esm-CuKt2qQ4.js';
import React__default, { useMemo } from 'react';
import { VisuallyHidden } from './VisuallyHidden.js';
import { baseTheme } from './baseTheme.js';
import { useTheme } from './useTheme.js';
import { s as scale } from './scale-CeLrnuzO.js';
import { typography } from './typography.js';
import './emotion-element-c16c303e.esm-CnTrGsmj.js';
import './cjs-C-GfJT3o.js';
import './fastEquals.js';
/**
* Custom hook returns used component and project themes based on custom theme exist check. Use it for all components defined in `ComponentsTheme`.
*/
var useComponentTheme = function useComponentTheme(name, __theme) {
var userTheme = useTheme();
return useMemo(function () {
var componentTheme;
var usedTheme;
if (userTheme.components && userTheme.components[name]) {
usedTheme = userTheme;
componentTheme = userTheme.components[name];
} else {
usedTheme = baseTheme;
componentTheme = baseTheme.components[name];
}
componentTheme = __theme || componentTheme;
return {
componentTheme: componentTheme,
usedTheme: usedTheme
};
}, [__theme, name, userTheme]);
};
var _excluded = ["children", "theme", "size", "block", "Icon", "iconAfter", "hidden", "type", "as", "external", "__theme", "css"];
var sizeDefaults = {
height: scale(6),
padding: scale(3),
iconSize: scale(3),
iconOffset: scale(1)
};
/**
* Button component.
*
* Renders <button /> or <a /> (pass `href`) or any custom element (pass `as`).
*
* Define themes and sizes in theme object (`components.Button`) and use them as `theme` / `size` prop values.
*/
var Btn = function Btn(_ref, ref) {
var _usedTheme$typography2;
var children = _ref.children,
_ref$theme = _ref.theme,
theme = _ref$theme === void 0 ? 'primary' : _ref$theme,
_ref$size = _ref.size,
size = _ref$size === void 0 ? 'md' : _ref$size,
_ref$block = _ref.block,
block = _ref$block === void 0 ? false : _ref$block,
Icon = _ref.Icon,
_ref$iconAfter = _ref.iconAfter,
iconAfter = _ref$iconAfter === void 0 ? false : _ref$iconAfter,
_ref$hidden = _ref.hidden,
hidden = _ref$hidden === void 0 ? false : _ref$hidden,
_ref$type = _ref.type,
type = _ref$type === void 0 ? 'button' : _ref$type,
as = _ref.as,
_ref$external = _ref.external,
external = _ref$external === void 0 ? false : _ref$external,
__theme = _ref.__theme,
css = _ref.css,
props = _objectWithoutProperties(_ref, _excluded);
/* Get theme objects. */
var _useComponentTheme = useComponentTheme('Button', __theme),
componentTheme = _useComponentTheme.componentTheme,
usedTheme = _useComponentTheme.usedTheme;
var buttonTheme = componentTheme;
if (!buttonTheme.themes[theme]) console.warn("Specify \"".concat(theme, "\" theme. Default values are used instead"));
if (!buttonTheme.sizes[size]) console.warn("Specify \"".concat(size, "\" size. Default values are used instead"));
/* Get theme default state properties and merge them with default values. */
var themeProperties = getThemeProperties(buttonTheme, theme, 'default');
var sizeProperties = buttonTheme.sizes[size];
var themeDefaults = useMemo(function () {
return {
borderWidth: themeProperties.border ? 1 : 0,
borderStyle: 'solid',
time: 200,
easing: 'ease',
color: baseTheme.colors.white,
bg: baseTheme.colors.black
};
}, [themeProperties.border]);
var tp = useMemo(function () {
return _objectSpread2(_objectSpread2({}, themeDefaults), themeProperties);
}, [themeDefaults, themeProperties]);
var sp = useMemo(function () {
return _objectSpread2(_objectSpread2({}, sizeDefaults), sizeProperties);
}, [sizeProperties]);
/* Define CSS rules from theme properties for default state. */
var typographyName = sp.typography;
var typographyCSS = typography(typographyName, usedTheme);
var pv = useMemo(function () {
var _usedTheme$typography;
return getVerticalPaddings(typographyName ? (_usedTheme$typography = usedTheme.typography) === null || _usedTheme$typography === void 0 || (_usedTheme$typography = _usedTheme$typography.styles[typographyName]) === null || _usedTheme$typography === void 0 ? void 0 : _usedTheme$typography.desktop : undefined, sp, tp, !!Icon);
}, [Icon, sp, tp, typographyName, (_usedTheme$typography2 = usedTheme.typography) === null || _usedTheme$typography2 === void 0 ? void 0 : _usedTheme$typography2.styles]);
var borderRadius = !tp.half ? tp.borderRadius : sp.height / 2;
var padding = "".concat(pv, "px ").concat(sp.padding, "px");
var transition = useMemo(function () {
return getTransition(tp.time, tp.easing);
}, [tp.easing, tp.time]);
var defaultCSS = useMemo(function () {
return _objectSpread2(_objectSpread2(_objectSpread2({
display: 'inline-flex',
justifyContent: 'center',
alignItems: 'center',
borderWidth: tp.borderWidth,
borderStyle: tp.borderStyle
}, typographyCSS), {}, {
borderRadius: borderRadius,
padding: padding,
transition: transition
}, getStateCSS(tp)), sp.css);
}, [borderRadius, padding, sp.css, tp, transition, typographyCSS]);
/* Define CSS rules from theme properties for other states. */
var themeHoverProperties = getThemeProperties(buttonTheme, theme, 'hover');
var themeActiveProperties = getThemeProperties(buttonTheme, theme, 'active');
var themeDisabledProperties = getThemeProperties(buttonTheme, theme, 'disabled');
var themeFocusProperties = getThemeProperties(buttonTheme, theme, 'focus');
var statesCSS = useMemo(function () {
return {
':hover': _objectSpread2(_objectSpread2({}, getStateCSS(themeHoverProperties)), tp.timeIn && {
transition: getTransition(tp.timeIn, tp.easing)
}),
':active': getStateCSS(themeActiveProperties),
':disabled': _objectSpread2(_objectSpread2({}, getStateCSS(themeDisabledProperties)), {}, {
cursor: 'not-allowed'
}),
':focus': getStateCSS(themeFocusProperties)
};
}, [themeActiveProperties, themeDisabledProperties, themeFocusProperties, themeHoverProperties, tp.easing, tp.timeIn]);
/* Build CSS object combined with rules from props. */
var blockStyles = useMemo(function () {
return {
display: 'flex',
width: '100%'
};
}, []);
var hiddenRoundStyles = useMemo(function () {
return {
borderRadius: '50%',
padding: "".concat(pv, "px ").concat((sp.height - sp.iconSize - tp.borderWidth) / 2, "px")
};
}, [pv, sp.height, sp.iconSize, tp.borderWidth]);
// @ts-ignore
var styles = useMemo(function () {
return [defaultCSS, statesCSS, block && blockStyles, hidden && tp.round && hiddenRoundStyles, css];
}, [block, blockStyles, css, defaultCSS, hidden, hiddenRoundStyles, statesCSS, tp.round]);
/* Define CSS rules for icon. */
var marginRule = "margin".concat(!iconAfter ? 'Right' : 'Left');
var iconCSS = useMemo(function () {
return _defineProperty(_defineProperty(_defineProperty({}, marginRule, !hidden ? sp.iconOffset : undefined), "width", sp.iconSize), "height", sp.iconSize);
}, [hidden, marginRule, sp.iconOffset, sp.iconSize]);
return jsx(as || 'button', _objectSpread2({
ref: ref,
type: !as || as === 'button' ? type : null,
target: external ? '_blank' : null,
rel: external ? 'nofollow noopener' : null,
css: styles
}, props), jsx(React__default.Fragment, null, Icon && !iconAfter && jsx(Icon, {
css: iconCSS
}), hidden ? jsx(VisuallyHidden, null, children) : children, Icon && iconAfter && jsx(Icon, {
css: iconCSS
})));
};
var getStateCSS = function getStateCSS(_ref3) {
var color = _ref3.color,
bg = _ref3.bg,
border = _ref3.border,
shadow = _ref3.shadow,
css = _ref3.css;
return _objectSpread2({
color: color,
fill: color,
background: bg,
borderColor: border,
boxShadow: shadow
}, css);
};
var getThemeProperties = function getThemeProperties(buttonTheme, theme, state) {
var _buttonTheme$base;
var themeProperties = buttonTheme.themes[theme][state];
var baseProperties = (_buttonTheme$base = buttonTheme.base) === null || _buttonTheme$base === void 0 ? void 0 : _buttonTheme$base[state];
return _objectSpread2(_objectSpread2({}, baseProperties), themeProperties);
};
var getVerticalPaddings = function getVerticalPaddings(typographyProperties, sizeProperties, themeProperties, isIcon) {
var cssRule = sizeProperties.css;
var fontSize = 16;
var lineHeight = 1.4;
if (typographyProperties) {
fontSize = parseFloat(typographyProperties.fontSize) * 16;
lineHeight = typographyProperties.lineHeight;
} else if (cssRule) {
if (cssRule.fontSize) {
if (typeof cssRule.fontSize === 'number') {
fontSize = cssRule.fontSize;
} else if (typeof cssRule.fontSize === 'string') {
if (cssRule.fontSize.endsWith('rem')) {
fontSize = parseFloat(cssRule.fontSize) * 16;
} else {
fontSize = parseFloat(cssRule.fontSize);
}
}
}
if (cssRule.lineHeight && typeof cssRule.lineHeight === 'number') lineHeight = cssRule.lineHeight;
}
var textHeight = Math.floor(fontSize * lineHeight);
var iconSize = sizeProperties.iconSize;
var height = sizeProperties.height;
var borderWidth = themeProperties.borderWidth;
var maxHeight = Math.max(textHeight, isIcon ? iconSize : 0);
var verticalPaddings = (height - maxHeight - borderWidth * 2) / 2;
return verticalPaddings;
};
var getTransition = function getTransition(time, easing) {
return ['color', 'fill', 'background-color', 'border-color', 'box-shadow'].map(function (name) {
return "".concat(name, " ").concat(easing, " ").concat(time, "ms");
}).join(', ');
};
var Button = /*#__PURE__*/React__default.forwardRef(Btn);
export { Btn, Button };