UNPKG

@spark-web/box

Version:

--- title: Box storybookPath: page-layout-box--default isExperimentalPackage: false ---

335 lines (316 loc) 12.5 kB
import { useTheme } from '@spark-web/theme'; import { createContext, useContext } from 'react'; import { jsx } from 'react/jsx-runtime'; import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2'; import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties'; import { cx, css } from '@emotion/css'; import { resetElementStyles, buildDataAttributes } from '@spark-web/utils/internal'; import { forwardRefWithAs } from '@spark-web/utils/ts'; // prepare context var backgroundContext = /*#__PURE__*/createContext('body'); var InternalBackgroundProvider = backgroundContext.Provider; var useBackground = function useBackground() { return useContext(backgroundContext); }; // conditional provider function renderBackgroundProvider(background, element) { return background ? /*#__PURE__*/jsx(InternalBackgroundProvider, { value: background, children: element }) : element; } // a11y contrast utility var useBackgroundLightness = function useBackgroundLightness(backgroundOverride) { var backgroundFromContext = useBackground(); var background = backgroundOverride || backgroundFromContext; var theme = useTheme(); var defaultLightness = theme.backgroundLightness.body; // used by the consumer-facing/external BackgroundProvider if (background === 'UNKNOWN_DARK') { return 'dark'; } if (background === 'UNKNOWN_LIGHT') { return 'light'; } return background ? theme.backgroundLightness[background] || defaultLightness : defaultLightness; }; /** Enforce background "lightness" without applying a background color. */ var BackgroundProvider = function BackgroundProvider(_ref) { var type = _ref.type, children = _ref.children; return renderBackgroundProvider(type === 'dark' ? 'UNKNOWN_DARK' : 'UNKNOWN_LIGHT', children); }; // TODO perf review // TODO: review responsive props! Now that we're using object syntax, un-mapped properties don't behave as expected // types // Hook // ------------------------------ var useBoxStyles = function useBoxStyles(_ref) { var alignItems = _ref.alignItems, alignSelf = _ref.alignSelf, background = _ref.background, border = _ref.border, borderTop = _ref.borderTop, borderBottom = _ref.borderBottom, borderLeft = _ref.borderLeft, borderRight = _ref.borderRight, borderRadius = _ref.borderRadius, _ref$borderWidth = _ref.borderWidth, borderWidth = _ref$borderWidth === void 0 ? 'standard' : _ref$borderWidth, bottom = _ref.bottom, cursor = _ref.cursor, display = _ref.display, flex = _ref.flex, flexDirection = _ref.flexDirection, flexGrow = _ref.flexGrow, flexShrink = _ref.flexShrink, flexWrap = _ref.flexWrap, gap = _ref.gap, height = _ref.height, justifyContent = _ref.justifyContent, left = _ref.left, margin = _ref.margin, marginBottom = _ref.marginBottom, marginLeft = _ref.marginLeft, marginRight = _ref.marginRight, marginTop = _ref.marginTop, marginX = _ref.marginX, marginY = _ref.marginY, minHeight = _ref.minHeight, minWidth = _ref.minWidth, opacity = _ref.opacity, overflow = _ref.overflow, padding = _ref.padding, paddingBottom = _ref.paddingBottom, paddingLeft = _ref.paddingLeft, paddingRight = _ref.paddingRight, paddingTop = _ref.paddingTop, paddingX = _ref.paddingX, paddingY = _ref.paddingY, position = _ref.position, right = _ref.right, shadow = _ref.shadow, top = _ref.top, userSelect = _ref.userSelect, width = _ref.width, zIndex = _ref.zIndex; var theme = useTheme(); var unresponsiveProps = { background: background ? theme.color.background[background] : undefined, boxShadow: shadow ? theme.shadow[shadow] : undefined, cursor: cursor, minHeight: minHeight, minWidth: minWidth, opacity: opacity, overflow: overflow, userSelect: userSelect }; var conditionalBorderStyles = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, border ? { borderStyle: 'solid', borderColor: theme.utils.mapResponsiveScale(border, theme.border.color), borderWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width) } : {}), borderTop ? { borderTopStyle: 'solid', borderTopColor: theme.utils.mapResponsiveScale(borderTop, theme.border.color), borderTopWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width) } : {}), borderBottom ? { borderBottomStyle: 'solid', borderBottomColor: theme.utils.mapResponsiveScale(borderBottom, theme.border.color), borderBottomWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width) } : {}), borderLeft ? { borderLeftStyle: 'solid', borderLeftColor: theme.utils.mapResponsiveScale(borderLeft, theme.border.color), borderLeftWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width) } : {}), borderRight ? { borderRightStyle: 'solid', borderRightColor: theme.utils.mapResponsiveScale(borderRight, theme.border.color), borderRightWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width) } : {}); return theme.utils.resolveResponsiveProps(_objectSpread(_objectSpread(_objectSpread({}, unresponsiveProps), conditionalBorderStyles), {}, { // allow padding and height/width props to play nice display: theme.utils.mapResponsiveProp(display), // margin marginBottom: theme.utils.mapResponsiveScale(marginBottom || marginY || margin, theme.spacing), marginTop: theme.utils.mapResponsiveScale(marginTop || marginY || margin, theme.spacing), marginLeft: theme.utils.mapResponsiveScale(marginLeft || marginX || margin, theme.spacing), marginRight: theme.utils.mapResponsiveScale(marginRight || marginX || margin, theme.spacing), // padding paddingBottom: theme.utils.mapResponsiveScale(paddingBottom || paddingY || padding, theme.spacing), paddingTop: theme.utils.mapResponsiveScale(paddingTop || paddingY || padding, theme.spacing), paddingLeft: theme.utils.mapResponsiveScale(paddingLeft || paddingX || padding, theme.spacing), paddingRight: theme.utils.mapResponsiveScale(paddingRight || paddingX || padding, theme.spacing), // border borderRadius: theme.utils.mapResponsiveScale(borderRadius, theme.border.radius), // flex: parent alignItems: theme.utils.mapResponsiveScale(alignItems, flexMap.alignItems), gap: theme.utils.mapResponsiveScale(gap, theme.spacing), flexDirection: theme.utils.mapResponsiveScale(flexDirection, flexMap.flexDirection), justifyContent: theme.utils.mapResponsiveScale(justifyContent, flexMap.justifyContent), flexWrap: theme.utils.mapResponsiveProp(flexWrap), // flex: child alignSelf: theme.utils.mapResponsiveScale(alignSelf, flexMap.alignItems), flex: theme.utils.mapResponsiveProp(flex), flexGrow: theme.utils.mapResponsiveProp(flexGrow), flexShrink: theme.utils.mapResponsiveProp(flexShrink), // dimension height: theme.utils.mapResponsiveScale(height, theme.sizing), width: theme.utils.mapResponsiveScale(width, theme.sizing), // position position: theme.utils.mapResponsiveProp(position), bottom: theme.utils.mapResponsiveProp(bottom), left: theme.utils.mapResponsiveProp(left), right: theme.utils.mapResponsiveProp(right), top: theme.utils.mapResponsiveProp(top), zIndex: theme.utils.mapResponsiveScale(zIndex, theme.elevation) })); }; // Flex shorthand / adjustments // ------------------------------ var flexMap = { alignItems: { start: 'flex-start', center: 'center', end: 'flex-end', stretch: 'stretch' }, justifyContent: { start: 'flex-start', center: 'center', end: 'flex-end', spaceBetween: 'space-between', stretch: 'stretch' }, flexDirection: { row: 'row', rowReverse: 'row-reverse', column: 'column', columnReverse: 'column-reverse' } }; var _excluded$1 = ["alignItems", "alignSelf", "background", "border", "borderRadius", "borderWidth", "borderTop", "borderBottom", "borderLeft", "borderRight", "bottom", "cursor", "display", "flex", "flexDirection", "flexGrow", "flexShrink", "flexWrap", "gap", "height", "justifyContent", "left", "margin", "marginBottom", "marginLeft", "marginRight", "marginTop", "marginX", "marginY", "minHeight", "minWidth", "opacity", "overflow", "padding", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "paddingX", "paddingY", "position", "right", "shadow", "top", "userSelect", "width", "zIndex"]; /** Separate the style properties from the element attributes. */ function useBoxProps(props) { var alignItems = props.alignItems, alignSelf = props.alignSelf, background = props.background, border = props.border, borderRadius = props.borderRadius, borderWidth = props.borderWidth, borderTop = props.borderTop, borderBottom = props.borderBottom, borderLeft = props.borderLeft, borderRight = props.borderRight, bottom = props.bottom, cursor = props.cursor, display = props.display, flex = props.flex, flexDirection = props.flexDirection, flexGrow = props.flexGrow, flexShrink = props.flexShrink, flexWrap = props.flexWrap, gap = props.gap, height = props.height, justifyContent = props.justifyContent, left = props.left, margin = props.margin, marginBottom = props.marginBottom, marginLeft = props.marginLeft, marginRight = props.marginRight, marginTop = props.marginTop, marginX = props.marginX, marginY = props.marginY, minHeight = props.minHeight, minWidth = props.minWidth, opacity = props.opacity, overflow = props.overflow, padding = props.padding, paddingBottom = props.paddingBottom, paddingLeft = props.paddingLeft, paddingRight = props.paddingRight, paddingTop = props.paddingTop, paddingX = props.paddingX, paddingY = props.paddingY, position = props.position, right = props.right, shadow = props.shadow, top = props.top, userSelect = props.userSelect, width = props.width, zIndex = props.zIndex, attributes = _objectWithoutProperties(props, _excluded$1); var styles = useBoxStyles({ alignItems: alignItems, alignSelf: alignSelf, background: background, border: border, borderRadius: borderRadius, borderWidth: borderWidth, borderBottom: borderBottom, borderLeft: borderLeft, borderRight: borderRight, borderTop: borderTop, bottom: bottom, cursor: cursor, display: display, flex: flex, flexDirection: flexDirection, flexGrow: flexGrow, flexShrink: flexShrink, flexWrap: flexWrap, gap: gap, height: height, justifyContent: justifyContent, left: left, margin: margin, marginBottom: marginBottom, marginLeft: marginLeft, marginRight: marginRight, marginTop: marginTop, marginX: marginX, marginY: marginY, minHeight: minHeight, minWidth: minWidth, opacity: opacity, overflow: overflow, padding: padding, paddingBottom: paddingBottom, paddingLeft: paddingLeft, paddingRight: paddingRight, paddingTop: paddingTop, paddingX: paddingX, paddingY: paddingY, position: position, right: right, shadow: shadow, top: top, userSelect: userSelect, width: width, zIndex: zIndex }); return { styles: styles, attributes: attributes }; } var _excluded = ["as", "asElement", "className", "data", "id"]; /** Exposes a prop-based API for adding styles to a view, within the constraints of the theme. */ var Box = forwardRefWithAs(function (_ref, forwardedRef) { var _ref$as = _ref.as, Tag = _ref$as === void 0 ? 'div' : _ref$as, asElement = _ref.asElement, className = _ref.className, data = _ref.data, id = _ref.id, props = _objectWithoutProperties(_ref, _excluded); var _useBoxProps = useBoxProps(props), styles = _useBoxProps.styles, attributes = _useBoxProps.attributes; var resetStyles = resetElementStyles(asElement !== null && asElement !== void 0 ? asElement : Tag); var element = /*#__PURE__*/jsx(Tag, _objectSpread(_objectSpread({}, data ? buildDataAttributes(data) : undefined), {}, { ref: forwardedRef, id: id, className: cx(css(resetStyles), css(styles), className) }, attributes)); return renderBackgroundProvider(props.background, element); }); export { BackgroundProvider, Box, useBackground, useBackgroundLightness };