WIP: Tailwind 유틸리티 우선 유사 구문을 사용하는 스타일이 지정된 구성 요소

저는 Tailwind와 같은 유틸리티 우선 라이브러리를 사용하는 것을 정말 좋아합니다. 신속하게 이동할 수 있고 상속보다 구성이라는 아이디어를 사용하며 가장 중요한 것은 다음과 같습니다. 일관성에 대해 걱정할 필요가 없습니다. 각 변수의 몇 가지 변형. :)

그러나 styled-components와 함께 TailWind를 사용하는 방법을 살펴보았을 때 다음과 같은 공포를 느꼈습니다.

It requires you to set up post-css (with all that extra re-render time when developing and config tweaking)



내가 이루고 싶은 것



styled-component를 작성할 때 다음과 같은 구문과 같이 Tailwind를 구문 분석할 수 있는 함수가 필요합니다.

parseUtilsString('bg-blue fc-blue-lighten p-large mt-xl') 


이는 다음으로 번역됩니다.

background-color: {defined theme blue}; 
font-color: {defined theme blue, but two increments lighter}; 
padding: {defined theme large units};
margin-top:  {defined theme extra large units};
margin-bottom:  {defined theme extra large units};


스타일 구성 요소에 추가 CSS를 추가하고 테마 변수를 사용하는 옵션도 있었으면 합니다.

소개: tiny-util-first-like-tailwind-sort-of-setup



(이 설정이 완성되면 아마 더 나은 이름을 생각해 낼 것입니다)

설정



이는 매우 간단합니다. 테마 변수를 정의하고 themeParser 또는/및 theme를 구성 요소로 가져와서 사용합니다.
styled-components에서 themeProvider를 사용할 수 있지만 작성하는 것을 알고 있습니다.

font-size: ${props => props.theme.fs.large}


생각보다 길고 번거롭다.

font-size: ${theme.fs.large}


(그래, 나는 내 캐릭터에 대해 게으르거나 싸다)

용법



그렇다면 어떻게 이 새를 날게 할 수 있을까요? 물어. 스니펫은 1000자 이상이므로 다음과 같이 합니다.

import React from 'react'
import styled from 'styled-components';
import {themeParse} from '../Styles/theme'

const HeaderStyle = styled.header`
    ${themeParse('p-l ta-c')}
    font-weight: bold;
`;

const TitleStyle = styled.div`
    ${themeParse('bg-primary-darkest fs-xl ff-primary fc-white')}
    span{
        ${themeParse('fs-s ff-secondary d-b')}
        transform-origin: bottom left;
        transform: rotate(-10deg) translateY(4em);
    }
`;


export default function Header() {
    return (
        <HeaderStyle>
            <TitleStyle>
                <span>Welcom to</span>
                tiny-util-first-like-tailwind-sort-of-setup
                </TitleStyle>
        </HeaderStyle>
    )
}


이것은 이와 같은 것으로 렌더링됩니다



사용 방법


  • 아래의 이 멋진 스니펫을 복사하여 프로젝트에 파일로 저장합니다.
  • themeStyles의 속성을 수정 및/또는 추가합니다(아마도 모든 유틸리티에 대해 짧은 이름과 같은 부트스트랩 대신 전체 이름을 선호할 것입니다. 결국 text-centerta-c보다 더 설명적입니다.)
  • node_modules에 polished 추가(또는 가져오기를 주석 처리하고 고유한 색상 음영 작성)
  • 구성 요소로 가져오고 해킹합니다.

  • import { lighten, darken } from 'polished';
    
    const units = {
      xs: 5,
      s: 10,
      m: 15,
      l: 30,
      xl: 50,
    };
    
    const fonts = {
        primary: 'Open Sans',
        secondary: 'Cursive',
    };
    
    const fontSizes = {
      xs: '.85rem',
      s: '1rem',
      m: '1.2rem',
      l: '1.5rem',
      xl: '2rem',
    };
    
    const colors = {
      primary: _setColorMap('#80C565'),
      secondary: _setColorMap('#002B55'),
      white: _setColorMap('#ffffff'),
    };
    
    const theme = {
      unit: units,
      color: colors,
      fontSize: fontSizes,
      font: fonts,
    };
    // Exported for use of independent values
    export default theme;
    
    
    const displays = {
      b: 'block',
      i: 'inline',
      ib: 'inline-block',
      f: 'flex',
      if: 'inline-flext',
      g: 'grid',
    };
    
    const textAligns = {
      c: 'center',
      l: 'left',
      r: 'right',
      j: 'justify',
    };
    
    const themeStyles = {
      fc: _renderVariationStyles('color', colors),
      ff: _renderStyleSeries('font-family', fonts, false),
      fs: _renderStyleSeries('font-size', fontSizes, false),
    
      bg: _renderVariationStyles('background-color', colors, false),
      br: _renderStyleSeries('border-radius', units),
    
      p: _renderStyleSeries('padding', units),
      py: _renderStyleSeries(['padding-top', 'padding-bottom'], units),
      px: _renderStyleSeries(['padding-left', 'padding-right'], units),
      m: _renderStyleSeries('margin', units),
      my: _renderStyleSeries(['margin-top', 'margin-bottom'], units),
      mx: _renderStyleSeries(['margin-left', 'margin-right'], units),
    
      d: _renderStyleSeries('display', displays, false),
      ta: _renderStyleSeries('text-align', textAligns, false),
    };
    
    /**
     * Parser function for tailwind like syntax
     *
     * @param {String} atomicString A set of tailwind parameters as a string
     */
    function themeParse(atomicString) {
    
      var output = atomicString.split(' ').map((classString) => {
        const [first, second, third] = classString.split('-');
    
        // Handle "flat" colors
        if (themeStyles[first][second].hasOwnProperty('base') && !third) {
          return themeStyles[first][second]['base'];
        }
        return third
          ? themeStyles[first][second][third]
          : themeStyles[first][second];
      });
      return output;
    }
    
    // Exported for use in components
    export { themeParse };
    
    /**
     * Renders the styles for a property
     *
     * @param {Array} styles
     * @param {Array} units
     * @param {Boolean} isPixleValue
     */
    function _renderStyleSeries(styles, units, isPixleValue = true) {
      // Let us use either a string value or  an array
      if (!Array.isArray(styles)) styles = [styles];
    
      let styleSerie = {};
      let suffix = isPixleValue ? 'px' : '';
      for (const unit in units) {
        styleSerie[unit] = ``;
        styles.forEach((style) => {
          styleSerie[unit] += `${style}: ${units[unit]}${suffix};`;
        });
      }
    
      return styleSerie;
    }
    
    /**
     * Renders deep nested values as e.g. 'colors'
     *
     * @param {Array} styles
     * @param {Array} units
     */
    function _renderVariationStyles(styles, units) {
      // Let us use either a string value or  an array
      if (!Array.isArray(styles)) styles = [styles];
    
      let styleSerie = {};
      for (const unit in units) {
        styleSerie[unit] = {};
        for (const subUnit in units[unit]) {
          if (subUnit === 'toString') continue;
          styleSerie[unit][subUnit] = ``;
          styles.forEach((style) => {
            styleSerie[unit][subUnit] += `${style}: ${units[unit][subUnit]};`;
          });
        }
      }
      return styleSerie;
    }
    
    /**
     * Render a color in different variations; light, lighter, lightest and dark, darker, darkest
     * Either just pass a mainColor or a set of preferred values
     *
     * @param {String} mainColor a color hex value for the standard color
     * @param {String} dark
     * @param {String} darker
     * @param {String} darkest
     * @param {String} light
     * @param {String} lighter
     * @param {String} lightest
     */
    function _setColorMap(
      mainColor,
      dark,
      darker,
      darkest,
      light,
      lighter,
      lightest
    ) {
      if (!mainColor) throw Error('Main color must be provided');
      return {
        toString: () => mainColor,
        base: mainColor,
        dark: dark || darken(0.1, mainColor),
        darker: darker || darken(0.2, mainColor),
        darkest: darkest || darken(0.4, mainColor),
        light: light || lighten(0.1, mainColor),
        lighter: lighter || lighten(0.2, mainColor),
        lightest: lightest || lighten(0.4, mainColor),
      };
    }
    
    


    엔딩 노트



    그래서 이것은 제가 생각한 것이지만 성능과 확장에 대해 많이 생각하지 않았습니다.
    제안이나 의견이 있는 경우(내가 방금 바퀴를 재발명했습니까, 아니면 작동하는 바퀴를 부술 수 있었습니까?) - 낯선 사람처럼 굴지 마십시오! 코멘트를 추가하다. :)

    좋은 웹페이지 즐겨찾기