UNPKG

@greensight/gds

Version:
839 lines (794 loc) 24.4 kB
var useTheme = require('./useTheme-DeOpgGLJ.js'); var React = require('react'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React); var isMergeableObject = function isMergeableObject(value) { return isNonNullObject(value) && !isSpecial(value) }; function isNonNullObject(value) { return !!value && typeof value === 'object' } function isSpecial(value) { var stringValue = Object.prototype.toString.call(value); return stringValue === '[object RegExp]' || stringValue === '[object Date]' || isReactElement(value) } // see https://github.com/facebook/react/blob/b5ac963fb791d1298e7f396236383bc955f916c1/src/isomorphic/classic/element/ReactElement.js#L21-L25 var canUseSymbol = typeof Symbol === 'function' && Symbol.for; var REACT_ELEMENT_TYPE = canUseSymbol ? Symbol.for('react.element') : 0xeac7; function isReactElement(value) { return value.$$typeof === REACT_ELEMENT_TYPE } function emptyTarget(val) { return Array.isArray(val) ? [] : {} } function cloneUnlessOtherwiseSpecified(value, options) { return (options.clone !== false && options.isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, options) : value } function defaultArrayMerge(target, source, options) { return target.concat(source).map(function(element) { return cloneUnlessOtherwiseSpecified(element, options) }) } function getMergeFunction(key, options) { if (!options.customMerge) { return deepmerge } var customMerge = options.customMerge(key); return typeof customMerge === 'function' ? customMerge : deepmerge } function getEnumerableOwnPropertySymbols(target) { return Object.getOwnPropertySymbols ? Object.getOwnPropertySymbols(target).filter(function(symbol) { return Object.propertyIsEnumerable.call(target, symbol) }) : [] } function getKeys(target) { return Object.keys(target).concat(getEnumerableOwnPropertySymbols(target)) } function propertyIsOnObject(object, property) { try { return property in object } catch(_) { return false } } // Protects from prototype poisoning and unexpected merging up the prototype chain. function propertyIsUnsafe(target, key) { return propertyIsOnObject(target, key) // Properties are safe to merge if they don't exist in the target yet, && !(Object.hasOwnProperty.call(target, key) // unsafe if they exist up the prototype chain, && Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable. } function mergeObject(target, source, options) { var destination = {}; if (options.isMergeableObject(target)) { getKeys(target).forEach(function(key) { destination[key] = cloneUnlessOtherwiseSpecified(target[key], options); }); } getKeys(source).forEach(function(key) { if (propertyIsUnsafe(target, key)) { return } if (propertyIsOnObject(target, key) && options.isMergeableObject(source[key])) { destination[key] = getMergeFunction(key, options)(target[key], source[key], options); } else { destination[key] = cloneUnlessOtherwiseSpecified(source[key], options); } }); return destination } function deepmerge(target, source, options) { options = options || {}; options.arrayMerge = options.arrayMerge || defaultArrayMerge; options.isMergeableObject = options.isMergeableObject || isMergeableObject; // cloneUnlessOtherwiseSpecified is added to `options` so that custom arrayMerge() // implementations can use it. The caller may not replace it. options.cloneUnlessOtherwiseSpecified = cloneUnlessOtherwiseSpecified; var sourceIsArray = Array.isArray(source); var targetIsArray = Array.isArray(target); var sourceAndTargetTypesMatch = sourceIsArray === targetIsArray; if (!sourceAndTargetTypesMatch) { return cloneUnlessOtherwiseSpecified(source, options) } else if (sourceIsArray) { return options.arrayMerge(target, source, options) } else { return mergeObject(target, source, options) } } deepmerge.all = function deepmergeAll(array, options) { if (!Array.isArray(array)) { throw new Error('first argument should be an array') } return array.reduce(function(prev, next) { return deepmerge(prev, next, options) }, {}) }; var deepmerge_1 = deepmerge; var cjs = deepmerge_1; var deepmerge$1 = /*@__PURE__*/useTheme.getDefaultExportFromCjs(cjs); var palettes = { grey: [ "#121314", "#3c3f42", "#666a6f", "#8a8f95", "#a8adb3", "#c0c4cb", "#d2d5dc", "#e0e3e8", "#eaecf0", "#f1f2f5" ], blue: [ "#021540", "#042471", "#0835a1", "#1146cc", "#215bf0", "#6391ff", "#90b2ff", "#c2d6ff", "#d9e4ff", "#eff2fa" ], red: [ "#470000", "#6f0101", "#960202", "#b80303", "#d40505", "#ea1414", "#f14646", "#f57979", "#f5aaaa", "#f2dada" ] }; var colors$1 = { black: "#000000", grey0: "#121314", grey20: "#666a6f", grey40: "#a8adb3", grey60: "#d6d8db", grey70: "#e0e3e8", grey90: "#f1f2f5", white: "#ffffff", fade: "rgba(0, 0, 0, 0.5)", brand: "#215bf0", brandHover: "#1146cc", brandSecond: "#ea1414", brandSecondHover: "#d40505", error: "#f14646", warning: "#f0b621", success: "#4aa253", tagHit: "#68c1dd", tagSale: "#f369a3", tagNew: "#b6d674" }; var typography$2 = { breakpoints: [ 1440, 768 ], styles: { buttonLg: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.5rem", lineHeight: 1.2 } }, buttonMd: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1rem", lineHeight: 1.2, fontVariantNumeric: "tabular-nums" } }, buttonSm: { desktop: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "0.875rem", lineHeight: 1 } }, captionUppercase: { desktop: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "0.75rem", lineHeight: 1.4, letterSpacing: "0.05em", textTransform: "uppercase" } }, caption: { desktop: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "0.75rem", lineHeight: 1.4, letterSpacing: "0.02em" } }, smallBold: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "0.875rem", lineHeight: 1.4 }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "0.75rem", lineHeight: 1.4 } }, small: { desktop: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "0.875rem", lineHeight: 1.4 }, mobile: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "0.75rem", lineHeight: 1.4 } }, bodyBold: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1rem", lineHeight: 1.4, fontVariantNumeric: "tabular-nums" }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "0.875rem", lineHeight: 1.4 } }, body: { desktop: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "1rem", lineHeight: 1.4 }, mobile: { fontFamily: "PT Root UI", fontWeight: 400, fontSize: "0.875rem", lineHeight: 1.4 } }, subheading: { desktop: { fontFamily: "PT Root UI", fontWeight: 500, fontSize: "1.25rem", lineHeight: 1.5 }, mobile: { fontFamily: "PT Root UI", fontWeight: 500, fontSize: "1.125rem", lineHeight: 1.5 } }, title: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.25rem", lineHeight: 1.2 }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.125rem", lineHeight: 1.2 } }, headline: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.5rem", lineHeight: 1.2 }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.25rem", lineHeight: 1.2 } }, h4: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.75rem", lineHeight: 1.2 }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.375rem", lineHeight: 1.2 } }, h3: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "2rem", lineHeight: 1.2 }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "1.5rem", lineHeight: 1.2 } }, h2: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "3rem", lineHeight: 1.2 }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "2.125rem", lineHeight: 1.2 } }, h1: { desktop: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "4.25rem", lineHeight: 1.2, letterSpacing: "-0.02em" }, mobile: { fontFamily: "PT Root UI", fontWeight: 700, fontSize: "3rem", lineHeight: 1.2, letterSpacing: "-0.02em" } } } }; var layout = { cols: { xxxl: 12, md: 6, xs: 4, xxs: 2 }, container: { xxxl: 1440, xl: "none" }, marginLeft: { xxxl: "auto", xl: 0 }, marginRight: { xxxl: "auto", xl: 0 }, breakpoints: { xxxl: 1920, xxl: 1600, xl: 1440, lg: 1280, md: 960, sm: 768, xs: 568, xxs: 360, xxxs: 320 }, gap: { xxxl: 24, sm: 16 }, padding: { xl: 60, lg: 40, md: 36, sm: 32, xs: 24, xxs: 16 } }; var shadows$1 = { small: "1px 1px 3px rgba(18, 19, 20, 0.05), 1px 3px 10px rgba(18, 19, 20, 0.05)", big: "4px 10px 35px rgba(18, 19, 20, 0.08)", inner: "inset 3px 3px 10px rgba(18, 19, 20, 0.1), inset 2px 2px 5px rgba(18, 19, 20, 0.1), inset 2px 2px 3px rgba(18, 19, 20, 0.08)" }; var tokens = { palettes: palettes, colors: colors$1, typography: typography$2, layout: layout, shadows: shadows$1 }; var _path, _path2; var _excluded$1 = ["title", "titleId"]; function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; } var SvgPlaceholder = function SvgPlaceholder(_ref) { var title = _ref.title, titleId = _ref.titleId, props = _objectWithoutProperties(_ref, _excluded$1); return /*#__PURE__*/React__namespace.createElement("svg", _extends({ width: 24, height: 24, viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", "aria-labelledby": titleId }, props), title ? /*#__PURE__*/React__namespace.createElement("title", { id: titleId }, title) : null, _path || (_path = /*#__PURE__*/React__namespace.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M6 8.5C6 7.11929 7.11929 6 8.5 6C9.88071 6 11 7.11929 11 8.5C11 9.88071 9.88071 11 8.5 11C7.11929 11 6 9.88071 6 8.5ZM8.5 8C8.22386 8 8 8.22386 8 8.5C8 8.77614 8.22386 9 8.5 9C8.77614 9 9 8.77614 9 8.5C9 8.22386 8.77614 8 8.5 8Z" })), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M22 5C22 3.34315 20.6569 2 19 2H5C3.34315 2 2 3.34315 2 5V19C2 20.6569 3.34315 22 5 22H19C20.6569 22 22 20.6569 22 19V5ZM5 4C4.44772 4 4 4.44772 4 5V19C4 19.4288 4.2699 19.7946 4.64909 19.9367L15.2929 9.29289C15.6834 8.90237 16.3166 8.90237 16.7071 9.29289L20 12.5858V5C20 4.44772 19.5523 4 19 4H5ZM20 15.4142L16 11.4142L7.41421 20H19C19.5523 20 20 19.5523 20 19V15.4142Z" }))); }; /** * Helper for scaling system usage. Pass `multiplier` to use major scale: values multiple 8. Pass `multiplier` and `isMinor` flag to use minor scale: values less than 40 multiple 4. * * You can define your own step with `customStep` argument but it must be done once per project. For example with step equals 10 major scale allows to use values multiple 10 and minor scale allows to use values less than 40 multiple 5. Recommended way to do this is define wrapper with your step as third argument: * * ``` * import { scale as scaleHelper } from '@greensight/gds'; * import { MAJOR_STEP } from '@scripts/constants'; * * const scale = (multiplier: number, isMinor?: boolean) => scaleHelper(multiplier, isMinor, MAJOR_STEP); * * export default scale; * ``` */ var scale = function scale(multiplier, isMinor, customStep) { var majorStep = useTheme.MAJOR_STEP; var truncatedMultiplier = Math.trunc(multiplier); if (!Number.isInteger(multiplier)) { console.warn("Spacings scale accepts only integers. Your value ".concat(multiplier, " was truncated to ").concat(truncatedMultiplier, ".")); } var value; if (!isMinor) { value = majorStep * truncatedMultiplier; } else { var minorStep = majorStep / 2; value = minorStep * truncatedMultiplier; if (value > useTheme.MINOR_MAX) { var roundedValue = Math.trunc(value / majorStep) * majorStep; console.warn("Minor scale is not defined on sizes bigger than ".concat(useTheme.MINOR_MAX, "px. Your value ").concat(value, " was rounded to ").concat(roundedValue, ".")); value = roundedValue; } } return value; }; var colors = tokens.colors, shadows = tokens.shadows; /* Здесь умышленно не используется createTheme, т.к. она возвращает тип Theme, а базовую тему хочется использовать как константу, чтобы при вводе baseTheme.colors. выводились все цвета + не выдавалось излишних проверок на существование. Мы теряем здесь типизацию при наборе базовой темы (исключительно этот файл), но даём пользователям удобство работы с константой. Пользовательские тему будут создаваться через createTheme и строго следовать типам. */ /** * Default GDS theme. */ var baseTheme = deepmerge$1(tokens, { global: { placeholder: SvgPlaceholder, fonts: { families: { 'PT Root UI': { stack: useTheme.FONT_STACK } }, fontFace: [{ '@font-face': { fontFamily: 'PT Root UI', src: 'url("../fonts/PTRootUI/PTRootUI-Regular.woff2") format("woff2"), url("../fonts/PTRootUI/PTRootUI-Regular.woff") format("woff")', fontDisplay: 'swap' } }, { '@font-face': { fontFamily: 'PT Root UI', src: 'url("../fonts/PTRootUI/PTRootUI-Medium.woff2") format("woff2"), url("../fonts/PTRootUI/PTRootUI-Medium.woff") format("woff")', fontDisplay: 'swap', fontWeight: 500 } }, { '@font-face': { fontFamily: 'PT Root UI', src: 'url("../fonts/PTRootUI/PTRootUI-Bold.woff2") format("woff2"), url("../fonts/PTRootUI/PTRootUI-Bold.woff") format("woff")', fontDisplay: 'swap', fontWeight: 700 } }] }, base: { selection: { color: colors.white, bg: colors.brand }, focus: { width: 2, color: colors.brand, offset: 2 }, body: { typography: 'body', color: colors.black, bg: colors.white } } }, components: { Button: { base: { "default": { round: true, half: true } }, themes: { primary: { "default": { color: colors.white, bg: colors.brand }, hover: { bg: colors.brandHover }, active: { border: 'transparent', shadow: shadows.inner }, disabled: { bg: colors.grey70, color: colors.grey40 } }, secondary: { "default": { color: colors.brand, border: colors.brand, bg: colors.white }, hover: { color: colors.brandHover, border: colors.brandHover }, active: { bg: colors.grey90, border: 'transparent', shadow: shadows.inner }, disabled: { border: colors.grey60, color: colors.grey40 } } }, sizes: { lg: { height: scale(8), padding: scale(3), iconSize: scale(4), iconOffset: scale(1), typography: 'buttonLg' }, md: { height: scale(6), padding: scale(3), iconSize: scale(3), iconOffset: scale(1), typography: 'buttonMd' }, sm: { height: scale(5), padding: scale(2), iconSize: scale(2), iconOffset: scale(1), typography: 'buttonSm' } } } } }); function fastEquals(a, b) { // If both are the same object/reference or same primitive value if (a === b) return true; // If they are not the same type if (useTheme._typeof(a) !== useTheme._typeof(b)) return false; // If they are objects if (useTheme._typeof(a) === 'object') { // If they are not the same class (Array, Object) if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false; // If they are arrays, compare each element if (Array.isArray(a)) { if (a.length !== b.length) return false; for (var i = 0; i < a.length; i++) { if (!fastEquals(a[i], b[i])) return false; } return true; } // If they are objects, compare each key var keys = Object.keys(a); if (keys.length !== Object.keys(b).length) return false; for (var _i = 0, _keys = keys; _i < _keys.length; _i++) { var key = _keys[_i]; // eslint-disable-next-line no-prototype-builtins if (!b.hasOwnProperty(key)) return false; if (!fastEquals(a[key], b[key])) return false; } return true; } // If they are not the same primitive value return false; } var _excluded = ["fontSize"], _excluded2 = ["fontSize"]; var cache = new Map(); /** * Helper for typography styles usage. Generate typography CSS rules by style name included mobile version, fluid typography and variable fonts support. * * By default helper uses GDS base theme. Recommended way to use this helper with your own theme is define wrapper with your theme as second argument: * * ``` * import { typography as typographyHelper } from '@greensight/gds'; * import theme from '@scripts/theme'; * * const typography = (name: string) => typographyHelper(name, theme); * * export default typography; * ``` */ var typography$1 = function typography(name) { var _theme$global, _globalFontsTheme$fam, _globalFontsTheme$fam2; var theme = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : baseTheme; if (!name) { console.warn('"name" argument is not defined.'); return; } if (!theme.typography || !theme.typography.styles[name]) { console.warn("Typography style ".concat(name, " is not defined.")); return; } var cached = cache.get(name); if (cached && fastEquals(cached.theme, theme)) { return cached === null || cached === void 0 ? void 0 : cached.css; } var typographyStyle = theme.typography.styles[name]; var fontName = typographyStyle.desktop.fontFamily; var globalFontsTheme = (_theme$global = theme.global) === null || _theme$global === void 0 ? void 0 : _theme$global.fonts; var stack = (globalFontsTheme === null || globalFontsTheme === void 0 || (_globalFontsTheme$fam = globalFontsTheme.families) === null || _globalFontsTheme$fam === void 0 || (_globalFontsTheme$fam = _globalFontsTheme$fam[fontName]) === null || _globalFontsTheme$fam === void 0 ? void 0 : _globalFontsTheme$fam.stack) || 'sans-serif'; var fontFamilyStyles = { fontFamily: "\"".concat(fontName, "\", ").concat(stack) }; var isVf = globalFontsTheme === null || globalFontsTheme === void 0 || (_globalFontsTheme$fam2 = globalFontsTheme.families) === null || _globalFontsTheme$fam2 === void 0 || (_globalFontsTheme$fam2 = _globalFontsTheme$fam2[fontName]) === null || _globalFontsTheme$fam2 === void 0 ? void 0 : _globalFontsTheme$fam2.vf; if (isVf) { fontFamilyStyles = useTheme._objectSpread2(useTheme._objectSpread2({}, fontFamilyStyles), {}, { '@supports (font-variation-settings: normal)': { fontFamily: "\"".concat(fontName, " VF\", ").concat(stack) } }); } var desktopStyles = removeFontFamily(typographyStyle.desktop); var mqMobileStyles = {}; var fluidStyles = {}; var mainStyles = desktopStyles; var _theme$typography$bre = useTheme._slicedToArray(theme.typography.breakpoints, 2), maxVw = _theme$typography$bre[0], minVw = _theme$typography$bre[1]; var mq = [maxVw, minVw].map(function (bp) { return "@media (max-width: ".concat(bp, "px)"); }); if (typographyStyle.mobile) { var mobileStyles = removeFontFamily(typographyStyle.mobile); var maxFs = desktopStyles.fontSize, desktopStylesWithoutFs = useTheme._objectWithoutProperties(desktopStyles, _excluded); var minFs = mobileStyles.fontSize, mobileStylesWithoutFs = useTheme._objectWithoutProperties(mobileStyles, _excluded2); var mobileStyleEntries = Object.entries(mobileStylesWithoutFs); var uniqueMobileStyles = Object.fromEntries(mobileStyleEntries.filter(function (_ref) { var _ref2 = useTheme._slicedToArray(_ref, 1), name = _ref2[0]; return !desktopStylesWithoutFs[name] || desktopStylesWithoutFs[name] !== mobileStylesWithoutFs[name]; })); mainStyles = desktopStylesWithoutFs; mqMobileStyles = uniqueMobileStyles; var isFluid = true; var fluidSettings = globalFontsTheme === null || globalFontsTheme === void 0 ? void 0 : globalFontsTheme.fluid; if (fluidSettings !== undefined) { isFluid = Array.isArray(fluidSettings) ? !fluidSettings.includes(name) : fluidSettings; } if (isFluid) { fluidStyles = useTheme._defineProperty({ fontSize: maxFs }, mq[0], { fontSize: "calc(".concat(minFs, " + ((100vw - ").concat(pxToRem(minVw), "rem) / (").concat(pxToRem(maxVw), " - ").concat(pxToRem(minVw), ")) * (").concat(parseFloat(maxFs), " - ").concat(parseFloat(minFs), "))") }); } else { fluidStyles = { fontSize: maxFs }; } mqMobileStyles = useTheme._objectSpread2(useTheme._objectSpread2({}, mqMobileStyles), {}, { fontSize: minFs }); } var result = useTheme._objectSpread2(useTheme._objectSpread2(useTheme._objectSpread2(useTheme._objectSpread2({}, fontFamilyStyles), mainStyles), fluidStyles), {}, useTheme._defineProperty({}, mq[1], mqMobileStyles)); cache.set(name, { css: result, theme: theme }); return result; }; var pxToRem = function pxToRem(px) { return px / 16; }; var removeFontFamily = function removeFontFamily(styles) { var entries = Object.entries(styles); var filteredEntries = entries.filter(function (_ref3) { var _ref4 = useTheme._slicedToArray(_ref3, 1), name = _ref4[0]; return name !== 'fontFamily'; }); var filteredStyles = Object.fromEntries(filteredEntries); return filteredStyles; }; /** Импорт CSSObject нужен для tsc. */ /** * `typography` helper with baseTheme. For use with inner components styling (such autokits). */ var typography = function typography(name) { return typography$1(name, baseTheme); }; exports.baseTheme = baseTheme; exports.deepmerge = deepmerge$1; exports.scale = scale; exports.typography = typography; exports.typography$1 = typography$1;