diff options
Diffstat (limited to '@linaria/packages/interop')
-rw-r--r-- | @linaria/packages/interop/CHANGELOG.md | 19 | ||||
-rw-r--r-- | @linaria/packages/interop/README.md | 45 | ||||
-rw-r--r-- | @linaria/packages/interop/__tests__/__snapshots__/index.test.js.snap | 73 | ||||
-rw-r--r-- | @linaria/packages/interop/__tests__/index.test.js | 117 | ||||
-rw-r--r-- | @linaria/packages/interop/index.js | 54 | ||||
-rw-r--r-- | @linaria/packages/interop/package.json | 22 |
6 files changed, 330 insertions, 0 deletions
diff --git a/@linaria/packages/interop/CHANGELOG.md b/@linaria/packages/interop/CHANGELOG.md new file mode 100644 index 0000000..99b4976 --- /dev/null +++ b/@linaria/packages/interop/CHANGELOG.md @@ -0,0 +1,19 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +# [3.0.0-beta.7](https://github.com/callstack/linaria/tree/master/packages/interop/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2021-06-24) + +**Note:** Version bump only for package @linaria/babel-plugin-interop + + + + + +# [3.0.0-beta.6](https://github.com/callstack/linaria/tree/master/packages/interop/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2021-06-06) + + +### Features + +* **interop:** interop between Linaria and traditional CSS-in-JS libraries ([#776](https://github.com/callstack/linaria/tree/master/packages/interop/issues/776)) ([0a5f5b4](https://github.com/callstack/linaria/tree/master/packages/interop/commit/0a5f5b440506bfa24724d4a91e519c48d6f6c69b)) diff --git a/@linaria/packages/interop/README.md b/@linaria/packages/interop/README.md new file mode 100644 index 0000000..c10fc6e --- /dev/null +++ b/@linaria/packages/interop/README.md @@ -0,0 +1,45 @@ +<p align="center"> + <img alt="Linaria" src="https://raw.githubusercontent.com/callstack/linaria/HEAD/website/assets/linaria-logo@2x.png" width="496"> +</p> + +<p align="center"> +Zero-runtime CSS in JS library. +</p> + +--- + +# `@linaria/babel-plugin-interop` + +This plugin allows to interpolate Linaria components inside styled-components and Emotion: +```javascript +import styled from 'styled-components'; +import { Title } from './Title.styled'; // Linaria component + +const Article = () => { /* … */ }; + +export default styled(Article)` + & > ${Title} { + color: green; + } +`; + +``` + +## Quick start + +Install the plugin first: + +``` +npm install --save-dev @linaria/babel-plugin-interop +``` + +Then add `@linaria/interop` to your babel configuration *before* `styled-components`: + +```JSON +{ + "plugins": [ + ["@linaria/interop", { "library": "styled-components" }], + "styled-components" + ] +} +``` diff --git a/@linaria/packages/interop/__tests__/__snapshots__/index.test.js.snap b/@linaria/packages/interop/__tests__/__snapshots__/index.test.js.snap new file mode 100644 index 0000000..52a322f --- /dev/null +++ b/@linaria/packages/interop/__tests__/__snapshots__/index.test.js.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`styled-components css 1`] = ` +"import { css } from \\"styled-components\\"; +import Title from \\"./Title\\"; +export default css\` + & > \${(i => i && i.__linaria ? '.' + i.__linaria.className : i)(Title)} { + color: red; + } +\`;" +`; + +exports[`styled-components keeps linaria 1`] = ` +"import styled from \\"linaria/react\\"; +import Title from \\"./Title\\"; +export default styled.h1\` + & > \${Title} { + color: red; + } +\`;" +`; + +exports[`styled-components member expression as selector 1`] = ` +"import styled from \\"styled-components\\"; +import Title from \\"./Title\\"; +export default styled.h1\` + & > \${(i => i && i.__linaria ? '.' + i.__linaria.className : i)(Title.Small)} { + color: red; + } +\`;" +`; + +exports[`styled-components styled(Cmp) 1`] = ` +"import styled from \\"styled-components\\"; +import Cmp from \\"./Cmp\\"; +import Title from \\"./Title\\"; +export default styled(Cmp)\` + & > \${(i => i && i.__linaria ? '.' + i.__linaria.className : i)(Title)} { + color: red; + } +\`;" +`; + +exports[`styled-components styled(Cmp).attrs({}) 1`] = ` +"import styled from \\"styled-components\\"; +import Cmp from \\"./Cmp\\"; +import Title from \\"./Title\\"; +export default styled(Cmp).attrs(() => ({}))\` + & > \${(i => i && i.__linaria ? '.' + i.__linaria.className : i)(Title)} { + color: red; + } +\`;" +`; + +exports[`styled-components styled.h1 1`] = ` +"import styled from \\"styled-components\\"; +import Title from \\"./Title\\"; +export default styled.h1\` + & > \${(i => i && i.__linaria ? '.' + i.__linaria.className : i)(Title)} { + color: red; + } +\`;" +`; + +exports[`styled-components styled.h1.attrs({}) 1`] = ` +"import styled from \\"styled-components\\"; +import Title from \\"./Title\\"; +export default styled.h1.attrs(() => ({}))\` + & > \${(i => i && i.__linaria ? '.' + i.__linaria.className : i)(Title)} { + color: red; + } +\`;" +`; diff --git a/@linaria/packages/interop/__tests__/index.test.js b/@linaria/packages/interop/__tests__/index.test.js new file mode 100644 index 0000000..d6e6d86 --- /dev/null +++ b/@linaria/packages/interop/__tests__/index.test.js @@ -0,0 +1,117 @@ +const babel = require('@babel/core'); +const dedent = require('dedent'); +const plugin = require('../'); + +const getCode = (src) => { + const { code } = babel.transform(dedent(src), { plugins: [plugin] }); + return code; +}; + +describe('styled-components', function () { + it('keeps linaria', () => { + const code = getCode(` + import styled from "linaria/react"; + import Title from "./Title"; + + export default styled.h1\` + & > ${'${Title}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); + + it('css', () => { + const code = getCode(` + import { css } from "styled-components"; + import Title from "./Title"; + + export default css\` + & > ${'${Title}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); + + it('styled.h1', () => { + const code = getCode(` + import styled from "styled-components"; + import Title from "./Title"; + + export default styled.h1\` + & > ${'${Title}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); + + it('member expression as selector', () => { + const code = getCode(` + import styled from "styled-components"; + import Title from "./Title"; + + export default styled.h1\` + & > ${'${Title.Small}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); + + it('styled(Cmp)', () => { + const code = getCode(` + import styled from "styled-components"; + import Cmp from "./Cmp"; + import Title from "./Title"; + + export default styled(Cmp)\` + & > ${'${Title}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); + + it('styled(Cmp).attrs({})', () => { + const code = getCode(` + import styled from "styled-components"; + import Cmp from "./Cmp"; + import Title from "./Title"; + + export default styled(Cmp).attrs(() => ({}))\` + & > ${'${Title}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); + + it('styled.h1.attrs({})', () => { + const code = getCode(` + import styled from "styled-components"; + import Title from "./Title"; + + export default styled.h1.attrs(() => ({}))\` + & > ${'${Title}'} { + color: red; + } + \`; + `); + + expect(code).toMatchSnapshot(); + }); +}); diff --git a/@linaria/packages/interop/index.js b/@linaria/packages/interop/index.js new file mode 100644 index 0000000..35eff7e --- /dev/null +++ b/@linaria/packages/interop/index.js @@ -0,0 +1,54 @@ +module.exports = function ({ types: t }, config = {}) { + const library = config.library || 'styled-components'; + const isLibrary = + library instanceof RegExp ? (s) => library.test(s) : (s) => s === library; + const fixer = { + 'MemberExpression|Identifier': (path) => { + if (!t.isTemplateLiteral(path.parent) || path.listKey !== 'expressions') { + return; + } + + const original = path.node; + path.replaceWithSourceString( + `(i => i && i.__linaria ? '.' + i.__linaria.className : i)('placeholder')` + ); + path.get('arguments.0').replaceWith(original); + }, + }; + + return { + visitor: { + TaggedTemplateExpression(path) { + const tag = path.get('tag'); + let identifier = null; + if (t.isIdentifier(tag)) { + identifier = tag; + } else if (t.isMemberExpression(tag)) { + identifier = tag.get('object'); + } else if (t.isCallExpression(tag)) { + identifier = tag.get('callee'); + } + + if (t.isMemberExpression(identifier)) { + // it's something like styled().attrs() + if (t.isCallExpression(identifier.node.object)) { + identifier = identifier.get('object.callee'); + } else if (t.isMemberExpression(identifier.node.object)) { + identifier = identifier.get('object.object'); + } + } + + const scope = identifier.scope; + const binding = scope.getBinding(identifier.node.name); + if (!t.isImportDeclaration(binding.path.parent)) { + return; + } + + const importSource = binding.path.parent.source.value; + if (isLibrary(importSource)) { + path.get('quasi').traverse(fixer); + } + }, + }, + }; +}; diff --git a/@linaria/packages/interop/package.json b/@linaria/packages/interop/package.json new file mode 100644 index 0000000..dabcfef --- /dev/null +++ b/@linaria/packages/interop/package.json @@ -0,0 +1,22 @@ +{ + "name": "@linaria/babel-plugin-interop", + "version": "3.0.0-beta.7", + "publishConfig": { + "access": "public" + }, + "main": "index.js", + "repository": "https://github.com/callstack/linaria/tree/master/packages/interop", + "homepage": "https://github.com/callstack/linaria/tree/master/packages/interop#readme", + "author": { + "name": "Anton Evzhakov", + "email": "anton@evz.name" + }, + "scripts": { + "test": "jest --config ../../jest.config.js --rootDir ." + }, + "license": "MIT", + "devDependencies": { + "@babel/core": ">=7", + "dedent": "^0.7.0" + } +} |