summaryrefslogtreecommitdiff
path: root/@linaria/packages/interop
diff options
context:
space:
mode:
Diffstat (limited to '@linaria/packages/interop')
-rw-r--r--@linaria/packages/interop/CHANGELOG.md19
-rw-r--r--@linaria/packages/interop/README.md45
-rw-r--r--@linaria/packages/interop/__tests__/__snapshots__/index.test.js.snap73
-rw-r--r--@linaria/packages/interop/__tests__/index.test.js117
-rw-r--r--@linaria/packages/interop/index.js54
-rw-r--r--@linaria/packages/interop/package.json22
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"
+ }
+}