@hakuna-matata-ui/system
Version:
Chakra UI system primitives
348 lines (286 loc) • 12.2 kB
JavaScript
import { useColorMode } from '@hakuna-matata-ui/color-mode';
export * from '@hakuna-matata-ui/color-mode';
import { toCSSVar, css, propNames, isStyleProp } from '@hakuna-matata-ui/styled-system';
export * from '@hakuna-matata-ui/styled-system';
import { ThemeProvider as ThemeProvider$1, Global, ThemeContext } from '@emotion/react';
export { keyframes } from '@emotion/react';
import { memoizedGet, runIfFn, omit, filterUndefined, mergeWith, objectFilter } from '@hakuna-matata-ui/utils';
import * as React from 'react';
import { useRef, useMemo } from 'react';
import isEqual from 'react-fast-compare';
import { createContext } from '@hakuna-matata-ui/react-utils';
import _styled from '@emotion/styled';
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
var ThemeProvider = function ThemeProvider(props) {
var _props$cssVarsRoot = props.cssVarsRoot,
cssVarsRoot = _props$cssVarsRoot === void 0 ? ":host, :root" : _props$cssVarsRoot,
theme = props.theme,
children = props.children;
var computedTheme = React.useMemo(function () {
return toCSSVar(theme);
}, [theme]);
return /*#__PURE__*/React.createElement(ThemeProvider$1, {
theme: computedTheme
}, /*#__PURE__*/React.createElement(Global, {
styles: function styles(theme) {
var _ref;
return _ref = {}, _ref[cssVarsRoot] = theme.__cssVars, _ref;
}
}), children);
};
function useTheme() {
var theme = React.useContext(ThemeContext);
if (!theme) {
throw Error("useTheme: `theme` is undefined. Seems you forgot to wrap your app in `<ChakraProvider />` or `<ThemeProvider />`");
}
return theme;
}
var _createContext = createContext({
name: "StylesContext",
errorMessage: "useStyles: `styles` is undefined. Seems you forgot to wrap the components in `<StylesProvider />` "
}),
StylesProvider = _createContext[0],
useStyles = _createContext[1];
/**
* Applies styles defined in `theme.styles.global` globally
* using emotion's `Global` component
*/
var GlobalStyle = function GlobalStyle() {
var _useColorMode = useColorMode(),
colorMode = _useColorMode.colorMode;
return /*#__PURE__*/React.createElement(Global, {
styles: function styles(theme) {
var styleObjectOrFn = memoizedGet(theme, "styles.global");
var globalStyles = runIfFn(styleObjectOrFn, {
theme: theme,
colorMode: colorMode
});
if (!globalStyles) return undefined;
var styles = css(globalStyles)(theme);
return styles;
}
});
};
/**
* Carefully selected html elements for chakra components.
* This is mostly for `chakra.<element>` syntax.
*/
var domElements = ["a", "b", "article", "aside", "blockquote", "button", "caption", "cite", "circle", "code", "dd", "div", "dl", "dt", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hr", "img", "input", "kbd", "label", "li", "main", "mark", "nav", "ol", "p", "path", "pre", "q", "rect", "s", "svg", "section", "select", "strong", "small", "span", "sub", "sup", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "ul"];
function omitThemingProps(props) {
return omit(props, ["styleConfig", "size", "variant", "colorScheme"]);
}
function useChakra() {
var colorModeResult = useColorMode();
var theme = useTheme();
return _extends({}, colorModeResult, {
theme: theme
});
} // inspired from ./css.ts : resolveTokenValue
var resolveTokenValue = function resolveTokenValue(theme, tokenValue, fallbackValue) {
var _ref, _getValue;
if (tokenValue == null) return tokenValue;
var getValue = function getValue(val) {
var _theme$__cssMap, _theme$__cssMap$val;
return (_theme$__cssMap = theme.__cssMap) == null ? void 0 : (_theme$__cssMap$val = _theme$__cssMap[val]) == null ? void 0 : _theme$__cssMap$val.value;
};
return (_ref = (_getValue = getValue(tokenValue)) != null ? _getValue : getValue(fallbackValue)) != null ? _ref : fallbackValue;
};
function useToken(scale, token, fallback) {
var theme = useTheme();
if (Array.isArray(token)) {
var fallbackArr = [];
if (fallback) {
fallbackArr = Array.isArray(fallback) ? fallback : [fallback];
}
return token.map(function (token, index) {
var _fallbackArr$index;
var path = scale + "." + token;
return resolveTokenValue(theme, path, (_fallbackArr$index = fallbackArr[index]) != null ? _fallbackArr$index : token);
});
}
var path = scale + "." + token;
return resolveTokenValue(theme, path, fallback);
}
function useProps(themeKey, props) {
var _theme$components, _styleConfig$defaultP;
var _useChakra = useChakra(),
theme = _useChakra.theme,
colorMode = _useChakra.colorMode;
var styleConfig = props.styleConfig || ((_theme$components = theme.components) == null ? void 0 : _theme$components[themeKey]);
var defaultProps = (_styleConfig$defaultP = styleConfig == null ? void 0 : styleConfig.defaultProps) != null ? _styleConfig$defaultP : {};
var propsWithDefault = _extends({}, defaultProps, filterUndefined(props));
var stylesRef = useRef({});
var mergedProps = mergeWith({}, propsWithDefault, {
theme: theme,
colorMode: colorMode
});
var memoizedStyles = useMemo(function () {
if (styleConfig) {
var _styleConfig$baseStyl, _styleConfig$variants, _styleConfig$variants2, _styleConfig$sizes, _styleConfig$sizes2;
var baseStyles = runIfFn((_styleConfig$baseStyl = styleConfig.baseStyle) != null ? _styleConfig$baseStyl : {}, mergedProps);
var variants = runIfFn((_styleConfig$variants = (_styleConfig$variants2 = styleConfig.variants) == null ? void 0 : _styleConfig$variants2[mergedProps.variant]) != null ? _styleConfig$variants : {}, mergedProps);
var sizes = runIfFn((_styleConfig$sizes = (_styleConfig$sizes2 = styleConfig.sizes) == null ? void 0 : _styleConfig$sizes2[mergedProps.size]) != null ? _styleConfig$sizes : {}, mergedProps);
var styles = mergeWith(baseStyles, sizes, variants);
if (styleConfig.parts) {
styleConfig.parts.forEach(function (part) {
var _styles$part;
styles[part] = (_styles$part = styles[part]) != null ? _styles$part : {};
});
}
var isStyleEqual = isEqual(stylesRef.current, styles);
if (!isStyleEqual) {
stylesRef.current = styles;
}
}
return stylesRef.current;
}, [styleConfig, mergedProps]);
return {
styles: memoizedStyles,
props: omitThemingProps(propsWithDefault)
};
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
/**
* List of props for emotion to omit from DOM.
* It mostly consists of Chakra props
*/
var allPropNames = new Set([].concat(propNames, ["textStyle", "layerStyle", "apply", "isTruncated", "noOfLines", "focusBorderColor", "errorBorderColor", "as", "__css", "css", "sx"]));
/**
* htmlWidth and htmlHeight is used in the <Image />
* component to support the native `width` and `height` attributes
*
* https://github.com/monacohq/hakuna-matata-ui/issues/149
*/
var validHTMLProps = new Set(["htmlWidth", "htmlHeight", "htmlSize"]);
var shouldForwardProp = function shouldForwardProp(prop) {
return validHTMLProps.has(prop) || !allPropNames.has(prop);
};
var _excluded$1 = ["theme", "css", "__css", "sx"],
_excluded2 = ["baseStyle"];
/**
* Style resolver function that manages how style props are merged
* in combination with other possible ways of defining styles.
*
* For example, take a component defined this way:
* ```jsx
* <Box fontSize="24px" sx={{ fontSize: "40px" }}></Box>
* ```
*
* We want to manage the priority of the styles properly to prevent unwanted
* behaviors. Right now, the `sx` prop has the highest priority so the resolved
* fontSize will be `40px`
*/
var toCSSObject = function toCSSObject(_ref) {
var baseStyle = _ref.baseStyle;
return function (props) {
props.theme;
var cssProp = props.css,
__css = props.__css,
sx = props.sx,
rest = _objectWithoutPropertiesLoose(props, _excluded$1);
var styleProps = objectFilter(rest, function (_, prop) {
return isStyleProp(prop);
});
var finalBaseStyle = runIfFn(baseStyle, props);
var finalStyles = Object.assign({}, __css, finalBaseStyle, filterUndefined(styleProps), sx);
var computedCSS = css(finalStyles)(props.theme);
return cssProp ? [computedCSS, cssProp] : computedCSS;
};
};
function styled(component, options) {
var _ref2 = options != null ? options : {},
baseStyle = _ref2.baseStyle,
styledOptions = _objectWithoutPropertiesLoose(_ref2, _excluded2);
if (!styledOptions.shouldForwardProp) {
styledOptions.shouldForwardProp = shouldForwardProp;
}
var styleObject = toCSSObject({
baseStyle: baseStyle
});
return _styled(component, styledOptions)(styleObject);
}
var chakra = styled;
domElements.forEach(function (tag) {
chakra[tag] = chakra(tag);
});
/**
* All credit goes to Chance (Reach UI), Haz (Reakit) and (fluentui)
* for creating the base type definitions upon which we improved on
*/
function forwardRef(component) {
return /*#__PURE__*/React.forwardRef(component);
}
var _excluded = ["styleConfig"];
function useStyleConfig(themeKey, props, opts) {
var _styleConfig$defaultP;
if (props === void 0) {
props = {};
}
if (opts === void 0) {
opts = {};
}
var _props = props,
styleConfigProp = _props.styleConfig,
rest = _objectWithoutPropertiesLoose(_props, _excluded);
var _useChakra = useChakra(),
theme = _useChakra.theme,
colorMode = _useChakra.colorMode;
var themeStyleConfig = memoizedGet(theme, "components." + themeKey);
var styleConfig = styleConfigProp || themeStyleConfig;
var mergedProps = mergeWith({
theme: theme,
colorMode: colorMode
}, (_styleConfig$defaultP = styleConfig == null ? void 0 : styleConfig.defaultProps) != null ? _styleConfig$defaultP : {}, filterUndefined(omit(rest, ["children"])));
/**
* Store the computed styles in a `ref` to avoid unneeded re-computation
*/
var stylesRef = useRef({});
if (styleConfig) {
var _styleConfig$baseStyl, _styleConfig$variants, _styleConfig$variants2, _styleConfig$sizes$me, _styleConfig$sizes, _opts;
var baseStyles = runIfFn((_styleConfig$baseStyl = styleConfig.baseStyle) != null ? _styleConfig$baseStyl : {}, mergedProps);
var variants = runIfFn((_styleConfig$variants = (_styleConfig$variants2 = styleConfig.variants) == null ? void 0 : _styleConfig$variants2[mergedProps.variant]) != null ? _styleConfig$variants : {}, mergedProps);
var sizes = runIfFn((_styleConfig$sizes$me = (_styleConfig$sizes = styleConfig.sizes) == null ? void 0 : _styleConfig$sizes[mergedProps.size]) != null ? _styleConfig$sizes$me : {}, mergedProps);
var styles = mergeWith({}, baseStyles, sizes, variants);
if ((_opts = opts) != null && _opts.isMultiPart && styleConfig.parts) {
styleConfig.parts.forEach(function (part) {
var _styles$part;
styles[part] = (_styles$part = styles[part]) != null ? _styles$part : {};
});
}
var isStyleEqual = isEqual(stylesRef.current, styles);
if (!isStyleEqual) {
stylesRef.current = styles;
}
}
return stylesRef.current;
}
function useMultiStyleConfig(themeKey, props) {
return useStyleConfig(themeKey, props, {
isMultiPart: true
});
}
export { GlobalStyle, StylesProvider, ThemeProvider, chakra, forwardRef, omitThemingProps, shouldForwardProp, styled, toCSSObject, useChakra, useMultiStyleConfig, useProps, useStyleConfig, useStyles, useTheme, useToken };