UNPKG

@greensight/gds

Version:
238 lines (227 loc) 10 kB
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 };