diff --git a/examples/with-tailwindcss-emotion/.babelrc b/examples/with-tailwindcss-emotion/.babelrc new file mode 100644 index 0000000000000..fe1be8b87d7e9 --- /dev/null +++ b/examples/with-tailwindcss-emotion/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["next/babel"], + "plugins": [["emotion"], ["macros"]] +} diff --git a/examples/with-tailwindcss-emotion/README.md b/examples/with-tailwindcss-emotion/README.md new file mode 100644 index 0000000000000..81d2f46ec823b --- /dev/null +++ b/examples/with-tailwindcss-emotion/README.md @@ -0,0 +1,65 @@ +# Tailwind CSS with Emotion.js example + +This is an example of how you can add the tailwind CSS with Emotion.js in your web app. + +## How to use + +### Using `create-next-app` + +Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) or [npx](https://github.com/zkat/npx#readme) to bootstrap the example: + +```bash +npx create-next-app --example with-tailwindcss-emotion with-tailwindcss-emotion-app +# or +yarn create next-app --example with-tailwindcss-emotion with-tailwindcss-emotion-app +``` + +### Download manually + +Download the example: + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-tailwindcss-emotion +cd with-tailwindcss-emotion +``` + +Install it and run: + +```bash +npm install +npm run dev +# or +yarn +yarn dev +``` + +Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download)): + +```bash +now +``` + +## The idea behind the example + +This setup has inspiration from [examples/with-tailwindcss](https://github.com/zeit/next.js/blob/canary/examples/with-tailwindcss/README.md). This example will show you how to integrate [Emotion](https://emotion.sh/docs/introduction) with [tailwind](https://tailwindcss.com/). + +`tailwindcss.macros` is used to add tailwind classes inside Emotion by injecting the tailwind CSS into the styled component. No need to use CSS files, autoprefix, minifier, etc. You will get the full benefits of Emotion. + +The CSS classes generated by Emotion will include the tailwind styles but not the name of the classes. For example the following component: + +```jsx +const Header = styled.div` + ${tw`font-mono text-sm text-gray-800`} +` +``` + +Will be transformed into: + +```css +.css-25og8s-Header { + font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', + monospace; + font-size: 0.875rem; + color: #2d3748; +} +``` diff --git a/examples/with-tailwindcss-emotion/babel-plugin-macros.config.js b/examples/with-tailwindcss-emotion/babel-plugin-macros.config.js new file mode 100644 index 0000000000000..7d38fabe9d776 --- /dev/null +++ b/examples/with-tailwindcss-emotion/babel-plugin-macros.config.js @@ -0,0 +1,5 @@ +module.exports = { + tailwind: { + styled: '@emotion/styled' + } +} diff --git a/examples/with-tailwindcss-emotion/next.config.js b/examples/with-tailwindcss-emotion/next.config.js new file mode 100644 index 0000000000000..37dba1c72a9ac --- /dev/null +++ b/examples/with-tailwindcss-emotion/next.config.js @@ -0,0 +1,10 @@ +module.exports = { + webpack: (config, options) => { + // Fixes npm packages that depend on `fs` module + config.node = { + fs: 'empty' + } + + return config + } +} diff --git a/examples/with-tailwindcss-emotion/package.json b/examples/with-tailwindcss-emotion/package.json new file mode 100644 index 0000000000000..3cec1eaa08b39 --- /dev/null +++ b/examples/with-tailwindcss-emotion/package.json @@ -0,0 +1,23 @@ +{ + "name": "with-tailwindcss-emotion", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "@emotion/core": "10.0.17", + "@emotion/styled": "10.0.17", + "next": "latest", + "react": "16.10.1", + "react-dom": "16.10.1" + }, + "devDependencies": { + "babel-plugin-emotion": "10.0.19", + "babel-plugin-macros": "2.6.1", + "tailwind.macro": "1.0.0-alpha.10", + "tailwindcss": "1.1.2" + } +} diff --git a/examples/with-tailwindcss-emotion/pages/index.js b/examples/with-tailwindcss-emotion/pages/index.js new file mode 100644 index 0000000000000..a6276711cc34e --- /dev/null +++ b/examples/with-tailwindcss-emotion/pages/index.js @@ -0,0 +1,38 @@ +import React from 'react' +import { css } from '@emotion/core' +import styled from '@emotion/styled' +import tw from 'tailwind.macro' + +/** + * We can use macros in `styled`. + */ +const Header = styled.div` + ${tw`font-mono text-sm text-gray-800 hover:text-red-500`} +` + +const Button = styled.button` + ${tw`bg-blue-500 text-white font-mono px-4 py-2 rounded`} + :hover { + ${tw`bg-blue-700`} + } +` + +/** + * Also, we can use `css`. + */ +const CardStyle = css` + ${tw`p-4 border-solid border border-gray-300 rounded p-4 shadow-xl`} +` + +const Card = styled.div` + ${CardStyle} +` + +const Example = () => ( + +
Hello
+ +
+) + +export default Example diff --git a/examples/with-tailwindcss-emotion/tailwind.js b/examples/with-tailwindcss-emotion/tailwind.js new file mode 100644 index 0000000000000..c9f06c913b9cb --- /dev/null +++ b/examples/with-tailwindcss-emotion/tailwind.js @@ -0,0 +1,490 @@ +/** + * default config from https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js + * we also use `tailwind.js` because the default of `babel-plugin-macros` set this file as a tailwind default config. + */ +module.exports = { + prefix: '', + important: false, + separator: ':', + theme: { + colors: { + transparent: 'transparent', + + black: '#000', + white: '#fff', + + gray: { + 100: '#f7fafc', + 200: '#edf2f7', + 300: '#e2e8f0', + 400: '#cbd5e0', + 500: '#a0aec0', + 600: '#718096', + 700: '#4a5568', + 800: '#2d3748', + 900: '#1a202c' + }, + red: { + 100: '#fff5f5', + 200: '#fed7d7', + 300: '#feb2b2', + 400: '#fc8181', + 500: '#f56565', + 600: '#e53e3e', + 700: '#c53030', + 800: '#9b2c2c', + 900: '#742a2a' + }, + orange: { + 100: '#fffaf0', + 200: '#feebc8', + 300: '#fbd38d', + 400: '#f6ad55', + 500: '#ed8936', + 600: '#dd6b20', + 700: '#c05621', + 800: '#9c4221', + 900: '#7b341e' + }, + yellow: { + 100: '#fffff0', + 200: '#fefcbf', + 300: '#faf089', + 400: '#f6e05e', + 500: '#ecc94b', + 600: '#d69e2e', + 700: '#b7791f', + 800: '#975a16', + 900: '#744210' + }, + green: { + 100: '#f0fff4', + 200: '#c6f6d5', + 300: '#9ae6b4', + 400: '#68d391', + 500: '#48bb78', + 600: '#38a169', + 700: '#2f855a', + 800: '#276749', + 900: '#22543d' + }, + teal: { + 100: '#e6fffa', + 200: '#b2f5ea', + 300: '#81e6d9', + 400: '#4fd1c5', + 500: '#38b2ac', + 600: '#319795', + 700: '#2c7a7b', + 800: '#285e61', + 900: '#234e52' + }, + blue: { + 100: '#ebf8ff', + 200: '#bee3f8', + 300: '#90cdf4', + 400: '#63b3ed', + 500: '#4299e1', + 600: '#3182ce', + 700: '#2b6cb0', + 800: '#2c5282', + 900: '#2a4365' + }, + indigo: { + 100: '#ebf4ff', + 200: '#c3dafe', + 300: '#a3bffa', + 400: '#7f9cf5', + 500: '#667eea', + 600: '#5a67d8', + 700: '#4c51bf', + 800: '#434190', + 900: '#3c366b' + }, + purple: { + 100: '#faf5ff', + 200: '#e9d8fd', + 300: '#d6bcfa', + 400: '#b794f4', + 500: '#9f7aea', + 600: '#805ad5', + 700: '#6b46c1', + 800: '#553c9a', + 900: '#44337a' + }, + pink: { + 100: '#fff5f7', + 200: '#fed7e2', + 300: '#fbb6ce', + 400: '#f687b3', + 500: '#ed64a6', + 600: '#d53f8c', + 700: '#b83280', + 800: '#97266d', + 900: '#702459' + } + }, + spacing: { + px: '1px', + 0: '0', + 1: '0.25rem', + 2: '0.5rem', + 3: '0.75rem', + 4: '1rem', + 5: '1.25rem', + 6: '1.5rem', + 8: '2rem', + 10: '2.5rem', + 12: '3rem', + 16: '4rem', + 20: '5rem', + 24: '6rem', + 32: '8rem', + 40: '10rem', + 48: '12rem', + 56: '14rem', + 64: '16rem' + }, + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px' + }, + fontFamily: { + sans: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + '"Helvetica Neue"', + 'Arial', + '"Noto Sans"', + 'sans-serif', + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Noto Color Emoji"' + ], + serif: ['Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'], + mono: [ + 'Menlo', + 'Monaco', + 'Consolas', + '"Liberation Mono"', + '"Courier New"', + 'monospace' + ] + }, + fontSize: { + xs: '0.75rem', + sm: '0.875rem', + base: '1rem', + lg: '1.125rem', + xl: '1.25rem', + '2xl': '1.5rem', + '3xl': '1.875rem', + '4xl': '2.25rem', + '5xl': '3rem', + '6xl': '4rem' + }, + fontWeight: { + hairline: '100', + thin: '200', + light: '300', + normal: '400', + medium: '500', + semibold: '600', + bold: '700', + extrabold: '800', + black: '900' + }, + lineHeight: { + none: '1', + tight: '1.25', + snug: '1.375', + normal: '1.5', + relaxed: '1.625', + loose: '2' + }, + letterSpacing: { + tighter: '-0.05em', + tight: '-0.025em', + normal: '0', + wide: '0.025em', + wider: '0.05em', + widest: '0.1em' + }, + textColor: theme => theme('colors'), + backgroundColor: theme => theme('colors'), + backgroundPosition: { + bottom: 'bottom', + center: 'center', + left: 'left', + 'left-bottom': 'left bottom', + 'left-top': 'left top', + right: 'right', + 'right-bottom': 'right bottom', + 'right-top': 'right top', + top: 'top' + }, + backgroundSize: { + auto: 'auto', + cover: 'cover', + contain: 'contain' + }, + borderWidth: { + default: '1px', + 0: '0', + 2: '2px', + 4: '4px', + 8: '8px' + }, + borderColor: theme => ({ + ...theme('colors'), + default: theme('colors.gray.300', 'currentColor') + }), + borderRadius: { + none: '0', + sm: '0.125rem', + default: '0.25rem', + lg: '0.5rem', + full: '9999px' + }, + cursor: { + auto: 'auto', + default: 'default', + pointer: 'pointer', + wait: 'wait', + text: 'text', + move: 'move', + 'not-allowed': 'not-allowed' + }, + width: theme => ({ + auto: 'auto', + ...theme('spacing'), + '1/2': '50%', + '1/3': '33.33333%', + '2/3': '66.66667%', + '1/4': '25%', + '2/4': '50%', + '3/4': '75%', + '1/5': '20%', + '2/5': '40%', + '3/5': '60%', + '4/5': '80%', + '1/6': '16.66667%', + '2/6': '33.33333%', + '3/6': '50%', + '4/6': '66.66667%', + '5/6': '83.33333%', + '1/12': '8.33333%', + '2/12': '16.66667%', + '3/12': '25%', + '4/12': '33.33333%', + '5/12': '41.66667%', + '6/12': '50%', + '7/12': '58.33333%', + '8/12': '66.66667%', + '9/12': '75%', + '10/12': '83.33333%', + '11/12': '91.66667%', + full: '100%', + screen: '100vw' + }), + height: theme => ({ + auto: 'auto', + ...theme('spacing'), + full: '100%', + screen: '100vh' + }), + minWidth: { + 0: '0', + full: '100%' + }, + minHeight: { + 0: '0', + full: '100%', + screen: '100vh' + }, + maxWidth: { + xs: '20rem', + sm: '24rem', + md: '28rem', + lg: '32rem', + xl: '36rem', + '2xl': '42rem', + '3xl': '48rem', + '4xl': '56rem', + '5xl': '64rem', + '6xl': '72rem', + full: '100%' + }, + maxHeight: { + full: '100%', + screen: '100vh' + }, + padding: theme => theme('spacing'), + margin: (theme, { negative }) => ({ + auto: 'auto', + ...theme('spacing'), + ...negative(theme('spacing')) + }), + objectPosition: { + bottom: 'bottom', + center: 'center', + left: 'left', + 'left-bottom': 'left bottom', + 'left-top': 'left top', + right: 'right', + 'right-bottom': 'right bottom', + 'right-top': 'right top', + top: 'top' + }, + boxShadow: { + default: + '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)', + md: + '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', + lg: + '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)', + xl: + '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', + '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)', + inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)', + outline: '0 0 0 3px rgba(66, 153, 225, 0.5)', + none: 'none' + }, + zIndex: { + auto: 'auto', + 0: '0', + 10: '10', + 20: '20', + 30: '30', + 40: '40', + 50: '50' + }, + opacity: { + 0: '0', + 25: '0.25', + 50: '0.5', + 75: '0.75', + 100: '1' + }, + fill: { + current: 'currentColor' + }, + stroke: { + current: 'currentColor' + }, + flex: { + 1: '1 1 0%', + auto: '1 1 auto', + initial: '0 1 auto', + none: 'none' + }, + flexGrow: { + 0: '0', + default: '1' + }, + flexShrink: { + 0: '0', + default: '1' + }, + order: { + first: '-1', + last: '999', + none: '0', + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12' + }, + listStyleType: { + none: 'none', + disc: 'disc', + decimal: 'decimal' + }, + inset: { + 0: '0', + auto: 'auto' + }, + container: {} + }, + variants: { + appearance: ['responsive'], + backgroundAttachment: ['responsive'], + backgroundColor: ['responsive', 'hover', 'focus'], + backgroundPosition: ['responsive'], + backgroundRepeat: ['responsive'], + backgroundSize: ['responsive'], + borderCollapse: [], + borderColor: ['responsive', 'hover', 'focus'], + borderRadius: ['responsive'], + borderStyle: ['responsive'], + borderWidth: ['responsive'], + cursor: ['responsive'], + display: ['responsive'], + flexDirection: ['responsive'], + flexWrap: ['responsive'], + alignItems: ['responsive'], + alignSelf: ['responsive'], + justifyContent: ['responsive'], + alignContent: ['responsive'], + flex: ['responsive'], + flexGrow: ['responsive'], + flexShrink: ['responsive'], + order: ['responsive'], + float: ['responsive'], + fontFamily: ['responsive'], + fontWeight: ['responsive', 'hover', 'focus'], + height: ['responsive'], + lineHeight: ['responsive'], + listStylePosition: ['responsive'], + listStyleType: ['responsive'], + margin: ['responsive'], + maxHeight: ['responsive'], + maxWidth: ['responsive'], + minHeight: ['responsive'], + minWidth: ['responsive'], + objectFit: ['responsive'], + objectPosition: ['responsive'], + opacity: ['responsive'], + outline: ['focus'], + overflow: ['responsive'], + padding: ['responsive'], + pointerEvents: ['responsive'], + position: ['responsive'], + inset: ['responsive'], + resize: ['responsive'], + boxShadow: ['responsive', 'hover', 'focus'], + fill: [], + stroke: [], + tableLayout: ['responsive'], + textAlign: ['responsive'], + textColor: ['responsive', 'hover', 'focus'], + fontSize: ['responsive'], + fontStyle: ['responsive'], + textTransform: ['responsive'], + textDecoration: ['responsive', 'hover', 'focus'], + fontSmoothing: ['responsive'], + letterSpacing: ['responsive'], + userSelect: ['responsive'], + verticalAlign: ['responsive'], + visibility: ['responsive'], + whitespace: ['responsive'], + wordBreak: ['responsive'], + width: ['responsive'], + zIndex: ['responsive'] + }, + corePlugins: {}, + plugins: [] +}