🎨(app-desk) add margin and padding to Box

Add margin and padding system to Box component.
It proposes the autocompletion.
It is bind with the Cunninghams spacing system.
This commit is contained in:
Anthony LC
2024-04-29 12:41:12 +02:00
committed by Anthony LC
parent c94888fe09
commit a45408c93c
4 changed files with 143 additions and 2 deletions

View File

@@ -1,3 +1,4 @@
import '@testing-library/jest-dom';
import * as dotenv from 'dotenv';
dotenv.config({ path: './.env.test' });

View File

@@ -2,6 +2,12 @@ import { ComponentPropsWithRef, ReactHTML } from 'react';
import styled from 'styled-components';
import { CSSProperties } from 'styled-components/dist/types';
import {
MarginPadding,
stylesMargin,
stylesPadding,
} from '@/utils/styleBuilder';
export interface BoxProps {
as?: keyof ReactHTML;
$align?: CSSProperties['alignItems'];
@@ -15,11 +21,13 @@ export interface BoxProps {
$height?: CSSProperties['height'];
$justify?: CSSProperties['justifyContent'];
$overflow?: CSSProperties['overflow'];
$maxWidth?: CSSProperties['maxWidth'];
$margin?: MarginPadding;
$minWidth?: CSSProperties['minWidth'];
$padding?: MarginPadding;
$position?: CSSProperties['position'];
$radius?: CSSProperties['borderRadius'];
$width?: CSSProperties['width'];
$maxWidth?: CSSProperties['maxWidth'];
$minWidth?: CSSProperties['minWidth'];
}
export type BoxType = ComponentPropsWithRef<typeof Box>;
@@ -36,7 +44,9 @@ export const Box = styled('div')<BoxProps>`
${({ $gap }) => $gap && `gap: ${$gap};`}
${({ $height }) => $height && `height: ${$height};`}
${({ $justify }) => $justify && `justify-content: ${$justify};`}
${({ $margin }) => $margin && stylesMargin($margin)}
${({ $overflow }) => $overflow && `overflow: ${$overflow};`}
${({ $padding }) => $padding && stylesPadding($padding)}
${({ $position }) => $position && `position: ${$position};`}
${({ $radius }) => $radius && `border-radius: ${$radius};`}
${({ $width }) => $width && `width: ${$width};`}

View File

@@ -0,0 +1,51 @@
import { render, screen } from '@testing-library/react';
import { Box } from '../Box';
describe('<Box />', () => {
it('has the padding from prop', () => {
const { unmount } = render(<Box $padding="10px">My Box</Box>);
expect(screen.getByText('My Box')).toHaveStyle('padding: 10px');
unmount();
render(
<Box $padding={{ horizontal: 'xl', all: 'large', bottom: 'tiny' }}>
My Box
</Box>,
);
expect(screen.getByText('My Box')).toHaveStyle(`
padding-left: 4rem;
padding-right: 4rem;
padding-top: 3rem;
padding-bottom: 0.5rem;`);
});
it('has the margin from prop', () => {
const { unmount } = render(<Box $margin="10px">My Box</Box>);
expect(screen.getByText('My Box')).toHaveStyle('margin: 10px');
unmount();
render(
<Box
$margin={{
horizontal: 'auto',
vertical: 'big',
bottom: 'full',
all: 'xtiny',
}}
>
My Box
</Box>,
);
expect(screen.getByText('My Box')).toHaveStyle(`
margin-left: auto;
margin-right: auto;
margin-top: 1.625rem;
margin-bottom: 100%;`);
});
});

View File

@@ -0,0 +1,79 @@
import { tokens } from '@/cunningham/cunningham-tokens';
/* eslint-disable @typescript-eslint/no-unused-vars */
const {
'0': _0,
st,
t,
s,
b,
bx,
l,
...spacingsLight
} = tokens.themes.default.theme.spacings;
/* eslint-enable @typescript-eslint/no-unused-vars */
const spacings = {
xtiny: tokens.themes.default.theme.spacings['st'],
tiny: tokens.themes.default.theme.spacings['t'],
small: tokens.themes.default.theme.spacings['s'],
big: tokens.themes.default.theme.spacings['b'],
xbig: tokens.themes.default.theme.spacings['bx'],
large: tokens.themes.default.theme.spacings['l'],
...spacingsLight,
};
type SpacingsKey = keyof typeof spacings;
// eslint-disable-next-line @typescript-eslint/ban-types
export type Spacings = SpacingsKey | (string & {});
export const spacingValue = (value?: Spacings) =>
value && value in spacings ? spacings[value as SpacingsKey] : value;
export type MarginPadding =
| Spacings
| {
vertical?: Spacings;
horizontal?: Spacings;
top?: Spacings;
bottom?: Spacings;
left?: Spacings;
right?: Spacings;
all?: Spacings;
};
export const stylesPadding = (pad: MarginPadding) => {
if (typeof pad === 'object') {
return {
'padding-top': spacingValue(pad.top || pad.vertical || pad.all),
'padding-bottom': spacingValue(pad.bottom || pad.vertical || pad.all),
'padding-left': spacingValue(pad.left || pad.horizontal || pad.all),
'padding-right': spacingValue(pad.right || pad.horizontal || pad.all),
};
} else {
return {
padding: spacingValue(pad),
};
}
};
export const stylesMargin = (margin: MarginPadding) => {
if (typeof margin === 'object') {
return {
'margin-top': spacingValue(margin.top || margin.vertical || margin.all),
'margin-bottom': spacingValue(
margin.bottom || margin.vertical || margin.all,
),
'margin-left': spacingValue(
margin.left || margin.horizontal || margin.all,
),
'margin-right': spacingValue(
margin.right || margin.horizontal || margin.all,
),
};
} else {
return {
margin: spacingValue(margin),
};
}
};