styled-components와 csstype으로 안전한 Chakra UI 구성 요소 만들기

세 줄을 한데 모으다.
  • css mixin을 사용하여 여러 구성 요소에 사용할 스타일 조수를 만들 수 있음
  • csstype를 사용하여Typolphy, 스페이스, Color 등 유형의props
  • 를 제작할 수 있다.
  • 기본 구성 요소에서 혼합 모델의props를 수신하고mixin에서 조형하여 ChakraUI와 같은 유형의 안전한 스타일 설명을 할 수 있음
  • 뭐 하고 싶어요?


    차크라 UI 같은 작법을 쓰고 싶어 이번 기사의 주제는 스타일드-components로 할 수 있는지 없는지를 시험해보자는 것이다.
    export default function App() {
      return (
        <VStack spacing={4} w="100vw" h="100vh" px={4} py={8} bgColor={palette.white}>
          <HStack w="100%">
            <Typography>🍣🍕🍣</Typography>
            <StackSpacer />
            <Typography fontSize="xx-large">🍣🍕🍣</Typography>
          </HStack>
    
          <Typography fontSize="xxx-large">🍕</Typography>
    
          <Typography color={palette.brown} textDecoration="underline">
            Typographyでマークアップした文章マークアップした文章Typographyでマークアップした文章
          </Typography>
    
          <StackSpacer />
    
          <Button label="ボタン" onPress={() => console.log('pressed')} />
          <Button label="primary button" primary onPress={() => console.log('pressed')} />
          <Button label="DANGER!!!" danger onPress={() => console.log('pressed')} />
        </VStack>
      );
    }
    
    スクリーンショット
    전례Magnus UI 등으로 이번에는 자신이 실시하면 어떤 느낌을 받을지 해보고 싶어서 스타일드-components의 스타일링과 csstype의 유형으로 정의하기로 했다.

    개발 환경


    {
      "dependencies": {
        "csstype": "^3.0.7",
        "expo": "~40.0.0",
        "react": "16.13.1",
        "react-dom": "16.13.1",
        "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
        "react-native-web": "~0.13.12",
        "styled-components": "^5.2.3"
      },
      "devDependencies": {
        "@types/styled-components": "^5.1.9",
        "@types/styled-components-react-native": "^5.1.1",
        "typescript": "~4.0.0"
      }
    }
    

    생성된 소스 코드


    다음 창고에는 PUSH가 있습니다.
    https://github.com/suzukalight/study-styled-components-mixin-csstype-expo

    Styled-components의 Mixin 모드 사용


    여기서 글꼴과 관련된 CSS형 정의를 열거하여 구체적인 예로 Typolaphy 구성 요소를 만들어 보겠습니다.
    먼저 font Mixin부터 만들기;
    import * as CSS from 'csstype';
    import { css } from 'styled-components';
    
    export type FontProps = {
      fontSize: CSS.Property.FontSize;
      fontWeight: CSS.Property.FontWeight;
      lineHeight: CSS.Property.LineHeight;
    };
    
    export const fontMixin = css<Partial<FontProps>>`
      ${({ fontSize }) => fontSize != null && `font-size: ${fontSize};`}
      ${({ fontWeight }) => fontWeight != null && `font-weight: ${fontWeight};`}
      ${({ lineHeight }) => lineHeight != null && `line-height: ${lineHeight};`}
    `;
    
    CSS의 TypeScript형 정의는 csstype를 사용했습니다.차크라 UI도 활용된다.CSS.Property.X에서 X의 유효한 값을 얻어 각 변수에 유형으로 분배할 수 있다.
    styled-componentscss의 조수 함수를 사용하여mixin을 만듭니다.CSS 생성 논리를 분리하여 여러 구성 요소에 대한 스타일 처리를 정의할 수 있습니다.

    Mixin을 기본 구성 요소로 사용


    이어서 Typolaphy 구성 요소를 만들고 실제 믹스를 사용합니다.
    import React, { ReactNode } from 'react';
    import styled from 'styled-components/native';
    
    import { colorMixin, ColorProps } from '../../styles/color';
    import { FontProps, fontMixin } from '../../styles/typography';
    
    export type TypographyStyledProps = Partial<FontProps> & Partial<ColorProps>;
    
    export const TypographyStyled = styled.Text`
      ${fontMixin}
      ${colorMixin}
    `;
    
    export type TypographyProps = TypographyStyledProps & {
      children?: ReactNode;
    };
    
    export const Typography = ({ children, ...styles }: TypographyProps) => (
      <TypographyStyled children={children} {...styles} />
    );
    
    어셈블리의 Proops로서 방금 정의한 FontProops를 자신의 Proops에 결합합니다.Partial로 병합하여 옵션 속성으로 반영합니다.이렇게 하면 사용자가 지정한 속성만 스타일에 덮어쓸 수 있습니다.
    방금 만든 font Mixin을 자신의 스타일 기술부로 가져오면 스타일을 덮어쓸 수 있습니다.구성 요소의 고유한 스타일을 설정하려면mixin 아래에서 계속 기술할 수 있습니다.
    이 예에서 별도로 제작된 컬러믹스도 믹스에서 이런 느낌으로 레이아웃, 스페이스, 백그라운드 등 믹스를 만들어 결합해 사용하는 형태가 최종 목표다.각양각색의 자제 부품이 통일감 있는 프로퍼스가 조형할 수 있는 환경을 지정하면 생산성이 뛰어난 것이 맞습니다!

    실제로 Props로 스타일링을 해봤어요.


    제작된 기초 구성 요소의 한 쪽을 이용하여props를 통해 스타일을 지정할 수 있습니다.
    const Page = () => (
      <VStack spacing={4} w="100vw" h="100vh" px={4} py={8} bgColor={palette.white}>
        <HStack w="100%">
          <Typography>🍣🍕🍣</Typography>
          <StackSpacer />
          <Typography fontSize="xx-large">🍣🍕🍣</Typography>
        </HStack>
    
        <Typography color={palette.brown} textDecoration="underline">
          Typographyでマークアップした文章マークアップした文章Typographyでマークアップした文章
        </Typography>
      </VStack>
    );
    
    다음은 Typegraphiy 구성 요소 인코딩을 실제로 사용할 때의 vscode 힌트입니다.정의되지 않은 props를 추가하거나 부정확한 유형의 매개 변수를 props로 전달하면 오류임을 확인할 수 있습니다.
    サジェスト結果

    응용편


    문장은 주제의 내용을 이전 절까지 다음과 같이 특수한 상황에 대한 응용이다.

    'x-large'이런 디자인 영패를 추가하고 싶어요.


    디자인 시스템을 운용하는 상황에서 때로는 CSS 값 자체를 사용하지 않고 이용 범위를 더욱 축소x-large하는 디자인 영패를 사용하려고 한다.
    export type StyleSize = 'large' | 'medium' | 'small';
    
    이러한 상황에서 이 유형의 정의를 추가하고 이를 CSS로 전환하는 예처리를 할 수 있다.
    import { StyleSize } from './type';
    
    const fontSizes: { [key in StyleSize]: string } = {
      small: '12px',
      medium: '16px',
      large: '20px',
    };
    
    export type FontSize = StyleSize | CSS.Property.FontSize;
    export type FontProps = {
      fontSize: FontSize;
      /* 以下省略 */
    };
    
    export const fz = (fontSize?: FontSize) => {
      if (typeof fontSize === 'string') return fontSizes[fontSize as StyleSize] ?? fontSize;
      if (typeof fontSize === 'number') return `${fontSize}px`;
      return 'inherit';
    };
    
    export const fontMixin = css<Partial<FontProps>>`
      ${({ fontSize }) => fontSize != null && `font-size: ${fz(fontSize ?? 'medium')};`}
    `;
    

    스파링으로 Stack 사이에 보증금을 추가하고 싶어요.


    웹의 React라면 문제없지만 React Native는 CSS에 대한 시뮬레이션 지원만 할 뿐 일부 CSS 기재법은 이용할 수 없습니다.구체적으로 인접 선택기는 사용할 수 없고 기술할 수 없음& > * + * 같은 Stack(방법이 있으면 알려주세요).
    그래서 이번엔 CSS가 아닌 JS가 대응할 겁니다.구체적으로 말하면children에margin-top: x를 주어 대응한다.
    export const VStack = ({ children, spacing, ...styles }: VStackProps) => {
      const childrenWithProps = spacing
        ? React.Children.map(children, (child) => {
            if (!React.isValidElement(child)) return child;
            return React.cloneElement(child, {
              style: { marginTop: sizeValueToPixel(spacing as number) },
            });
          })
        : children;
    
      return <VStackStyled children={childrenWithProps} {...styles} />;
    };
    

    references

  • csstype
  • styled-components: API Reference
  • javascript - How to pass props to {this.props.children} - Stack Overflow
  • 좋은 웹페이지 즐겨찾기