@patreon/studio
Version:
Patreon Studio Design System
114 lines • 5.74 kB
JSX
'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 { unwrapResponsive, mergeResponsivePreferringLastValue, wrapResponsive, } from '../../utilities/opaque-responsive';
import { safeResponsiveClassNameFor } from '../../utilities/responsive-style';
import { useIncrementLogger } from '../IncrementLogger';
/**
* 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, incrementLogger, }) {
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(safeResponsiveClassNameFor({
classNameFn: classNameForPaddingTop,
props: { paddingTop: padding.top },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.padding_top',
}), safeResponsiveClassNameFor({
classNameFn: classNameForPaddingBottom,
props: { paddingBottom: padding.bottom },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.padding_bottom',
}), safeResponsiveClassNameFor({
classNameFn: classNameForPaddingLeft,
props: { paddingLeft: padding.left },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.padding_left',
}), safeResponsiveClassNameFor({
classNameFn: classNameForPaddingRight,
props: { paddingRight: padding.right },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.padding_right',
}), safeResponsiveClassNameFor({
classNameFn: classNameForMarginTop,
props: { marginTop: margin.top },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.margin_top',
}), safeResponsiveClassNameFor({
classNameFn: classNameForMarginBottom,
props: { marginBottom: margin.bottom },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.margin_bottom',
}), safeResponsiveClassNameFor({
classNameFn: classNameForMarginLeft,
props: { marginLeft: margin.left },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.margin_left',
}), safeResponsiveClassNameFor({
classNameFn: classNameForMarginRight,
props: { marginRight: margin.right },
incrementLogger,
incrementName: 'studio.spacer.responsive_error.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 { incrementLoggerOnce: incrementLogger } = useIncrementLogger();
const classList = getClassList({ p, pv, ph, pt, pb, pl, pr, m, mv, mh, mt, mb, ml, mr, className, incrementLogger });
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) `
&& {
${({ css: userCss }) => userCss};
}
`;
//# sourceMappingURL=index.jsx.map