typescript-styled-components-px2rem
    TypeScript icon, indicating that this package has built-in type declarations

    1.5.1 • Public • Published

    typescript-styled-components-px2rem

    npm version Build Status codecov

    TypeScript transformer for convert px to rem units of styled-components

    1. Use postcss-plugin-px2rem to process all css text in template strings.

    2. Add a runtime px2rem function polyfill to process expression embedded in template strings when enable transformRuntime option.

    Babel plugin with similar functionality:babel-plugin-styled-components-px2rem.

    Table of Contents

    Requirement

    You need to install the following peerDependencies of typescript-styled-components-px2rem into your project at the same time:

    {
      "peerDependencies": {
        "typescript": "^3.0.0",
        "postcss": "^7.0.0"
      }
    }

    Usage

    ttypescript compiler

    see example

    The use of React and styled-components test cases.

    rollup

    Integration with rollup-plugin-typescript2 and ttypescript

    import typescript2 from 'rollup-plugin-typescript2';
    import tts from 'ttypescript';
     
    export default {
      // ... other rollup configs
      plugins: [
        // ...other rollup plugins
        typescript2({
          typescript: tts,
          objectHashIgnoreUnknownHack: true,
          tsconfigOverride: {
            compilerOptions: {
              module: 'ES2015',
              plugins: [
                {
                  transform: 'typescript-styled-components-px2rem',
                  rootValue: 100,
                  unitPrecision: 5,
                  minPixelValue: 0,
                  multiplier: 1,
                  tags: ['styled', 'css', 'createGlobalStyle', 'keyframes'],
                  transformRuntime: false,
                },
              ],
            },
          },
        }),
        // ...other rollup plugins
      ],
    };

    webpack

    Integration with awesome-typescript-loader or ts-loader

    const createCustomTransformer = require('typescript-styled-components-px2rem').default;
     
    const customTransformer = createCustomTransformer({
      rootValue: 100,
      unitPrecision: 5,
      minPixelValue: 0,
      multiplier: 1,
      tags: ['styled', 'css', 'createGlobalStyle', 'keyframes'],
      transformRuntime: false,
    });
     
    module.exports = {
      // ... other webpack configs
      module: {
        rules: [
          {
            test: /\.tsx?$/,
            // loader: 'awesome-typescript-loader',
            loader: 'ts-loader', // ts-loader or awesome-typescript-loader
            options: {
              // ... other loader options
              getCustomTransformers: () => ({ before: [customTransformer] }),
            },
          },
        ],
      },
    };

    Jest

    Integration with ts-jest and ttypescript:

    jest.config.js:

    module.exports = {
      // other jest configs
      globals: {
        'ts-jest': {
          compiler: 'ttypescript',
        },
      },
    };

    tsconfig.json:

    {
      "compilerOptions": {
        "plugins": [
          {
            "transform": "typescript-styled-components-px2rem",
            "type": "config",
            "rootValue": 100,
            "unitPrecision": 5,
            "minPixelValue": 0,
            "multiplier": 1,
            "tags": ["styled", "css", "createGlobalStyle", "keyframes"],
            "transformRuntime": false
          }
        ]
      }
    }

    Composition

    It should be put before typescript-plugin-styled-components

    tsconfig.json:

    {
      "compilerOptions": {
        "plugins": [
          {
            "transform": "typescript-styled-components-px2rem",
            "type": "config"
          },
          {
            "transform": "typescript-plugin-styled-components",
            "type": "config"
          }
        ]
      }
    }

    Options

    name type required default description
    rootValue number false 100 The root element font size
    unitPrecision number false 5 The decimal numbers to allow the REM units to grow to
    minPixelValue number false 0 Set the minimum pixel value to replace
    multiplier number false 1 The multiplier of input value
    tags string[] false ["styled", "css", "createGlobalStyle", "keyframes"] styled-components template literal tagged
    transformRuntime boolean false false since 1.1.0,enable transformation of all expressions that embedded in template strings

    Simple version of the formula:

    const input = '32px'; // the value in css text
    const pixels = parseFloat(input);
     
    if (pixels < minPixelValue) {
      return input;
    }
     
    const fixedVal = toFixed((pixels * multiplier) / rootValue, unitPrecision);
     
    return `${fixedVal}rem`;

    Remaining options are consistent with postcss-plugin-px2rem.

    Transform Runtime

    If enabled transformRuntime option, all supported expressions embedded in template strings are processed as follows:

    Note: Only expression that end with px will be processed.

    FunctionExpression

    source code:

    import styled from 'styled-components';
     
    export const FunctionExpression = styled.button<{ width?: number | string }>`
      width: ${function(props) {
        return props.width;
      }}px; /* Block Body */
      ${props => (props.disabled ? 'height: 400px' : 'height: 200px')};
    `;

    compiled:

    import styled from 'styled-components';
     
    export const FunctionExpression = styled.button`
      width: ${(...args) =>
        px2rem_1(function(props) {
          return props.width;
        }, ...args)}; /* Block Body */
      ${props => (props.disabled ? 'height: 4rem' : 'height: 2rem')};
    `;
     
    function px2rem_1(input, ...args) {
      if (typeof input === 'function') return px2rem_1(input(...args), ...args);
      var value = parseFloat(input);
      var pixels = Number.isNaN(value) ? 0 : value;
      if (Math.abs(pixels) < 0) return `${pixels}px`;
      var multiplier = Math.pow(10, 5 + 1);
      var wholeNumber = Math.floor(((pixels * 1) / 100) * multiplier);
      return `${(Math.round(wholeNumber / 10) * 10) / multiplier}rem`;
    }

    ArrowFunctionExpression

    source code:

    import styled from 'styled-components';
     
    const height = '44';
    export const ArrowFunction = styled.input.attrs(props => ({
      type: 'password',
      size: props.size || '16px',
      width: props.width || 100,
    }))`
      color: palevioletred;
      font-size: 14px;
      border: 1px solid palevioletred;
      border-radius: 8px;
      width: ${props => props.width}px; /* PropertyAccess Body */
      height: ${() => height}px; /* Identifier Body */
      line-height: ${() => '44'}px; /* StringLiteral Body */
      margin: ${() => 32}px; /* NumericLiteral Body */
      padding: ${props => props.size};
    `;
    export const ArrowFunctionWithBlockBody = styled.button<{ width?: number | string }>`
      width: ${props => {
        if (props.width) {
          return props.width;
        } else {
          return 0;
        }
      }}px; /* Block Body */
      ${props => (props.disabled ? 'height: 400px' : 'height: 200px')};
    `;
    export const ArrowFunctionWithBinaryBody = styled.button<{ height?: number }>`
      ${props =>
        props.disabled &&
        `
        width: 200px;
        font-size: 14px;
      `};
      height: ${props => !props.disabled && props.height}px; /* Binary Body */
    `;
    export const ArrowFunctionWithConditionalBody = styled.button<{ height?: number }>`
      height: ${props => (props.height ? height : 100)}px; /* Conditional Body */
    `;

    compiled:

    import styled from 'styled-components';
    const height = '44';
    export const ArrowFunction = styled.input.attrs(props => ({
      type: 'password',
      size: props.size || '0.16rem',
      width: props.width || 100,
    }))`
      color: palevioletred;
      font-size: 0.14rem;
      border: 1px solid palevioletred;
      border-radius: 0.08rem;
      width: ${props => px2rem_1(props.width)}; /* PropertyAccess Body */
      height: ${() => px2rem_1(height)}; /* Identifier Body */
      line-height: ${() => px2rem_1('44')}; /* StringLiteral Body */
      margin: ${() => px2rem_1(32)}; /* NumericLiteral Body */
      padding: ${props => props.size};
    `;
    export const ArrowFunctionWithBlockBody = styled.button`
      width: ${props =>
        px2rem_1(() => {
          if (props.width) {
            return props.width;
          } else {
            return 0;
          }
        })}; /* Block Body */
      ${props => (props.disabled ? 'height: 4rem' : 'height: 2rem')};
    `;
    export const ArrowFunctionWithBinaryBody = styled.button`
      ${props =>
        props.disabled &&
        `
        width: 2rem;
        font-size: 0.14rem;
      `};
      height: ${props => px2rem_1(!props.disabled && props.height)}; /* Binary Body */
    `;
    export const ArrowFunctionWithConditionalBody = styled.button`
      height: ${props => (props.height ? px2rem_1(height) : px2rem_1(100))}; /* Conditional Body */
    `;
    function px2rem_1(input, ...args) {
      if (typeof input === 'function') return px2rem_1(input(...args), ...args);
      var value = parseFloat(input);
      var pixels = Number.isNaN(value) ? 0 : value;
      if (Math.abs(pixels) < 0) return `${pixels}px`;
      var multiplier = Math.pow(10, 5 + 1);
      var wholeNumber = Math.floor(((pixels * 1) / 100) * multiplier);
      return `${(Math.round(wholeNumber / 10) * 10) / multiplier}rem`;
    }

    PropertyAccessExpression

    source code:

    import styled from 'styled-components';
     
    export const PropertyAccessExpression = styled.button<{ width: number; height: string }>(
      props => `
      width: ${props.width}px;
      height: ${props.height}; /* Note: Only expression end with 'px' will be processed. */
    `,
    );

    compiled:

    import styled from 'styled-components';
    export const PropertyAccessExpression = styled.button(
      props => `
      width: ${px2rem_1(props.width)};
      height: ${props.height}; /* Note: Only expression end with 'px' will be processed. */
    `,
    );
    function px2rem_1(input, ...args) {
      if (typeof input === 'function') return px2rem_1(input(...args), ...args);
      var value = parseFloat(input);
      var pixels = Number.isNaN(value) ? 0 : value;
      if (Math.abs(pixels) < 0) return `${pixels}px`;
      var multiplier = Math.pow(10, 5 + 1);
      var wholeNumber = Math.floor(((pixels * 1) / 100) * multiplier);
      return `${(Math.round(wholeNumber / 10) * 10) / multiplier}rem`;
    }

    ConditionalExpression

    source code:

    import React from 'react';
    import styled from 'styled-components';
     
    export const ConditionalExpression = function({ fontSize }: { fontSize?: unknown }) {
      const StyledButton = styled.button`
        font-size: ${typeof fontSize === 'number' ? fontSize : props => props?.theme.fontSize}px;
      `;
     
      return <StyledButton />;
    };
    export const ConditionalExpressionWhenTrue = function({ fontSize }: { fontSize?: unknown }) {
      const StyledButton = styled.button`
        font-size: ${typeof fontSize !== 'number' ? props => props?.theme.fontSize : fontSize}px;
      `;
     
      return <StyledButton />;
    };

    compiled:

    import React from 'react';
    import styled from 'styled-components';
    export const ConditionalExpression = function({ fontSize }) {
      const StyledButton = styled.button`
        font-size: ${typeof fontSize === 'number' ? px2rem_1(fontSize) : props => px2rem_1(props?.theme.fontSize)};
      `;
      return React.createElement(StyledButton, null);
    };
    export const ConditionalExpressionWhenTrue = function({ fontSize }) {
      const StyledButton = styled.button`
        font-size: ${typeof fontSize !== 'number' ? props => px2rem_1(props?.theme.fontSize: px2rem_1(fontSize)};
      `;
      return React.createElement(StyledButton, null);
    };
    function px2rem_1(input, ...args) {
      if (typeof input === 'function') return px2rem_1(input(...args), ...args);
      var value = parseFloat(input);
      var pixels = Number.isNaN(value) ? 0 : value;
      if (Math.abs(pixels) < 0) return `${pixels}px`;
      var multiplier = Math.pow(10, 5 + 1);
      var wholeNumber = Math.floor(((pixels * 1) / 100) * multiplier);
      return `${(Math.round(wholeNumber / 10) * 10) / multiplier}rem`;
    }

    Other Expressions

    Identifier, CallExpression, BinaryExpression, ...

    source code:

    import styled, { css, createGlobalStyle } from 'styled-components';
     
    const fontSize = 18;
    export const GlobalStyle = createGlobalStyle`
      html body {
        font-size: ${fontSize}px;
      }
    `;
     
    function getHeight() {
      const height = 100;
     
      return height / 2;
    }
    const mixins = css`
      padding: 0 16px;
    `;
    export const MixinsButton = styled.button`
      ${mixins};
      height: ${getHeight()}px;
    `;
     
    const condition = false;
    function calc() {
      return 20;
    }
    export const BinaryExpression = styled.button`
      ${condition ||
        `
        width: 200px;
      `};
      height: ${condition || 100}px;
      padding: ${40 + 50}px 8px ${4}px 16px;
      line-height: ${calc() - 2}px;
    `;

    compiled:

    import styled, { css, createGlobalStyle } from 'styled-components';
    const fontSize = 18;
    export const GlobalStyle = createGlobalStyle`
      html body {
        font-size: ${px2rem_1(fontSize)};
      }
    `;
    function getHeight() {
      const height = 100;
      return height / 2;
    }
    const mixins = css`
      padding: 0 0.16rem;
    `;
    export const MixinsButton = styled.button`
      ${mixins};
      height: ${px2rem_1(getHeight())};
    `;
    const condition = false;
    function calc() {
      return 20;
    }
    export const BinaryExpression = styled.button`
      ${condition ||
        `
        width: 2rem;
      `};
      height: ${px2rem_1(condition || 100)};
      padding: ${px2rem_1(40 + 50)} 0.08rem ${px2rem_1(4)} 0.16rem;
      line-height: ${px2rem_1(calc() - 2)};
    `;
     
    function px2rem_1(input, ...args) {
      if (typeof input === 'function') return px2rem_1(input(...args), ...args);
      var value = parseFloat(input);
      var pixels = Number.isNaN(value) ? 0 : value;
      if (Math.abs(pixels) < 0) return `${pixels}px`;
      var multiplier = Math.pow(10, 5 + 1);
      var wholeNumber = Math.floor(((pixels * 1) / 100) * multiplier);
      return `${(Math.round(wholeNumber / 10) * 10) / multiplier}rem`;
    }

    Install

    npm i typescript-styled-components-px2rem

    DownloadsWeekly Downloads

    6

    Version

    1.5.1

    License

    MIT

    Unpacked Size

    92.1 kB

    Total Files

    30

    Last publish

    Collaborators

    • xuyuanxiang