diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/Box/index.tsx | 18 | ||||
-rw-r--r-- | components/Breadcrumbs/index.tsx | 12 | ||||
-rw-r--r-- | components/Button/index.tsx | 39 | ||||
-rw-r--r-- | components/Input/index.tsx | 22 | ||||
-rw-r--r-- | components/Markdown/index.tsx | 4 | ||||
-rw-r--r-- | components/TextArea/index.tsx | 22 | ||||
-rw-r--r-- | components/Typography/index.tsx | 47 | ||||
-rw-r--r-- | components/Typography/typo.module.scss | 64 | ||||
-rw-r--r-- | components/ViewPort/index.tsx | 3 | ||||
-rw-r--r-- | components/utils/inputElementStyle.tsx | 16 | ||||
-rw-r--r-- | components/utils/systemProps.tsx | 107 |
11 files changed, 348 insertions, 6 deletions
diff --git a/components/Box/index.tsx b/components/Box/index.tsx new file mode 100644 index 0000000..32866b2 --- /dev/null +++ b/components/Box/index.tsx @@ -0,0 +1,18 @@ +import { getSystemStyle, SystemProps } from '../utils/systemProps'; + +interface BoxProps extends SystemProps { + style?: React.CSSProperties; + children?: React.ReactNode; +}; + +const Box: React.FC<BoxProps> = ({ style, children, ...props}) => { + const systemStyle = getSystemStyle(props, style); + + return ( + <div style={systemStyle}> + { children } + </div> + ); +}; + +export default Box; diff --git a/components/Breadcrumbs/index.tsx b/components/Breadcrumbs/index.tsx index c5a17b8..d773b33 100644 --- a/components/Breadcrumbs/index.tsx +++ b/components/Breadcrumbs/index.tsx @@ -6,6 +6,7 @@ import clsx from 'clsx'; export type BreadcrumbsProps = { className?: string; style?: object; + children: React.ReactNode; }; const Breadcrumbs : FC<BreadcrumbsProps> = ({children, className, ...props}) => ( @@ -25,7 +26,11 @@ const Breadcrumbs : FC<BreadcrumbsProps> = ({children, className, ...props}) => </span> ); -const Crumb : FC = ({children, ...props}) => ( +export type CrumbProps = { + children: React.ReactNode; +}; + +const Crumb : FC<CrumbProps> = ({children, ...props}) => ( <span className={styles.crumb} {...props}> {children} </span> @@ -33,12 +38,13 @@ const Crumb : FC = ({children, ...props}) => ( export type LinkCrumbProps = { href: string; + children: React.ReactNode; } const LinkCrumb : FC<LinkCrumbProps> = ({children, href, ...props}) => ( <Crumb> <Link href={href}> - <a>{children}</a> + {children} </Link> </Crumb> ); @@ -47,4 +53,4 @@ export { Crumb, Breadcrumbs, LinkCrumb -};
\ No newline at end of file +}; diff --git a/components/Button/index.tsx b/components/Button/index.tsx new file mode 100644 index 0000000..9eb2e95 --- /dev/null +++ b/components/Button/index.tsx @@ -0,0 +1,39 @@ +import React, { TextareaHTMLAttributes } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; + +interface ButtonProps + extends React.ButtonHTMLAttributes<HTMLButtonElement>, + SystemProps +{ } + +const Button: React.FC<ButtonProps> = ({ style, ...props }) => { + style = { + margin: '0.25rem 0.125rem', + cursor: 'pointer', + padding: '0.375rem 0.75rem', + borderRadius: '0.25rem', + textAlign: 'center', + verticalAlign: 'middle', + display: 'inline-block', + userSelect: 'none', + + fontFamily: 'inherit', + fontSize: '.95rem', + lineHeight: '1.15', + + // Color + color: '#fff', + backgroundColor: '#1473ff', + border: '1px solid #1473ff', + boxSizing: 'border-box', + + transition: 'color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out', + ...style, + }; + + const systemStyle = getSystemStyle(props, style); + + return (<button style={systemStyle} {...props} />); +}; + +export default Button; diff --git a/components/Input/index.tsx b/components/Input/index.tsx new file mode 100644 index 0000000..69f64fa --- /dev/null +++ b/components/Input/index.tsx @@ -0,0 +1,22 @@ +import React, { TextareaHTMLAttributes, ForwardRefRenderFunction } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; +import inputElStyle from '../utils/inputElementStyle'; + +interface InputProps + extends React.InputHTMLAttributes<HTMLInputElement>, + SystemProps +{ } + +const Input: ForwardRefRenderFunction<HTMLInputElement, InputProps> = + ({ style, ...props }, ref) => { + style = { + ...inputElStyle, + ...style, + }; + + const systemStyle = getSystemStyle(props, style); + + return <input ref={ref} style={systemStyle} {...props} />; + }; + +export default React.forwardRef(Input); diff --git a/components/Markdown/index.tsx b/components/Markdown/index.tsx index 4bb6c79..1a71330 100644 --- a/components/Markdown/index.tsx +++ b/components/Markdown/index.tsx @@ -11,7 +11,7 @@ interface MarkdownProps { const Markdown : FC<MarkdownProps> = ({md, className, ...props}) => ( <div className={clsx(styles.markdownContainer, className)} - + dangerouslySetInnerHTML={{ __html: md }} @@ -24,4 +24,4 @@ export type { MarkdownProps }; -export default Markdown;
\ No newline at end of file +export default Markdown; diff --git a/components/TextArea/index.tsx b/components/TextArea/index.tsx new file mode 100644 index 0000000..c40efed --- /dev/null +++ b/components/TextArea/index.tsx @@ -0,0 +1,22 @@ +import React, { TextareaHTMLAttributes, ForwardRefRenderFunction } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; +import inputElStyle from '../utils/inputElementStyle'; + +interface TextAreaProps + extends TextareaHTMLAttributes<HTMLTextAreaElement>, + SystemProps +{ } + +const TextArea: ForwardRefRenderFunction<HTMLTextAreaElement, TextAreaProps> = + ({ style, ...props }, ref) => { + style = { + ...inputElStyle, + ...style, + }; + + const systemStyle = getSystemStyle(props, style); + + return <textarea ref={ref} style={systemStyle} {...props} />; + }; + +export default React.forwardRef(TextArea); diff --git a/components/Typography/index.tsx b/components/Typography/index.tsx new file mode 100644 index 0000000..b9babc0 --- /dev/null +++ b/components/Typography/index.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import styles from './typo.module.scss'; +import clsx from 'clsx'; + + +type Variant = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body'; +type Align = 'inherit' | 'left' | 'center' | 'right'; + +interface TypographyProps extends React.HTMLAttributes<HTMLElement> { + variant?: Variant; + align?: Align; + gutter?: boolean; +} + +const variantTagMap: Record<Variant, keyof JSX.IntrinsicElements> = { + h1: 'h1', + h2: 'h2', + h3: 'h3', + h4: 'h4', + h5: 'h5', + h6: 'h6', + body: 'p' +}; + +const Typography: React.FC<TypographyProps> = ({ + variant = 'body', + align = 'inherit', + gutter = false, + className, + ...props +}) => { + const Tag = variantTagMap[variant] as keyof React.ReactHTML; + + const typographyClassName = clsx( + styles[`typo-${variant}`], + { + [`align-${align}`]: align !== 'inherit', + [styles['typo-gutter']]: gutter + }, + className + ); + + return <Tag className={typographyClassName} {...props} />; +}; + +export default Typography; + diff --git a/components/Typography/typo.module.scss b/components/Typography/typo.module.scss new file mode 100644 index 0000000..934333d --- /dev/null +++ b/components/Typography/typo.module.scss @@ -0,0 +1,64 @@ +.typo-h1 { + font-size: 2.8rem; + font-weight: 300; + line-height: 1.167; + letter-spacing: -0.01562em; + // margin-top: 1.0rem; + // margin-bottom: 1rem; + + padding-bottom: 0.4rem; + border-bottom: 0.12rem solid rgb(53, 53, 53); +} + +.typo-h2 { + font-size: 2.3rem; + font-weight: 300; + line-height: 1.2; + letter-spacing: -0.00833em; + + // margin-top: 1.6rem; + // margin-bottom: 0.8rem; +} + +.typo-h3 { + font-size: 1.3rem; + font-weight: 400; + line-height: 1.167; + letter-spacing: 0em; + + // margin-top: 1.3rem; + // margin-bottom: 0.5rem; +} + +.typo-h4 { + font-size: 1.25rem; +} + +.typo-h5 { + font-size: 1.15rem; +} + +.typo-h6 { + font-size: 1.10rem; +} + +.typo-h4, .typo-h5, .typo-h6 { + // margin-top: 0.8rem; + // margin-bottom: 0.6rem; +} + +.typo-p { + font-size: 1rem; + letter-spacing: 0.00938em; + font-weight: 300; +} + +.typo-p { + font-size: 1rem; + line-height: 1.5; + // margin-bottom: 1em; +} + +.typo-gutter { + margin-bottom: 0.35em; +} diff --git a/components/ViewPort/index.tsx b/components/ViewPort/index.tsx index 665ee00..29191a1 100644 --- a/components/ViewPort/index.tsx +++ b/components/ViewPort/index.tsx @@ -5,6 +5,7 @@ import clsx from 'clsx'; export type Props = { size?: "sm" | "md" | "lg"; className?: string; + children?: React.ReactNode; }; const Viewport : FC<Props> = ({children, className, size}) => { @@ -20,4 +21,4 @@ const Viewport : FC<Props> = ({children, className, size}) => { ) }; -export default Viewport;
\ No newline at end of file +export default Viewport; diff --git a/components/utils/inputElementStyle.tsx b/components/utils/inputElementStyle.tsx new file mode 100644 index 0000000..c784e85 --- /dev/null +++ b/components/utils/inputElementStyle.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +export default { + backgroundColor: '#fff', + border: '1px solid #ced4da', + padding: '0.375rem 0.75rem', + width: '100%', + borderRadius: '0.25rem', + resize: 'vertical', + fontFamily: 'inherit', + margin: '0', + display: 'block', + fontSize: '1em', + boxSizing: 'border-box', + lineHeight: '1.5rem', +} as React.CSSProperties; diff --git a/components/utils/systemProps.tsx b/components/utils/systemProps.tsx new file mode 100644 index 0000000..8fc0317 --- /dev/null +++ b/components/utils/systemProps.tsx @@ -0,0 +1,107 @@ +import React from 'react'; + +export type SystemProps = { + // Margin + mt?: number; + mb?: number; + ml?: number; + mr?: number; + mx?: number; + my?: number; + m?: number; + + // Padding + pt?: number; + pb?: number; + pl?: number; + pr?: number; + px?: number; + py?: number; + p?: number; + + // Arbitrary style + sx?: React.CSSProperties; +}; + +const calculateStyleValue = (multiplier: number, spacer: number = 1): string => { + return `${multiplier * spacer}em`; +}; + +const getSystemStyle = ( + systemProps: SystemProps, + userStyle: React.CSSProperties = {} +): React.CSSProperties => { + const spacer = 1; // 1em + + let style: React.CSSProperties = {}; + + // Margin + const { mt, mb, ml, mr, mx, my, m } = systemProps; + + if (m !== undefined) { + const value = calculateStyleValue(m, spacer); + style.marginTop = value; + style.marginBottom = value; + style.marginLeft = value; + style.marginRight = value; + } + + if (mx !== undefined) { + const value = calculateStyleValue(mx, spacer); + style.marginLeft = value; + style.marginRight = value; + } + + if (my !== undefined) { + const value = calculateStyleValue(my, spacer); + style.marginTop = value; + style.marginBottom = value; + } + + if (mt !== undefined) style.marginTop = calculateStyleValue(mt, spacer); + if (mb !== undefined) style.marginBottom = calculateStyleValue(mb, spacer); + if (ml !== undefined) style.marginLeft = calculateStyleValue(ml, spacer); + if (mr !== undefined) style.marginRight = calculateStyleValue(mr, spacer); + + // Padding + const { pt, pb, pl, pr, px, py, p } = systemProps; + + if (p !== undefined) { + const value = calculateStyleValue(p, spacer); + style.paddingTop = value; + style.paddingBottom = value; + style.paddingLeft = value; + style.paddingRight = value; + } + + if (px !== undefined) { + const value = calculateStyleValue(px, spacer); + style.paddingLeft = value; + style.paddingRight = value; + } + + if (py !== undefined) { + const value = calculateStyleValue(py, spacer); + style.paddingTop = value; + style.paddingBottom = value; + } + + if (pt !== undefined) style.paddingTop = calculateStyleValue(pt, spacer); + if (pb !== undefined) style.paddingBottom = calculateStyleValue(pb, spacer); + if (pl !== undefined) style.paddingLeft = calculateStyleValue(pl, spacer); + if (pr !== undefined) style.paddingRight = calculateStyleValue(pr, spacer); + + // Merge with arbitrary styles (sx) + if (systemProps.sx) { + style = { ...style, ...systemProps.sx }; + } + + // Override with user-defined style + style = { ...style, ...userStyle }; + + return style; +}; + +export { + getSystemStyle +}; |