Giter VIP home page Giter VIP logo

babel-plugin-styled-components-css-namespace's Introduction

@quickbaseoss/babel-plugin-styled-components-css-namespace

Travis CI status and link to builds

Getting Started

  1. Add the plugin with yarn add @quickbaseoss/babel-plugin-styled-components-css-namespace or npm install @quickbaseoss/babel-plugin-styled-components-css-namespace
  2. Include the plugin in your babel configuration.
"babel": {
  "plugins": [
    "@quickbaseoss/babel-plugin-styled-components-css-namespace"
  ]
}

If you are also using babel-plugin-styled-components, you must place styled-components-css-namespace before babel-plugin-styled-components.

"babel": {
  "plugins": [
    "@quickbaseoss/babel-plugin-styled-components-css-namespace",
    "babel-plugin-styled-components"
  ]
}

Options

Default

Without adding options, this plugin will duplicate the class name generated by styled-components as suggested in this issue.

/* output */
.c0.c0 {
  background-color: blue;
}

Increasing Specificity

A common scenario when integrating styled-components into existing projects is fighting against extremely specific legacy CSS selectors such as #someId .grossly .nested section input {/* styles */}.

To increase the specificity that this plugin adds, you can leverage the recommended approach from the styled-components docs. Add the appropriate number of & selectors equal to the desired selector duplication as the cssNamespace option (the default behavior is x2 {"cssNamespace": "&&"}).

{
  "plugins": [
    [
      "@quickbaseoss/babel-plugin-styled-components-css-namespace",
      {"cssNamespace": "&&&"}
    ],
    "babel-plugin-styled-components"
  ]
}
/* output */
.c0.c0.c0 {
  background-color: blue;
}

Custom Namespace

You can provide a cssNamespace to use instead of duplicating the class name. Remember to include a DOM element with that class that wraps the styled-component. The cssNamespace takes the form of the selector you want to use to wrap all of your styles with.

"babel": {
  "plugins": [
    ["@quickbaseoss/babel-plugin-styled-components-css-namespace", {"cssNamespace": ".specific .moreSpecific .reallySpecific"}],
    "styled-components"
  ]
}
/* output */
.specific .moreSpecific .reallySpecific .c0 {
  background-color: blue;
}

where .c0 is the class added by styled-components to the element

Notes

Media Query String Interpolation

While an uncommon use-case, it can often be useful to interpolate media query at-rules in your css template string. Compared to the method for creating media queries from the styled-component docs, this method reduces the overhead of multiple calls of css while still allowing queries to be constructed without requiring nested template literals.

const mediaQuery = '@media only screen and (min-width: 426px)'

const StyledComponent = styled.div`
  background-color: red;
  ${mediaQuery} {
    background-color: blue;
  }
`

Unfortunately, this syntax is identical to the syntax used to refer to other components and this plugin cannot distinguish between the two and will produce broken CSS rules. Since referring to other components is more common, the below method of formatting @media inline can be used as a workaround.

const mediaQuery = 'only screen and (min-width: 426px)';

const StyledComponent = styled.div`
  background-color: red;
  @media ${mediaQuery} {
    background-color: blue;
  }
`;

Upgrade to version 1.0.0

Note that rawCssNamespace was dropped in favor of the single cssNamespace option. Additionally, support for an array of selectors was dropped as well. Update any references to rawCssNamespace with cssNamespace.

If you were already using cssNamespace, update your configuration to use a css selector rather than an array of classes. E.g., cssNamespace: 'moreSpecific' should be cssNamespace: '.moreSpecific' and cssNamespace: ['specific', 'verySpecific'] should be cssNamespace: '.specific .verySpecific'.

The Problem

styled-components is an awesome library for css-in-js and feels like a natural combination of React and CSS. It is easy to use and produces css instead of inline styles.

However, if you are trying to gradually introduce styled-components into a legacy website that might not have the best CSS, the legacy styles may bleed into your styled-components because they have more specificity than the single class styled-components.

The Solution

This plugin will automatically add additional css namespaces or duplicated classes to the selectors produced by styled components effectively creating a wall between the legacy css code and your new shiny styled components.

monty-python-castle

Styling frameworks

This plugin was built for Styled Components; however, since initially creating it, we at Quick Base have switched to Emotion. It works as an alternative to the stylis extra scope plugin which requires creating your own instance of stylis.

Developing

  1. Clone the repo with git clone https://github.com/QuickBase/babel-plugin-styled-components-css-namespace.git
  2. yarn install (prefer yarn although npm should work as well)
  3. yarn test to run the tests

Publishing

When we are ready to release a new version, one of the admins needs to run the following commands to publish the new version to npm. We probably need to invest in a better deploy and semver management system. Interested? See this issue.

  • If needed, open a new PR to update the version in the package.json
  • Copy the commit hash from the commit log
  • Run git tag -a {version} {commit_hash}. For example: git tag -a 0.0.9 abf3123
  • In the editor, add a message about the changes in this version and save
  • Push the tag to GitHub with git push --follow-tags
  • Travis CI will build and publish the new version to npm

Acknowledgements

Open source software is a group effort. This version of the plugin was heavily inspired by a fork of the original plugin from @TrevorBurnham.

We also would like to thank some of our contributors who helped solve some tough issues with the previous iteration of this plugin:

  • @daniloster
  • @dan-kez
  • @prevostc
  • @danielhusar

babel-plugin-styled-components-css-namespace's People

Contributors

dan-kez avatar danielhusar avatar daniloster avatar dependabot[bot] avatar erikthedeveloper avatar ikonrad avatar jpylisela avatar nvanselow avatar prevostc avatar tinynumbers avatar zachhardesty7 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

babel-plugin-styled-components-css-namespace's Issues

Valid CSS cannot be parsed

Hi! First of all, thanks for this plugin! I run into CSS parsing errors when trying to add it to my project.
Minimal reproducible example:

const a = '2px';
const MyStyledComponent = styled.div`
  padding: ${a} ${a} ${a} ${a};
`;

Internally, this CSS snippet gets transpiled into:

padding: fake-element-placeholder fake-element-placeholder fake-element-placeholder fake-element-placeholder: fakevalue;

...which makes postcss complain about the missing semicolon.

Another example that causes parser to fail:

const padding = 'padding: 2px 2px 2px 2px;';
const MyStyledComponent = styled.div`
  ${padding}
`;

This time it get transpiled to:

fake-element-placeholder

Which causes Error: <css input>:3:3: Unknown word error.
I would be more than happy to help with fixing this issue, however, I might need some tips & guidance ๐Ÿ˜„

Cheers!

Usage with in an NPM package

Hi there,

I have an app and some npm packages. I bundle these packages using rollup. I would like to use this plugin on my packages bundled with rollup, however, I can't seem to get it to work. I'm using the rollup-babel plugin. Do I need to include the packages in my app babel config? How could I make this work?

Thanks!

Fix Known Issue with Sibling Selector

Hi I'm using styled-components in my current project and want to use this babel plugin as suggested by the official docs to prevent third-party styling of my components when embedded as a widget.

The styled components in this projects make quite some use of the & and sibling operator ~ which is not working and a known issue as stated in the docs. Is there any ambition to fix this in a future release as it seems to be fixed when using the rawCssNamepsace option? Unfortunately the rawCssNamespace option does not work in my project and my webpack dev server is not starting, it seems to be stuck in an infinite loop. I tried to debug it but till now I had no luck. Any hints are highly appreciated.

Issue in Component Interpolation inside `&.className`

If I write code like this

const SomeDiv = styled.div`
	span {
		color: blue;
	}
	&.is-span-red {
		span {
			color: red;
		}
	}
`;

It works good. But if I try to interpolate another styled-component inside the &.is-span-red, it doesn't work.

const SomeSpan = styled.span``;

const SomeDiv = styled.div`
	&.is-span-red {
		${SomeSpan} {
			color: red;
		}
	}
`;

Template literal not accepted

Hi,
here an example of code

export const AnchorWrapper = styled.div<{ selected: boolean }>
box-sizing: border-box;
width: fit-content;

${({ selected, theme: { colors, mediaQueries } }) =>
mediaQueries?.isMobile
? cssdisplay: flex; flex-direction: row; align-items: center; padding: ${pxToRem(8)} 0 ${pxToRem(8)} ${pxToRem(16)}; border-left: ${pxToRem(3)} solid ${selected ? colors.lightAccentDefault : colors.neutral300};
: cssheight: ${pxToRem(56)}; display: flex; flex-direction: column; justify-content: space-between; align-items: center; padding: ${pxToRem(21)} 0 ${pxToRem(14)}; gap: ${pxToRem(4)};}
;

and this is the error on returned

`ERROR in ../ui/build/src/atoms/Anchor/styles.js
Module build failed (from ../../node_modules/babel-loader/lib/index.js):
Error: prj/ui.frontend/packages/ui/build/src/atoms/Anchor/styles.js: There was a problem adding namespaces to this CSS in the file prj/ui.frontend/packages/ui/build/src/atoms/Anchor/styles.js. Error: :6:3: Unknown word
CSS:
box-sizing: border-box;
width: fit-content;

fake-element-placeholder-0
`

any known solution?

NodeJs compatibility

Hey all, I was working with this plugin on the node version 12.15.0 and over there it wasn't working... by downgrading to 12.4.0 it did work. Met me post more details soon, but any suggestions where this is coming from?

The issue I encountered was that the webpack build kept spinning reaching some of the first encountered styled-components. repeatedly the same file. (implementation of the component made no difference). simple for example: styled.div with background color

also running the test directly in the repo seems to be broken?
image

after this test i downgraded to node 11.9.0 via nvm. result is that jest is run within seconds!
image

checking versions it seems like version 12.10 is correct, higher is broken. confirmed 12.11.0 is not working, (12.11.1 also broken )

Media Query String Interpolation Bug

Just discovered what appears to be a bug with this library that causes media queries to be improperly parsed by placing the class name in the improper location. Unfortunately no error is produced so.

To reproduce

const mediaQuery = '@media only screen and (min-width: 426px) and (max-width: 767px)'

const Component = styled.div`
  background-color: red;
  ${mediaQuery} {
    background-color: blue;
  }
`

Without interpolating the string, it works fine, but the above produces a rule like this:

/* sc-component-id: sc-14zearg-1 */
.jmWrIX.jmWrIX{background-color: red;}
.jmWrIX.jmWrIX @media only screen and (min-width: 426px) and (max-width: 767px){background-color: blue;}

while it should produce a rule like this:

/* sc-component-id: sc-14zearg-1 */
.jmWrIX.jmWrIX{background-color: red;}
@media only screen and (min-width: 426px) and (max-width: 767px){.jmWrIX.jmWrIX{background-color: blue;}}

.extend`` not working with namespace

Hey there,
I am not entirely sure if this is an issue for intended behaviour, so maybe someone can just explain?!
But I have the problem, that I have some styled components, which I am also extending and then using in a bigger application. That's why I wanted to use this plugin, to up the specificity of those components.
For example

export const Button = styled.button`
  [...]
`;

export const ExtendedButton = Button.extend`
  [...]
`;

The problem is that the extended styles don't seem to get the prefix like the main styles do:
screen shot 2018-09-06 at 13 10 18

Just for reference, this is the config for the plugin I am using: ["@quickbaseoss/babel-plugin-styled-components-css-namespace", { "cssNamespace": "folders" }]

Can anyone help?

Works with Emotion?

Hi there,

This is exactly what I need for a pesky CSS problem ๐Ÿ‘

Does this work with Emotion 11 (@emotion/styled)? I am also using theme-ui to make the compiling even more interesting ๐Ÿ˜„

I am not seeing any modifications to the CSS, though it could very well be user-error. Any thoughts?

     {
                test: /\.(js|jsx|ts|tsx)$/,
                exclude: /node_modules/,
                loader: "babel-loader",
                options: {
                    presets: [
                        ["@babel/preset-env", {}],
                        "@babel/preset-typescript",
                        [
                            "@babel/preset-react",
                            {
                                runtime: "automatic",
                                importSource: "react"
                            }
                        ]
                    ],
                    plugins: [
                        ["@quickbaseoss/babel-plugin-styled-components-css-namespace", { cssNamespace: "&&&&" }],
                        "@babel/proposal-class-properties",
                        "@babel/proposal-object-rest-spread"
                    ]
                }

And the button

/** @jsxImportSource theme-ui */

import { Button as VendorButton, ButtonProps } from "@thirdpartyidontcontrol";
import styled from "@emotion/styled";
import { ReactNode } from "react";

export interface ButtonProps extends ButtonProps {
    sx?: Record<string, string>;
    variant?: string;
    children?: ReactNode;
}

const StyledButton = styled(VendorButton)``;

export function Button(props: ButtonProps) {
    const { sx: obj = {}, variant = "" } = props;
    const sx = { variant, ...obj };
    return <StyledButton {...props} />;
}

I am wondering if isStyled is evaluating to false, since it is Emotion and not in the approved list?

This would be a big help if emotion was supported, and I would be happy to help contribute to that end (if this is indeed the issue ๐Ÿคท )

Namespace break adjacent sibling combinator selector

First all thank for this plugin, is solved a very annoying CSS override issue between our 2 projects.

My issue is that:

const InfoContainer = styled.div`
  display: flex;
  & + & {
    margin-left: 0.5rem;
  }
`;

now generate the style ('spa' is our namespace):

.sc-eHgmQL {}.spa .hVujAK{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;} .spa .hVujAK + .spa .hVujAK{margin-left:0.5rem;}

With that style the margin-left is never applied because the selector should be .spa .hVujAK + .hVujAK instead of .spa .hVujAK + .spa .hVujAK

Is that fixable in babel-plugin-styled-components-css-namespace?

Plugin gives errors in case of // comments

Seems partially related to #33 or #46

Preamble: I migrated from old version 0.1.1 to 1.0.0-rc4 and a working application stopped working. I already read and performed migration procedure, converting class names and so on.

What I found: if my styled CSS contains comments in the form of // foo bar now I can't complile my app.

The errors is something like this:

ERROR in ./components/mycomponent.js
Module build failed (from ../node_modules/babel-loader/lib/index.js):
Error: ..../xxx.js.js: There was a problem adding namespaces to this CSS in the file .../xxx.js. Error: <css input>:7:3: Unknown word
 CSS:

If I go at line 7 of the CSS string I find a duble-slash.

I don't find any official reference, but I read that both of those kind of comments are legit:

  // This is a comment
  /* this is also a comment */

Unluckily now I have to convert my // to /* */.

rawCssNamespace will add suffix and not prefix when there is no nested class in css

Hey!

When you have component like this:

const Button = styled.button`
  background: green;
  color: red;
  padding: 1em;
`;

and .babelrc like:

["@quickbaseoss/babel-plugin-styled-components-css-namespace", {
  "rawCssNamespace": ["#prefix"]
}]

The generated selector is wrong:

<style data-styled="" data-styled-version="4.1.3">
/* sc-component-id: sc-bdVaJa */
.gBOsWq #prefix{background:green;color:red;padding:1em;}</style>

The correct should be

<style data-styled="" data-styled-version="4.1.3">
/* sc-component-id: sc-bdVaJa */
#prefix .gBOsWq {background:green;color:red;padding:1em;}</style>

Using the cssNamespace seems to work, but I need to prefix the selectors with id rather than class.

Note
If I change

const Button = styled.button`
  background: green;
  color: red;
  padding: 1em;
`;

to

const Button = styled.button`
  .foo {
    background: green;
    color: red;
    padding: 1em;
  }
`;

It works.

Is this a desired behaviour?

Unable to make it work at all

The component:

import styled from "styled-components/macro";
import { Segment } from "semantic-ui-react";

import semanticStyles from "../../../semantic/exports.module.less";

export const BlueSegment = styled(Segment)`
  background-color: ${semanticStyles.mediumBlue} !important;
  inverted: true;
`;

The config:

rule.options.plugins.push([
            "@quickbaseoss/babel-plugin-styled-components-css-namespace",
            {
                "cssNamespace": "#root"
            }
        ]);
        rule.options.plugins.push("babel-plugin-styled-components");

Outputs:

<div class="ui blue inverted center aligned segment PortalStatsMainStyles__BlueSegment-ws1dxq-0 iaCJEB">

.iaCJEB {
    background-color: #026fad !important;
    inverted: true;
}

So I cant override semantic-ui styles :(

The development server NOT Starting

Hi!
I use CRA and the development server NOT starting (without errors, only "Starting the development server..." in console displayed).

package.json:
"@quickbaseoss/babel-plugin-styled-components-css-namespace": "^1.0.0-rc4"
"react-app-rewired": "^2.1.5",
"customize-cra": "^0.9.1",
"react-scripts": "3.4.1"

But, if I change "react-scripts" to "3.2.0" - all work fine.

Add better semver management

Right now we have a very manual semver documentation and management system. If this plugin has many more additional fixes, we may want to investigate a better system. If anyone has suggestions, please comment or open a PR!

Upgrade to Babel 7

Hi all!

Babel has updated to v7 and it would be great to update this package to follow suite with upgrading its dependencies.

add className to current element, not as parent selector

Hi

I was wondering it possible to add the className as an additional class of the current element, and not as a parent selector ?

Requested:
"babel": { "plugins": [ ["@quickbaseoss/babel-plugin-styled-components-css-namespace", {"cssNamespace": "&.specific"}], "styled-components" ] }

// output:
.specific.c0 { background-color: blue; }

In order to add the same custom class on all styled components, so we can, for example use:
:not[class*='specific']
on existing legacy css selectors

Support for style objects

Are style objects supported? They don't seem to work for me, and I can't find any examples in the issues or in the tests. I'm running the plugin using inside create-react-app using customize-cra, but I believe I have it (mostly) configured properly because when I change things into template literals, the namespace does get added correctly (both using styled and the css prop).

Issue with nested pseudo-selectors in expressions

I posted #50 to handle the shuffling of expressions that happens when the CSS is run through postcss and the CSS contains nested pseudo-selectors e.g. &:hover, &:active etc.

That PR fixes one class of problems, but we've found another related problem that occurs when we include these sorts of pseudo-selectors inside the template expressions.

Example:

Here's the original styled component:

export default styled.div`
  background: ${props => props.background};
  border: 1px solid ${props => props.borderColor};
  cursor: text;

  &:hover {
    border-color: ${props => props.hoverBorder};
  }

  &:active {
    border-color: ${props => props.activeBorder};
  }

  ${props =>
    props.disabled &&
    css`
      border-color: ${props.disabledBorder};
      cursor: not-allowed;

      &:active,
      &:hover {
        border-color: ${props.disabledBorder};
      }

      * {
        cursor: not-allowed;
      }
    `
  };
`;

And here it is after processing with this plugin using cssNamespace: '.class-wrapper .other-wrapper':

export default styled.div`
.class-wrapper .other-wrapper & {
  background: ${props => props.background};
  border: 1px solid ${props => props.borderColor};
  cursor: text;

  ${props => 
    props.disabled &&
    css`
      border-color: ${props.disabledBorder};
      cursor: not-allowed;

      &:active,
      &:hover {
        border-color: ${props.disabledBorder};
      }

      * {
        cursor: not-allowed;
      }
    `
  };
}

.class-wrapper .other-wrapper &:hover {
  border-color: ${props => props.hoverBorder};
}

.class-wrapper .other-wrapper &:active {
  border-color: ${props => props.activeBorder};
}
`;

When styled-components renders this into the page and the component has the disabled prop set, the resulting CSS will look like this:

.class-wrapper .other-wrapper .AAAAAA {
  background: #bgcolor;
  border: 1px solid #borderColor;
  cursor: text;

  border-color: #disabledBorder;
  cursor: not-allowed;
}

.class-wrapper .other-wrapper .AAAAAA:active,
.class-wrapper .other-wrapper .AAAAAA:hover {
  border-color: #disabledBorder;
}

.class-wrapper .other-wrapper .AAAAAA * {
  cursor: not-allowed;
}

.class-wrapper .other-wrapper .AAAAAA:hover {
  border-color: #hoverBorder;
}

.class-wrapper .other-wrapper .AAAAAA:active {
  border-color: #activeBorder;
}

So, the problem is that this places the original (non-disabled) &:hover and &:active below the overrides that are intended to apply when the component gets the disabled prop. Therefore the "disabled" overrides don't actually override the base styles, but rather they themselves get overridden by the base styles, since CSS uses code-order to determine precedence.

The reason: this plugin "unwraps" the source styles, which pulls the &:hover and &:active that are not in expressions below the main style block. But the &:hover and &:active that are in expressions don't get "unwrapped" until styled-components generates the final CSS, based on evaluating those expressions. At that time, the expression versions get placed just below the main style block, before the "main" versions that were pulled out by the plugin.

Hopefully this makes sense.

My question:

It seems to me that the inclusion of the postcss-nested PostCSS processor is only to accommodate the postcss-parent-selector, which will generate invalid results if provided nested CSS. I wonder though if, instead of using postcss-parent-selector, instead a simplified version of that processor could be used, which only modifies the root element of the CSS it receives? Is there any reason for postcss-nested other than to make postcss-parent-selector happy? (*see below)

Such a simplified processor might look like this:

import postcss from 'postcss';

export default postcss.plugin('add-parent-selector', (opts = {}) => (root) => {
  root.walkRules((rule) => {
    if (rule.parent && rule.parent.type === 'root') {
      rule.selectors = rule.selectors.map((selectors) =>
        selectors.split(/,[\s]* /g).map((selector) => {
          // don't add the parent class to a rule that is
          // exactly equal to the one defined by the user
          if (selector === opts.selector) {
            return selector;
          }
          return `${opts.selector} ${selector}`;
        }),
      );
    }
  });
});

But I'm not sure if there are other reasons to include the postcss-nested processor that I am not seeing. Any thoughts?

I'd be happy to post this proposal as a PR but don't want to do so if it's going to break other things.


*Without unnesting, the parent-selector processor would produce something like...

export default styled.div`
.class-wrapper .other-wrapper & {
  background: ${props => props.background};
  ... 

  .class-wrapper .other-wrapper &:hover {
    border-color: ${props => props.hoverBorder};
  }

  .class-wrapper .other-wrapper &:active {
    border-color: ${props => props.activeBorder};
  }
  ...
}

`;

...i.e. generating final selectors like .class-wrapper .other-wrapper .xxxxxx .class-wrapper .other-wrapper .xxxxx:hover { ... }. Not good.

Unknown word

Having an issue since upgrading to the new version. This plugin is failing with the following message:

There was a problem adding namespaces to this CSS. Error: <css input>:5:5: Unknown word
 CSS: 
  && {
    fake-element-placeholder
    fake-element-placeholder
    transition: ease-in-out 50ms;

    fake-element-placeholder
    &:hover {
      transition: ease-in-out 100ms;
    }
  }

It's failing with the repo here: https://github.com/zachhardesty7/semantic-styled-ui
I'm currently working on reducing the factors that could cause this and getting a minimal reproducible test case going but as of now, it should be reproducible with the above files!

Nothing transformed when using cssNamespace option

Thank for the plugin;

Problem: no styled-component transformed when using cssNamespace option, work fine if not add cssNamespace option.

My project are using create-react-app, and install webpack to build a js file. it doesn't eject the create-react-app. Also the project use styled-component v3.

Also the compiler just hand if I add rawCssNamespace option

My .babelrc

{
  "presets": ["@babel/env", "@babel/react"],
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    [
      "@quickbaseoss/babel-plugin-styled-components-css-namespace",
      {
        "cssNamespace": ["moreSpecific", "reallySpecific", "extraSpecific"]
      }
    ],
    "babel-plugin-styled-components",
    ["@babel/plugin-transform-runtime", { "regenerator": true }]
  ]
}

My webpack.config.js

const webpack = require('webpack');
const path = require('path');

module.exports = {
  entry: './src/build.jsx',
  mode: 'production',
  resolve: {
    extensions: ['.js', '.jsx'],
  },
  output: {
    filename: 'aaa.js',
    libraryExport: 'default',
    libraryTarget: 'var',
    library: 'bbb',
    path: path.resolve(__dirname, './dist/lib'),
  },
  node: {
    fs: 'empty',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.browser': 'true',
    }),
  ],
};

My package.json

{
  "name": "",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@babel/plugin-proposal-class-properties": "^7.1.0",
    "@babel/preset-react": "^7.0.0",
    "@quickbaseoss/babel-plugin-styled-components-css-namespace": "^0.1.1",
    "nprogress": "^0.2.0",
    "prop-types": "^15.6.2",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "react-scripts": "2.1.1",
    "react-select": "^2.1.2",
    "react-toastify": "^4.5.1",
    "shortid": "^2.2.14",
    "styled-components": "^3.1.6",
    "webpack": "4.19.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "build:webpack": "webpack --config webpack.config.js"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "devDependencies": {
    "babel-loader": "^8.0.4",
    "babel-plugin-styled-components": "^1.10.0",
    "babel-plugin-transform-runtime": "^6.23.0",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-loader": "^2.1.1",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-jsx-a11y": "^6.1.2",
    "eslint-plugin-react": "^7.11.1",
    "webpack-cli": "^3.1.2"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "author": "",
  "license": "ISC",
  "description": "",
  "proxy": "http://localhost:8888",
  "main": "index.js"
}

rawCssNamespace does not resolve the content as sass

The new strategy for namespacing adds the wrapper as sass notation. I have only released now that styled components are not really sass.

Given rawCssNamespace: ['body .theme-light', '.theme-dark'] and styles:

styled.div`
  display: block;
  min-width: 200px;

  &.myClass {
    /* some css */
  }
`

When the plugin namespace styles
Then it should not add namespace as wrapper

Current behaviour:

styled.div`
  body .theme-light, .theme-dark {
    & {
      display: block;
      min-width: 200px;

      &.myClass {
        /* some css */
      }
    }
  }
`

Expected behaviour:
Current behaviour:

styled.div`
  body .theme-light &, .theme-dark & {
    display: block;
    min-width: 200px;
  }
  body .theme-light &.myClass, .theme-dark &.myClass  {
    /* some css */
  }
`

I will have a look at this weekend. I see to possible solutions:

  • Introduce sass to parse it (which I like more);
  • Create a module to analyse styles extracting the raw css as self and the rules scoped in its own module;

@nvanselow Sorry for that, it was good releasing as an alternative strategy. Let me know which solution you are up to, also, if you have a different solution. ;)

Thank you

babel config problem

I guess this is a bit off topic but maybe someone can help.

The plugin works nicely when I use it in a fresh "create-react-app" setup. Really cool !

Now I want to create a bundle of my project to be used in another project by using the "microbundle" bundler.
I tried different Babel configs ".babelrc" and "babel.config.js" - but the css prefixes are not applied. Not sure if the plugin is even called. Maybe I should try another bundler?

Thanks,
Oliver

Potential Babel 7 Problem

Hello!

That you for writing this awesome plugin! It's exactly what my team is looking for.

On adding it to my babel config I've received the following error. My guess is this is due to me using babel 7 in conjunction with webpack 4.

ERROR in ./src/index.js
Module build failed: TypeError: Cannot read property 'imports' of undefined
    at importLocalName (/Users/danielkezerashvili/code/forms/node_modules/@quickbaseoss/babel-plugin-styled-components-css-namespace/node_modules/babel-plugin-styled-components/lib/utils/detectors.js:15:45)
    at isCSSHelper (/Users/danielkezerashvili/code/forms/node_modules/@quickbaseoss/babel-plugin-styled-components-css-namespace/node_modules/babel-plugin-styled-components/lib/utils/detectors.js:41:46)
    at isHelper (/Users/danielkezerashvili/code/forms/node_modules/@quickbaseoss/babel-plugin-styled-components-css-namespace/node_modules/babel-plugin-styled-components/lib/utils/detectors.js:53:10)
    at exports.default (/Users/danielkezerashvili/code/forms/node_modules/@quickbaseoss/babel-plugin-styled-components-css-namespace/lib/visitors/cssNamespace.js:34:82)
    at PluginPass.TaggedTemplateExpression (/Users/danielkezerashvili/code/forms/node_modules/@quickbaseoss/babel-plugin-styled-components-css-namespace/lib/index.js:13:36)
    at newFn (/Users/danielkezerashvili/code/forms/node_modules/@babel/traverse/lib/visitors.js:223:21)
    at NodePath._call (/Users/danielkezerashvili/code/forms/node_modules/@babel/traverse/lib/path/context.js:64:19)
    at NodePath.call (/Users/danielkezerashvili/code/forms/node_modules/@babel/traverse/lib/path/context.js:38:17)
    at NodePath.visit (/Users/danielkezerashvili/code/forms/node_modules/@babel/traverse/lib/path/context.js:99:12)
    at TraversalContext.visitQueue (/Users/danielkezerashvili/code/forms/node_modules/@babel/traverse/lib/context.js:135:18)
 @ multi (webpack)-dev-server/client?http://0.0.0.0:3000 ./src

my babel config:

"babel": {
    "presets": [
      [
        "@babel/preset-env",
        {
          "shippedProposals": true,
          "targets": {
            "browsers": [
              "last 2 versions"
            ]
          }
        }
      ],
      "@babel/preset-react"
    ],
    "plugins": [
      "@quickbaseoss/babel-plugin-styled-components-css-namespace",
      "lodash",
      "transform-class-properties",
      [
        "styled-components",
        {
          "displayName": true
        }
      ]
    ]
  }

EDIT: The issue is shared with this issue styled-components/babel-plugin-styled-components#96

Plugin Not Working with Different Styled Component Syntax

Hi, I've got an issue with some components in a component library. The class names don't get doubled by this plugin when using the following Styled Components syntax:

Doesn't work

const ArrowButton = styled.button<ArrowButtonProps>(({ disabled = false }) => [
  tw`text-white`,
  disabled ? tw`bg-gray-50` : tw`hover:bg-secondary-700`
]);

Example output: .c0

Works

const PageCount = styled.div`
  ${tw`inline-flex justify-center items-center`};
`;

Example output: .c1.c1

Any ideas? Thank you!

Nothing transformed (usage with webpack and typescript)

I tried to use the plugin together with webpack (babel-loader) and typescript, but wasn't successful.

With the following module.rules part of my webpack.config.js I receive no error but the plugin shows no effect, i.e. the CSS of styled components is not transformed at all:

        test: /\.tsx?$/,
        exclude: path.resolve(__dirname, '../node_modules'),
        loader: 'babel-loader',
        options: {
            plugins: ['@quickbaseoss/babel-plugin-styled-components-css-namespace']
        }

When adding { cssNamespace: 'moreSpecific' }, that is:

        test: /\.tsx?$/,
        exclude: path.resolve(__dirname, '../node_modules'),
        loader: 'babel-loader',
        options: {
            plugins: [
                '@quickbaseoss/babel-plugin-styled-components-css-namespace',
                { cssNamespace: 'moreSpecific' }
            ]
        }

...I get the following error:

Module build failed: Error: Plugin 1 specified in "base" provided an invalid property of "cssNamespace"

Any ideas?

Versions of tools:

typescript: ^3.0.1
webpack: ^2.3.3
babel-loader: ^7.1.5
babel-plugin-styled-components-css-namespace: ^0.1.1

Duplicating ClassName Multiple Times

Hey man! This has been a super useful plugin for working with styled-components and 3rd party libraries but sometimes it would be super helpful to allow the className to be duplicated more than once. I tried running the plugin in Babel twice but that didn't work. Any thoughts?

Upgrading styled-components from 5.1.1 to 5.3.5 has broken the plugin

Environment

In the process of upgrading React to v18 we found that styled-components was throwing an error about breaking the rule of hooks. Upgrading styled-components to the latest version it appears that the babel-plugin-styled-components-css-namespace no longer works correctly.

Steps to reproduce

Given the babel config

['@quickbaseoss/babel-plugin-styled-components-css-namespace', { cssNamespace: '.ssa-app' }],

and the code

  const StyledIcon = styled(IcomoonReact)`
    transform: ${(props) => (props.$flipx ? `scaleX(-1)` : 'none')};`
  `
  
  <StyledIcon $flipx={true}   />
  <StyledIcon $flipx={false}   />

Expected Behavior

On version 5.1.1 the above would produce 2 styles and correctly assign the classnames to the elements in the DOM. (.ssa-app is the css prefix defined in babel-plugin-styled-components-css-namespace)

.ssa-app .lnugha {
    transform: none;
}

.ssa-app .hHOYwd {
    transform: scaleX(-1);
}

Actual Behavior

Since updating to 5.3.5 the CSS is as follows and both elements have the same class of sc-bczRLJ and thus both look the same (flipped).

.ssa-app .sc-bczRLJ {
    transform: scaleX(-1);
}

.ssa-app .sc-bczRLJ {
    transform: none;
}
.ssa-app .sc-bczRLJ {
    transform: none;
}

I'm completely stuck as to how to achieve the global css namespace in 5.3.5.

Conditional style is overwritten in loop when using cssNamespace

Hi,
I have a namespace #my-widget.

Components looks schematically like this

const PolarityCell = styled.td`
   color: ${({isNegative}) => isNegative ? 'red': 'green'};
`

<div id="my-widget">
    <table>
        {entries.map(({value, isNegative}) => (
            <tr>
                <td><PolarityCell isNegative={isNegative}>{value}</PolarityCell></td>
            </tr>
         )}
    </table>
</div>
}

When entries: [{value: '1', isNegative: false}, {value: '-2', isNegative: true}] all values are red

When entries: [{value: '-1', isNegative: true}, {value: '2', isNegative: false}] all values are green

Extra selectors added on `css` properties

Example:

const foo = css` 
width: 0px;
`;

const bar = styled`
color: green;
${foo}
`

Results in two classes:

.asdas.asdas.asdas.asdas {
width: 0px;
}
.asdas.asdas {
color: green;
}

expected behavior:

.asdas.asdas {
width: 0px;
color: green;
}

Note, that further nesting will add even more selectors.

Plugin doesn't work with typescript

Hello,

I have one Javascript project and one Typescript project, both with the plugin configured. In the Javascript project this work fine, but with Typescript doesn't work.

My question: This plugin is compatible with Typescript?

package.json:


{
  "name": "react-typescript-starter",
  "description": "Clean React + TypeScript starter, without usage of create-react-app โš›",
  "version": "1.0.0",
  "main": "src/index.tsx",
  "repository": "https://github.com/GR34SE/react-typescript-starter.git",
  "license": "MIT",
  "private": false,
  "scripts": {
    "dev": "webpack-dev-server --mode development --env.development",
    "build": "webpack --mode production --env.production --progress",
    "lint": "eslint './src/**/*.{ts,tsx}'",
    "lint:fix": "eslint './src/**/*.{ts,tsx}' --fix"
  },
  "devDependencies": {
    "@types/node": "13.13.33",
    "@types/react": "16.14.2",
    "@types/react-dom": "16.9.10",
    "@types/styled-components": "^5.1.4",
    "@types/webpack": "4.41.25",
    "@types/webpack-dev-server": "3.11.1",
    "@typescript-eslint/eslint-plugin": "4.8.2",
    "@typescript-eslint/parser": "4.8.2",
    "eslint": "7.14.0",
    "eslint-config-prettier": "6.15.0",
    "eslint-plugin-import": "2.22.1",
    "eslint-plugin-prettier": "3.1.4",
    "eslint-plugin-react": "7.21.5",
    "eslint-plugin-react-hooks": "4.2.0",
    "fork-ts-checker-webpack-plugin": "5.2.1",
    "html-webpack-plugin": "4.5.0",
    "prettier": "2.2.0",
    "ts-loader": "8.0.11",
    "ts-node": "9.0.0",
    "tsconfig-paths-webpack-plugin": "3.3.0",
    "typescript": "4.1.2",
    "webpack": "4.44.2",
    "webpack-cli": "3.3.12",
    "webpack-dev-server": "3.11.0"
  },
  "dependencies": {
    "@babel/cli": "^7.12.8",
    "@babel/core": "^7.12.9",
    "@babel/preset-env": "^7.12.7",
    "@babel/preset-react": "^7.12.7",
    "@quickbaseoss/babel-plugin-styled-components-css-namespace": "^1.0.1",
    "babel-loader": "^8.2.1",
    "babel-plugin-styled-components": "^1.12.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "styled-components": "^5.2.1"
  }
}

webpack.config.ts

import path from "path";
import webpack, {Configuration} from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import {TsconfigPathsPlugin} from "tsconfig-paths-webpack-plugin";

const webpackConfig = (env): Configuration => ({
    entry: "./src/index.tsx",
    ...(env.production || !env.development ? {} : {devtool: "eval-source-map"}),
    resolve: {
        extensions: [".ts", ".tsx", ".js"],
        plugins: [new TsconfigPathsPlugin()]
    },
    output: {
        path: path.join(__dirname, "/dist"),
        filename: "build.js"
    },
    module: {
        rules: [
            {
                test: /\.ts$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    plugins: [
                        [
                            "@quickbaseoss/babel-plugin-styled-components-css-namespace",
                            {"cssNamespace": ".my-namespace"}
                        ],
                        "styled-components"
                      ]
                }
            },
            {
                test: /\.tsx?$/,
                loader: "ts-loader",
                options: {
                    transpileOnly: true
                },
                exclude: /dist/
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html"
        }),
        new webpack.DefinePlugin({
            "process.env.PRODUCTION": env.production || !env.development,
            "process.env.NAME": JSON.stringify(require("./package.json").name),
            "process.env.VERSION": JSON.stringify(require("./package.json").version)
        }),
        new ForkTsCheckerWebpackPlugin({
            eslint: {
                files: "./src/**/*.{ts,tsx,js,jsx}" // required - same as command `eslint ./src/**/*.{ts,tsx,js,jsx} --ext .ts,.tsx,.js,.jsx`
            }
        })
    ]
});

export default webpackConfig;

index.tsx

<div className="my-namespace">
        <h1>Hello World</h1>

        <hr />

        <h3>Environmental variables:</h3>
        <Text>
            process.env.PRODUCTION: <b>{process.env.PRODUCTION.toString()}</b>
        </Text>
        <Text>
            process.env.NAME: <b>{process.env.NAME}</b>
        </Text>
        <Text>
            process.env.VERSION: <b>{process.env.VERSION}</b>
        </Text>
    </div>

Support for styled-components keyframes

Originally reported by @genedwards, moved from other repo.

Issue: the styled-components module exports a keyframe function. https://www.styled-components.com/docs/basics#animations

Example usage:

const rotate360 = keyframes`
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
`;

const Rotate = styled.div`
  animation: ${rotate360} 2s linear infinite;
`;

The generated CSS from the above example looks like the following:

@-webkit-keyframeskrrMtA{
  .<cssNamespace> from{
    -webkit-transform:rotate(0deg);
    -ms-transform:rotate(0deg);
    transform:rotate(0deg);
  }
  .<cssNamespace> to{
    -webkit-transform:rotate(360deg);
    -ms-transform:rotate(360deg);
    transform:rotate(360deg);
  }
}
@keyframes krrMtA{
  .<cssNamespace> from{
    -webkit-transform:rotate(0deg);
    -ms-transform:rotate(0deg);
    transform:rotate(0deg);
  }
  .<cssNamespace> to{
    -webkit-transform:rotate(360deg);
    -ms-transform:rotate(360deg);
    transform:rotate(360deg);
  }
}

Update on progress

January is going to be the month of closing out some issues in this project. Unfortunately, I was unable to dedicate enough time to improvements here. Thank you to everyone who has reported issues. Please continue to report them or open PRs with fixes. My goal is to better be aware of issues coming into the project and responding more quickly going forward.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.