UNPKG

@patreon/studio

Version:

Patreon Studio Design System

73 lines 4.19 kB
'use client'; import cx from 'classnames'; import React, { memo } from 'react'; import { styled } from 'styled-components'; import { classNameForMarginBottom } from '~/styles/classNameForMarginBottom'; import { classNameForMarginLeft } from '~/styles/classNameForMarginLeft'; import { classNameForMarginRight } from '~/styles/classNameForMarginRight'; import { classNameForMarginTop } from '~/styles/classNameForMarginTop'; import { classNameForPaddingBottom } from '~/styles/classNameForPaddingBottom'; import { classNameForPaddingLeft } from '~/styles/classNameForPaddingLeft'; import { classNameForPaddingRight } from '~/styles/classNameForPaddingRight'; import { classNameForPaddingTop } from '~/styles/classNameForPaddingTop'; import { mergeResponsivePreferringLastValue, unwrapResponsive, wrapResponsive } from '~/utilities/opaque-responsive'; /** * Wraps the responsive sides and merges them into a single responsive object * which contains the top, bottom, left and right values. */ function wrapAndMergeResponsiveSides({ a, v, h, t, b, l, r }) { const responsiveA = wrapResponsive(a); const responsiveV = wrapResponsive(v); const responsiveH = wrapResponsive(h); const responsiveT = wrapResponsive(t); const responsiveB = wrapResponsive(b); const responsiveL = wrapResponsive(l); const responsiveR = wrapResponsive(r); // Cascade the responsive values to get the final responsive value // for each side: start with all, then override with vertical/horizontal, then the specfic side const responsiveTop = mergeResponsivePreferringLastValue([responsiveA, responsiveV, responsiveT]); const responsiveBottom = mergeResponsivePreferringLastValue([responsiveA, responsiveV, responsiveB]); const responsiveLeft = mergeResponsivePreferringLastValue([responsiveA, responsiveH, responsiveL]); const responsiveRight = mergeResponsivePreferringLastValue([responsiveA, responsiveH, responsiveR]); // unusually we need to use `unwrapResponsive` here because we are // passing the responsive values to the `classNameFor` functions which // expect a ValueOrResponsive value return { top: unwrapResponsive(responsiveTop), bottom: unwrapResponsive(responsiveBottom), left: unwrapResponsive(responsiveLeft), right: unwrapResponsive(responsiveRight), }; } function getClassList({ p, pv, ph, pt, pb, pl, pr, m, mv, mh, mt, mb, ml, mr, className, }) { const padding = wrapAndMergeResponsiveSides({ a: p, v: pv, h: ph, t: pt, b: pb, l: pl, r: pr }); const margin = wrapAndMergeResponsiveSides({ a: m, v: mv, h: mh, t: mt, b: mb, l: ml, r: mr }); return cx(classNameForPaddingTop({ paddingTop: padding.top }), classNameForPaddingBottom({ paddingBottom: padding.bottom }), classNameForPaddingLeft({ paddingLeft: padding.left }), classNameForPaddingRight({ paddingRight: padding.right }), classNameForMarginTop({ marginTop: margin.top }), classNameForMarginBottom({ marginBottom: margin.bottom }), classNameForMarginLeft({ marginLeft: margin.left }), classNameForMarginRight({ marginRight: margin.right }), className); } /** * The spacer component is used to create wrapper divs with the specified * margins and padding. Allowed values for margins and padding map directly to * tokens.global.spaceX values. * * @example * <Spacer m={tokens.global.space.x4} pt={tokens.global.space.x8} pb={tokens.global.space.x16}> * ... * </Spacer> */ export const Spacer = memo(function Spacer({ as = 'div', p, pv, ph, pt, pb, pl, pr, m, mv, mh, mt, mb, ml, mr, className, style, id, 'data-tag': dataTag, children, ...props // aria props }) { const Component = as; const classList = getClassList({ p, pv, ph, pt, pb, pl, pr, m, mv, mh, mt, mb, ml, mr, className }); return (<Component className={classList} style={style} id={id} data-tag={dataTag} {...props}> {children} </Component>); }); /** @deprecated use `Spacer` with `className` and css modules instead. */ export const SpacerWithCss = styled(Spacer).withConfig({ shouldForwardProp: (prop) => !['css'].includes(prop), }) ` && { ${({ css: userCss }) => userCss}; } `; //# sourceMappingURL=index.jsx.map