Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imple Divider Component #120

Merged
merged 5 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/components/Divider/Divider.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.divider {
width: var(--width);
min-width: var(--min-width);
max-width: var(--max-width);
height: 1px;
margin: var(--margin-top) var(--margin-right) var(--margin-bottom) var(--margin-left);
border: none;
}

.divider.gray {
background-color: var(--color-border);
}

.divider.primary {
background-color: var(--color-primary);
}
42 changes: 42 additions & 0 deletions src/components/Divider/Divider.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { render, screen } from '@testing-library/react';
import { Divider } from './Divider';

describe('<Divider>', () => {
it('receives date attribute', async () => {
render(<Divider data-testid="divider" />);
const divider = screen.getByTestId('divider');

expect(divider).toBeInTheDocument();
});

it('receives max-width', async () => {
render(<Divider data-testid="divider" maxWidth="400px" />);
const divider = screen.getByTestId('divider');

expect(divider).toHaveStyle('--max-width: 400px');
});

it('receives min-width', async () => {
render(<Divider data-testid="divider" minWidth="400px" />);
const divider = screen.getByTestId('divider');

expect(divider).toHaveStyle('--min-width: 400px');
});

it('receives width', async () => {
render(<Divider data-testid="divider" width="400px" />);
const divider = screen.getByTestId('divider');

expect(divider).toHaveStyle('--width: 400px');
});

it('receives margins', async () => {
render(<Divider data-testid="divider" mt="xxs" mr="xs" mb="sm" ml="md" />);
const divider = screen.getByTestId('divider');

expect(divider).toHaveStyle('--margin-top: var(--size-spacing-xxs)');
expect(divider).toHaveStyle('--margin-right: var(--size-spacing-xs)');
expect(divider).toHaveStyle('--margin-bottom: var(--size-spacing-sm)');
expect(divider).toHaveStyle('--margin-left: var(--size-spacing-md)');
});
});
51 changes: 51 additions & 0 deletions src/components/Divider/Divider.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentPropsWithoutRef } from 'react';
import { Divider } from './Divider';
import { Stack } from '../Stack/Stack';

export default {
component: Divider,
} satisfies Meta<typeof Divider>;

type Props = ComponentPropsWithoutRef<typeof Divider>;

const defaultArgs: Props = {
border: 'gray',
};

type Story = StoryObj<typeof Divider>;

export const Default: Story = {
render: (args) => <Divider {...args} />,
args: defaultArgs,
};

export const BorderVariants: Story = {
render: () => {
return (
<Stack spacing="md">
<Divider border="gray" />
<Divider border="primary" />
</Stack>
);
},
};

export const Margins: Story = {
render: (args) => <Divider {...args} />,
args: {
...defaultArgs,
mt: 'md',
mr: 'lg',
mb: 'xl',
ml: 'xxl',
},
};

export const Width: Story = {
render: (args) => <Divider {...args} />,
args: {
...defaultArgs,
width: '50%',
},
};
48 changes: 48 additions & 0 deletions src/components/Divider/Divider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client';

import { clsx } from 'clsx';
import { forwardRef, type HTMLAttributes } from 'react';
import styles from './Divider.module.css';
import { MarginProps, WidthProps } from '../../types/style';
import { marginVariables, widthVariables } from '../../utils/style';

type AllowedHRAttributes = Omit<HTMLAttributes<HTMLHRElement>, 'className'>;

type Props = {
/**
* ボーダーの種類
*/
border?: 'gray' | 'primary';
} & WidthProps &
MarginProps &
AllowedHRAttributes;

export const Divider = forwardRef<HTMLHRElement, Props>(
({ border = 'gray', m, mx, my, mt, mr, mb, ml, width, minWidth, maxWidth, ...rest }, ref) => {
return (
<hr
className={clsx(styles.divider, styles[border])}
style={{
...marginVariables({
m,
mx,
my,
mt,
mr,
mb,
ml,
}),
...widthVariables({
width,
minWidth,
maxWidth,
}),
}}
ref={ref}
{...rest}
/>
);
},
);

Divider.displayName = 'Divider';
16 changes: 3 additions & 13 deletions src/components/FlexItem/FlexItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
import { clsx } from 'clsx';
import { CSSProperties, forwardRef, type PropsWithChildren, type HTMLAttributes } from 'react';
import styles from './FlexItem.module.css';
import { MarginProps, PaddingProps } from '../../types/style';
import { CSSWitdh, MarginProps, PaddingProps, WidthProps } from '../../types/style';
import { marginVariables, paddingVariables } from '../../utils/style';
import { CSSWitdh, CSSMaxWidth, CSSMinWidth } from '../../utils/types';

type FlexProperty = {
grow?: number;
Expand All @@ -21,17 +20,8 @@ type Props = {
* @defaultValue none
*/
flex?: 'none' | FlexProperty;
/**
* 最小幅
* @defaultValue auto
*/
minWidth?: CSSMinWidth;
/**
* 最大幅
* @defaultValue none
*/
maxWidth?: CSSMaxWidth;
} & MarginProps &
} & Omit<WidthProps, 'width'> &
MarginProps &
PaddingProps &
AllowedDivAttributes;

Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { Box } from './components/Box/Box';
export { Button } from './components/Button/Button';
export { ButtonCard } from './components/ButtonCard/ButtonCard';
export { Center } from './components/Center/Center';
export { Divider } from './components/Divider/Divider';
export { Heading } from './components/Heading/Heading';
export { LinkButton } from './components/Button/LinkButton';
export { ErrorMessage } from './components/ErrorMessage/ErrorMessage';
Expand Down
85 changes: 85 additions & 0 deletions src/types/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,88 @@ export type RadiusProp = {
};

export type BackgroundColor = 'primary' | 'primaryDarken' | 'accent' | 'accentDarken' | 'alert' | 'gray' | 'white';

export type CSSVariable = `var(--${string})`;

// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis
export type CSSLength =
| `${string}cap`
| `${string}ch`
| `${string}em`
| `${string}ex`
| `${string}ic`
| `${string}lh`
| `${string}rcap`
| `${string}rem`
| `${string}rex`
| `${string}ric`
| `${string}rlh`
| `${string}vh`
| `${string}vmax`
| `${string}vmin`
| `${string}vw`
| `${string}vb`
| `${string}vi`
| `${string}cqw`
| `${string}cqh`
| `${string}cqi`
| `${string}cqb`
| `${string}cqmin`
| `${string}cqmax`
| `${string}px`
| `${string}cm`
| `${string}mm`
| `${string}q`
| `${string}in`
| `${string}pc`
| `${string}pt`;

export type CSSPercentage = `${string}%`;

export type CSSLengthPercentage = CSSLength | CSSPercentage;

export type CSSWitdh =
| CSSLength
| CSSPercentage
| 'auto'
| 'fit-content'
| `fit-content(${CSSLengthPercentage})`
| 'min-content'
| 'max-content'
| CSSVariable;

export type CSSMaxWidth =
| 'none'
| CSSLengthPercentage
| 'min-content'
| 'max-content'
| 'fit-content'
| `fit-content(${CSSLengthPercentage})`
| CSSVariable;

export type CSSMinWidth =
| 'auto'
| CSSLengthPercentage
| 'min-content'
| 'max-content'
| 'fit-content'
| `fit-content(${CSSLengthPercentage})`
| CSSVariable;

export type WidthProps = {
/**
* 幅を指定
* @default 'auto'
*/
width?: CSSWitdh;
/**
* 最小幅
* @default 'auto'
*/
minWidth?: CSSMinWidth;
/**
* 最大幅
* @default 'none'
*/
maxWidth?: CSSMaxWidth;
};
19 changes: 19 additions & 0 deletions src/utils/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import type {
HeadingLeading,
TagLeading,
TextColor,
CSSMinWidth,
CSSMaxWidth,
CSSWitdh,
} from '../types/style';
import type { CSSProperties } from 'react';

Expand Down Expand Up @@ -239,3 +242,19 @@ export const gapVariables = (spacing?: Spacing) => {
'--gap': spacing ? `var(--size-spacing-${spacing})` : '0',
} as CSSProperties;
};

export const widthVariables = ({
width = 'auto',
minWidth = 'auto',
maxWidth = 'none',
}: {
width?: CSSWitdh;
minWidth?: CSSMinWidth;
maxWidth?: CSSMaxWidth;
}) => {
return {
'--width': width,
'--min-width': minWidth,
'--max-width': maxWidth,
} as CSSProperties;
};
67 changes: 0 additions & 67 deletions src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,3 @@ export type AllOrNone<T> = T | Partial<Record<keyof T, undefined>>;
export type DistributiveOmit<T, TOmitted extends PropertyKey> = T extends any ? Omit<T, TOmitted> : never;

export type HTMLTagname = keyof HTMLElementTagNameMap;

export type CSSVariable = `var(--${string})`;

// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis
export type CSSLength =
| `${string}cap`
| `${string}ch`
| `${string}em`
| `${string}ex`
| `${string}ic`
| `${string}lh`
| `${string}rcap`
| `${string}rem`
| `${string}rex`
| `${string}ric`
| `${string}rlh`
| `${string}vh`
| `${string}vmax`
| `${string}vmin`
| `${string}vw`
| `${string}vb`
| `${string}vi`
| `${string}cqw`
| `${string}cqh`
| `${string}cqi`
| `${string}cqb`
| `${string}cqmin`
| `${string}cqmax`
| `${string}px`
| `${string}cm`
| `${string}mm`
| `${string}q`
| `${string}in`
| `${string}pc`
| `${string}pt`;

export type CSSPercentage = `${string}%`;

export type CSSLengthPercentage = CSSLength | CSSPercentage;

export type CSSWitdh =
| CSSLength
| CSSPercentage
| 'auto'
| 'fit-content'
| `fit-content(${CSSLengthPercentage})`
| 'min-content'
| 'max-content'
| CSSVariable;

export type CSSMaxWidth =
| 'none'
| CSSLengthPercentage
| 'min-content'
| 'max-content'
| 'fit-content'
| `fit-content(${CSSLengthPercentage})`
| CSSVariable;

export type CSSMinWidth =
| 'auto'
| CSSLengthPercentage
| 'min-content'
| 'max-content'
| 'fit-content'
| `fit-content(${CSSLengthPercentage})`
| CSSVariable;