├── .github
└── logo.svg
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── demo
├── components
│ ├── GithubLink.js
│ ├── Logo.js
│ └── Typography.js
├── fonts
│ ├── Inter-italic-latin.var.woff2
│ ├── Inter-roman-latin.var.woff2
│ ├── SourceSansPro-Regular.otf
│ └── Ubuntu-Mono-bold.woff2
├── package-lock.json
├── package.json
├── pages
│ ├── _app.js
│ └── index.js
├── postcss.config.js
├── public
│ └── favicon
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── mstile-150x150.png
│ │ ├── safari-pinned-tab.svg
│ │ └── site.webmanifest
├── styles
│ ├── base.css
│ ├── components.css
│ ├── main.css
│ └── utilities.css
├── tailwind.config.full.js
└── tailwind.config.js
├── package-lock.json
├── package.json
├── prettier.config.js
└── src
└── index.js
/.github/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .next
2 | node_modules
3 | /demo/out
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | docs
2 | node_modules
3 | .next
4 | package-lock.json
5 | yarn.lock
6 | demo
7 | .github
8 | prettier.config.js
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Mosaad
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | A Tailwind CSS plugin for automatically trimming the whitespace above and below text nodes. This is a port of [Capsize](https://github.com/seek-oss/capsize).
6 |
7 | Huge thanks to [Michael Taranto](https://github.com/michaeltaranto) and the [Seek](https://github.com/seek-oss) team behind it for figuring out the hard parts.
8 |
9 | [View live demo](https://tailwindcss-capsize.themosaad.com)
10 |
11 | ```html
12 | Capsized Text
13 | ```
14 |
15 | # Table of Contents
16 |
17 | - [Installation](#installation)
18 | - [Usage](#usage)
19 | - [Trim by default](#trim-by-default)
20 | - [Default line-height](#default-line-height)
21 | - [Define a default font-family](#define-a-default-font-family)
22 | - [Usage with @apply](#usage-with--apply)
23 | - [Root font-size](#root-font-size)
24 | - [Limitation and Customization](#limitation-and-customization)
25 | - [Behind the scenes](#behind-the-scenes)
26 | - [This port vs original Capsize](#this-port-vs-original-capsize)
27 | - [cap-height (since v0.4.0)](#cap-height--since-v040-)
28 | - [Default values](#default-values)
29 | - [line-gap (since v0.4.0)](#line-gap--since-v040-)
30 | - [Default values](#default-values-1)
31 |
32 | ## Installation
33 |
34 | Install the plugin from npm:
35 |
36 | ```sh
37 | # Using npm
38 | npm install @themosaad/tailwindcss-capsize
39 | ```
40 |
41 | Then add the plugin to your `tailwind.config.js` file:
42 |
43 | ```js
44 | // tailwind.config.js
45 | module.exports = {
46 | theme: {
47 | fontFamily: {
48 | // define your custom font
49 | sans: ['Inter var', 'sans-serif'],
50 | },
51 | capsize: {
52 | fontMetrics: {
53 | // define font metrics for your custom font from Capsize's website
54 | sans: {
55 | capHeight: 2048,
56 | ascent: 2728,
57 | descent: -680,
58 | lineGap: 0,
59 | unitsPerEm: 2816,
60 | },
61 | },
62 | // define the utility class for trimming (leave empty to trim all text nodes)
63 | className: 'capsize',
64 | },
65 | },
66 | plugins: [require('@themosaad/tailwindcss-capsize')],
67 | }
68 | ```
69 |
70 | ## Usage
71 |
72 | Now you can use the `capsize` class to trim any text:
73 |
74 | ```html
75 | Capsized Text
76 | ```
77 |
78 | ### Trim by default
79 |
80 | if you prefer to trim text nodes by default, don't define a class name. This will move the trimming css to the font-size classes:
81 |
82 | ```js
83 | // tailwind.config.js
84 | module.exports = {
85 | theme: {
86 | capsize: {
87 | fontMetrics: {
88 | // ...
89 | },
90 | // className: 'capsize',
91 | },
92 | },
93 | plugins: [require('@themosaad/tailwindcss-capsize')],
94 | }
95 | ```
96 |
97 | this way, you can use:
98 |
99 | ```html
100 | Capsized Text
101 | ```
102 |
103 | ### Default line-height
104 |
105 | The root `line-height` is set to `1.5` by default. Which you can alter via:
106 |
107 | ```js
108 | // tailwind.config.js
109 | module.exports = {
110 | theme: {
111 | capsize: {
112 | rootLineHeightUnitless: 1.2,
113 | },
114 | }
115 | ```
116 |
117 | Therefore, if that's the line-height you want for a capsized element, you can ditch the leading class:
118 |
119 | ```html
120 | Capsized Text
121 | ```
122 |
123 | If you want better default line-height per font-size, you can enable the [defaultLineHeights experimental feature](https://github.com/tailwindlabs/tailwindcss/blob/v1.8.5/src/flagged/defaultLineHeights.js). Which will become the default in Tailwindcss v2.
124 |
125 | ```js
126 | // tailwind.config.js
127 | module.exports = {
128 | experimental: {
129 | defaultLineHeights: true,
130 | },
131 | }
132 | ```
133 |
134 | ### Define a default font-family
135 |
136 | In most cases, you'll have a default font-family that's used accross the website by default.
137 |
138 | If you added the `font-sans` class to the body or a parent element, you can use
139 |
140 | ```html
141 | Capsized Text
142 | ```
143 |
144 | ### Usage with @apply
145 |
146 | Since the plugin outputs pseudo-elements, you'll need to use the experimental applyComplexClasses feature:
147 |
148 | ```js
149 | // tailwind.config.js
150 | module.exports = {
151 | experimental: {
152 | applyComplexClasses: true,
153 | },
154 | }
155 | ```
156 |
157 | Which will allow you to use:
158 |
159 | ```css
160 | p {
161 | @apply capsize font-sans text-xl leading-7;
162 | }
163 | ```
164 |
165 | ### Root font-size
166 |
167 | The plugin outputs the following inside the `@tailwind/base`:
168 |
169 | ```css
170 | html {
171 | font-size: 16px;
172 | --root-font-size-px: 16;
173 | }
174 | ```
175 |
176 | So overriding it from you css might mess up the trimming calculations.
177 |
178 | To change the default root font-size:
179 |
180 | ```js
181 | // tailwind.config.js
182 | module.exports = {
183 | theme: {
184 | capsize: {
185 | rootFontSizePx: {
186 | default: 16,
187 | },
188 | },
189 | },
190 | }
191 | ```
192 |
193 | You can also change the rootFontSize for each screen:
194 |
195 | ```js
196 | // tailwind.config.js
197 | module.exports = {
198 | theme: {
199 | capsize: {
200 | rootFontSizePx: {
201 | default: 16,
202 | sm: 18,
203 | lg: 20,
204 | },
205 | },
206 | },
207 | }
208 | ```
209 |
210 | ## Limitation and Customization
211 |
212 | - Accepts `rem` and `px` for fontSize.
213 | - Accepts `rem`, `px`, and `unitless` for lineHeight.
214 | - Doesn't trim text on IE11 as it uses css variables for the trimming calculations. (will work on a JS polyfill or an average pre-calculation for all project fonts)
215 | - ~~Adds `padding: 0.05px 0` to capsized element which will override your padding utility classes.~~ No longer the case from v0.3.0.
216 |
217 | ## Behind the scenes
218 |
219 | The plugin adds the following to typography-related utility classes:
220 |
221 | To font-family classes, it adds css variables with font metrics:
222 |
223 | ```css
224 | .font-sans {
225 | font-family: Inter var, system-ui;
226 | --cap-height-scale: 0.7272;
227 | --descent-scale: 0.2414;
228 | --ascent-scale: 0.96875;
229 | --line-gap-scale: 0;
230 | --line-height-scale: 1.2102;
231 | }
232 | ```
233 |
234 | To font-size classes, it adds css variables for calculating the font-size in pixels:
235 |
236 | ```css
237 | .text-6xl {
238 | font-size: 4rem;
239 | --font-size-rem: 4;
240 | --font-size-px: calc(var(--font-size-rem) * var(--root-font-size-px));
241 | }
242 | ```
243 |
244 | To line-height classes, it adds css variables for calculating the line-height in pixels:
245 |
246 | ```css
247 | .leading-tight {
248 | line-height: 1.25;
249 | --line-height-unitless: 1.25;
250 | --line-height-px: calc(var(--line-height-unitless) * var(--font-size-px));
251 | }
252 | ```
253 |
254 | To the capsized element's pseduo selectors, it adds the trimming calculation:
255 |
256 | ```css
257 | .capsize::before {
258 | content: '';
259 | display: table;
260 | --line-height-normal: calc(var(--line-height-scale) * var(--font-size-px));
261 | --specified-line-height-offset-double: calc(var(--line-height-normal) - var(--line-height-px));
262 | --specified-line-height-offset: calc(var(--specified-line-height-offset-double) / 2);
263 | --specified-line-height-offset-to-scale: calc(
264 | var(--specified-line-height-offset) / var(--font-size-px)
265 | );
266 | --line-gap-scale-half: calc(var(--line-gap-scale) / 2);
267 | --leading-trim-top: calc(
268 | var(--ascent-scale) - var(--cap-height-scale) + var(--line-gap-scale-half) - var(--specified-line-height-offset-to-scale)
269 | );
270 | margin-bottom: calc(-1em * var(--leading-trim-top));
271 | }
272 |
273 | .capsize::after {
274 | content: '';
275 | display: table;
276 | --line-height-normal: calc(var(--line-height-scale) * var(--font-size-px));
277 | --specified-line-height-offset-double: calc(var(--line-height-normal) - var(--line-height-px));
278 | --specified-line-height-offset: calc(var(--specified-line-height-offset-double) / 2);
279 | --specified-line-height-offset-to-scale: calc(
280 | var(--specified-line-height-offset) / var(--font-size-px)
281 | );
282 | --prevent-collapse-to-scale: calc(var(--prevent-collapse) / var(--font-size-px));
283 | --line-gap-scale-half: calc(var(--line-gap-scale) / 2);
284 | --leading-trim-bottom: calc(
285 | var(--descent-scale) + var(--line-gap-scale-half) - var(--specified-line-height-offset-to-scale)
286 | );
287 | margin-top: calc(-1em * var(--leading-trim-bottom));
288 | }
289 | ```
290 |
291 | ## This port vs original Capsize
292 |
293 | Aside from implementing the calculations via CSS variables to allow the usage of utility classes as illustrated above, I use a different method to prevent margin collapse that's not yet used in the original Capsize package (capsize@1.1.0 at the time).
294 |
295 | Capsize currently adds a `0.05` top and bottom padding to the capsized element to prevent margin collapse.
296 |
297 | From v0.3.0, I implemented a new way to prevent the collapsing based on @michaeltaranto's findings in [this issue](https://github.com/seek-oss/capsize/issues/26#issuecomment-686796155) that's not yet implemented in their Capsize.
298 |
299 | Now, you can use padding classes on the capsized element:
300 |
301 | ```html
302 |
303 | Capsized Link with Padding
304 |
305 | ```
306 |
307 | If you encountered any crossbrowser issue with the new prevent collapse implementation, you can reverse back to the original implementation with padding:
308 |
309 | ```js
310 | // tailwind.config.js
311 | module.exports = {
312 | theme: {
313 | capsize: {
314 | keepPadding: true,
315 | },
316 | },
317 | }
318 | ```
319 |
320 | ## cap-height (since v0.4.0)
321 |
322 | Instead of setting the `font-size`, you can use `cap-height` to declare the height of a the capital letters, and it'll automatically set the `font-size` based on the `fontMetrics`.
323 |
324 | This comes in handy when you have an icon next to the test and you want to visually balance their height.
325 |
326 | ```html
327 | Capsized Text that's 1rem in height
328 | ```
329 |
330 | ### Default values
331 |
332 | Default values are cut from the `extendedSpacingScale` feature flag. Found it unuseful to inclue the very small and very large values.
333 |
334 | You can override the default values via:
335 |
336 | ```js
337 | module.exports = {
338 | theme: {
339 | // ...
340 | capHeight: {
341 | 2: '0.5rem',
342 | 2.5: '0.625rem',
343 | 3: '0.75rem',
344 | 3.5: '0.875rem',
345 | 4: '1rem',
346 | 5: '1.25rem',
347 | 6: '1.5rem',
348 | 7: '1.75rem',
349 | 8: '2rem',
350 | 9: '2.25rem',
351 | 10: '2.5rem',
352 | 11: '2.75rem',
353 | 12: '3rem',
354 | 13: '3.25rem',
355 | 14: '3.5rem',
356 | 15: '3.75rem',
357 | },
358 | },
359 | }
360 | ```
361 |
362 | ## line-gap (since v0.4.0)
363 |
364 | `line-gap` goes hand in hand with `cap-height` to have predectible height.
365 |
366 | If the following example wrapped to 2 lines. The total height of the element would be 3rem.
367 |
368 | ```html
369 |
370 | Capsized Text that's 1rem in height and has a 1rem line-gap
371 |
372 | ```
373 |
374 | ### Default values
375 |
376 | `line-gap` has the same default values as `cap-height` which you can override via:
377 |
378 | ```js
379 | module.exports = {
380 | theme: {
381 | // ...
382 | lineGap: {
383 | 2: '0.5rem',
384 | 2.5: '0.625rem',
385 | 3: '0.75rem',
386 | 3.5: '0.875rem',
387 | 4: '1rem',
388 | 5: '1.25rem',
389 | 6: '1.5rem',
390 | 7: '1.75rem',
391 | 8: '2rem',
392 | 9: '2.25rem',
393 | 10: '2.5rem',
394 | 11: '2.75rem',
395 | 12: '3rem',
396 | 13: '3.25rem',
397 | 14: '3.5rem',
398 | 15: '3.75rem',
399 | },
400 | },
401 | }
402 | ```
403 |
404 | You can also set default `line-gap` values for each `cap-height` similar to the [defaultLineHeights experimental feature](https://github.com/tailwindlabs/tailwindcss/blob/v1.8.5/src/flagged/defaultLineHeights.js) via:
405 |
406 | ```js
407 | module.exports = {
408 | theme: {
409 | // ...
410 | capHeight: {
411 | 2: ['0.5rem', { lineGap: '0.5rem' }],
412 | 3: ['0.75rem', { lineGap: '0.625rem' }],
413 | // ...
414 | },
415 | },
416 | }
417 | ```
418 |
--------------------------------------------------------------------------------
/demo/components/GithubLink.js:
--------------------------------------------------------------------------------
1 | export default function GithubLink() {
2 | return (
3 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/demo/components/Logo.js:
--------------------------------------------------------------------------------
1 | export default function Logo() {
2 | return (
3 |
4 |
5 |
11 |
17 |
18 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
45 |
49 |
53 |
57 |
62 |
67 |
71 |
75 |
80 |
87 |
91 |
92 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | )
107 | }
108 |
--------------------------------------------------------------------------------
/demo/components/Typography.js:
--------------------------------------------------------------------------------
1 | import resolveConfig from 'tailwindcss/resolveConfig'
2 | import tailwindConfig from '../tailwind.config'
3 |
4 | export default function Typography() {
5 | const fullConfig = resolveConfig(tailwindConfig)
6 | return (
7 | <>
8 |
9 | {Object.keys(fullConfig.theme.capsize.fontMetrics).map((fontFamily, fontFamilyIndex) => (
10 |
11 |
15 | font-{fontFamily}
16 |
17 |
18 |
19 |
20 | font-size & line-height
21 |
22 | {Object.keys(fullConfig.theme.fontSize)
23 | // .reverse()
24 | .map((fontSize, fontSizeIndex) => (
25 |
26 |
{`text-${fontSize}`}
29 |
{`text-${fontSize} leading-none`}
32 |
{`text-${fontSize} leading-tight`}
35 |
{`text-${fontSize} leading-relaxed`}
38 |
39 | ))}
40 |
41 |
42 |
43 | cap-height & line-gap
44 |
45 |
46 | {Object.keys(fullConfig.theme.capHeight)
47 | .sort((a, b) => a - b)
48 | .map((capHeight, capHeightIndex) => (
49 |
50 |
{`cap-height-${capHeight}`}
53 |
{`cap-height-${capHeight} line-gap-0`}
56 |
{`cap-height-${capHeight} line-gap-8`}
59 |
{`cap-height-${capHeight} line-gap-10`}
62 |
63 | ))}
64 |
65 |
66 |
67 |
68 | ))}
69 |
70 | >
71 | )
72 | }
73 |
--------------------------------------------------------------------------------
/demo/fonts/Inter-italic-latin.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/fonts/Inter-italic-latin.var.woff2
--------------------------------------------------------------------------------
/demo/fonts/Inter-roman-latin.var.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/fonts/Inter-roman-latin.var.woff2
--------------------------------------------------------------------------------
/demo/fonts/SourceSansPro-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/fonts/SourceSansPro-Regular.otf
--------------------------------------------------------------------------------
/demo/fonts/Ubuntu-Mono-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/fonts/Ubuntu-Mono-bold.woff2
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tailwindcss-capsize-demo",
3 | "version": "1.0.0",
4 | "description": "A demo for testing @themosaad/tailwindcss-capsize plugin",
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start"
9 | },
10 | "author": "Mosaad",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@themosaad/tailwindcss-capsize": "^1.0.0",
14 | "autoprefixer": "^10.2.4",
15 | "next": "^10.0.6",
16 | "postcss": "^8.2.4",
17 | "react": "^16.13.1",
18 | "react-dom": "^16.13.1",
19 | "tailwindcss": "^2.0.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/demo/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/main.css'
2 |
3 | export default function MyApp({ Component, pageProps }) {
4 | return
5 | }
6 |
--------------------------------------------------------------------------------
/demo/pages/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import Typography from '../components/Typography'
3 | import GithubLink from '../components/GithubLink'
4 | import Logo from '../components/Logo'
5 |
6 | export default function Index() {
7 | return (
8 |
9 |
10 |
Tailwind CSS and Capsize
11 |
12 |
13 |
14 | Tailwind CSS and Capsize
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/demo/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/demo/public/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/demo/public/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/demo/public/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/demo/public/favicon/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #000000
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/demo/public/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/demo/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/demo/public/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/favicon.ico
--------------------------------------------------------------------------------
/demo/public/favicon/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/theMosaad/tailwindcss-capsize/8c334eef1a421e7d02ca92c9dc8ff21d3b2ef00a/demo/public/favicon/mstile-150x150.png
--------------------------------------------------------------------------------
/demo/public/favicon/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/public/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Next.js",
3 | "short_name": "Next.js",
4 | "icons": [
5 | {
6 | "src": "/favicons/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "/favicons/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "theme_color": "#000000",
17 | "background_color": "#000000",
18 | "display": "standalone"
19 | }
20 |
--------------------------------------------------------------------------------
/demo/styles/base.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Inter var';
3 | font-weight: 100 900;
4 | font-display: swap;
5 | font-style: normal;
6 | font-named-instance: 'Regular';
7 | src: url('../fonts/Inter-roman-latin.var.woff2') format('woff2');
8 | }
9 |
10 | @font-face {
11 | font-family: 'Inter var';
12 | font-weight: 100 900;
13 | font-display: swap;
14 | font-style: italic;
15 | font-named-instance: 'Italic';
16 | src: url('../fonts/Inter-italic-latin.var.woff2') format('woff2');
17 | }
18 |
19 | @font-face {
20 | font-family: 'Source Sans Pro';
21 | font-style: normal;
22 | font-weight: 400;
23 | font-display: swap;
24 | src: url('../fonts/SourceSansPro-Regular.otf') format('opentype');
25 | }
26 |
27 | @font-face {
28 | font-family: 'Ubuntu Mono';
29 | font-weight: 700;
30 | font-style: normal;
31 | src: url('../fonts/Ubuntu-Mono-bold.woff2') format('woff2');
32 | }
33 |
34 | @tailwind base;
35 |
--------------------------------------------------------------------------------
/demo/styles/components.css:
--------------------------------------------------------------------------------
1 | @tailwind components;
2 |
--------------------------------------------------------------------------------
/demo/styles/main.css:
--------------------------------------------------------------------------------
1 | @import 'base.css';
2 | @import 'components.css';
3 |
4 | @import 'utilities.css';
5 |
--------------------------------------------------------------------------------
/demo/styles/utilities.css:
--------------------------------------------------------------------------------
1 | @tailwind utilities;
2 |
--------------------------------------------------------------------------------
/demo/tailwind.config.full.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | future: {
3 | // removeDeprecatedGapUtilities: true,
4 | // purgeLayersByDefault: true,
5 | },
6 | purge: [],
7 | target: 'relaxed',
8 | prefix: '',
9 | important: false,
10 | separator: ':',
11 | theme: {
12 | screens: {
13 | sm: '640px',
14 | md: '768px',
15 | lg: '1024px',
16 | xl: '1280px',
17 | },
18 | colors: {
19 | transparent: 'transparent',
20 | current: 'currentColor',
21 |
22 | black: '#000',
23 | white: '#fff',
24 |
25 | gray: {
26 | 100: '#f7fafc',
27 | 200: '#edf2f7',
28 | 300: '#e2e8f0',
29 | 400: '#cbd5e0',
30 | 500: '#a0aec0',
31 | 600: '#718096',
32 | 700: '#4a5568',
33 | 800: '#2d3748',
34 | 900: '#1a202c',
35 | },
36 | red: {
37 | 100: '#fff5f5',
38 | 200: '#fed7d7',
39 | 300: '#feb2b2',
40 | 400: '#fc8181',
41 | 500: '#f56565',
42 | 600: '#e53e3e',
43 | 700: '#c53030',
44 | 800: '#9b2c2c',
45 | 900: '#742a2a',
46 | },
47 | orange: {
48 | 100: '#fffaf0',
49 | 200: '#feebc8',
50 | 300: '#fbd38d',
51 | 400: '#f6ad55',
52 | 500: '#ed8936',
53 | 600: '#dd6b20',
54 | 700: '#c05621',
55 | 800: '#9c4221',
56 | 900: '#7b341e',
57 | },
58 | yellow: {
59 | 100: '#fffff0',
60 | 200: '#fefcbf',
61 | 300: '#faf089',
62 | 400: '#f6e05e',
63 | 500: '#ecc94b',
64 | 600: '#d69e2e',
65 | 700: '#b7791f',
66 | 800: '#975a16',
67 | 900: '#744210',
68 | },
69 | green: {
70 | 100: '#f0fff4',
71 | 200: '#c6f6d5',
72 | 300: '#9ae6b4',
73 | 400: '#68d391',
74 | 500: '#48bb78',
75 | 600: '#38a169',
76 | 700: '#2f855a',
77 | 800: '#276749',
78 | 900: '#22543d',
79 | },
80 | teal: {
81 | 100: '#e6fffa',
82 | 200: '#b2f5ea',
83 | 300: '#81e6d9',
84 | 400: '#4fd1c5',
85 | 500: '#38b2ac',
86 | 600: '#319795',
87 | 700: '#2c7a7b',
88 | 800: '#285e61',
89 | 900: '#234e52',
90 | },
91 | blue: {
92 | 100: '#ebf8ff',
93 | 200: '#bee3f8',
94 | 300: '#90cdf4',
95 | 400: '#63b3ed',
96 | 500: '#4299e1',
97 | 600: '#3182ce',
98 | 700: '#2b6cb0',
99 | 800: '#2c5282',
100 | 900: '#2a4365',
101 | },
102 | indigo: {
103 | 100: '#ebf4ff',
104 | 200: '#c3dafe',
105 | 300: '#a3bffa',
106 | 400: '#7f9cf5',
107 | 500: '#667eea',
108 | 600: '#5a67d8',
109 | 700: '#4c51bf',
110 | 800: '#434190',
111 | 900: '#3c366b',
112 | },
113 | purple: {
114 | 100: '#faf5ff',
115 | 200: '#e9d8fd',
116 | 300: '#d6bcfa',
117 | 400: '#b794f4',
118 | 500: '#9f7aea',
119 | 600: '#805ad5',
120 | 700: '#6b46c1',
121 | 800: '#553c9a',
122 | 900: '#44337a',
123 | },
124 | pink: {
125 | 100: '#fff5f7',
126 | 200: '#fed7e2',
127 | 300: '#fbb6ce',
128 | 400: '#f687b3',
129 | 500: '#ed64a6',
130 | 600: '#d53f8c',
131 | 700: '#b83280',
132 | 800: '#97266d',
133 | 900: '#702459',
134 | },
135 | },
136 | spacing: {
137 | px: '1px',
138 | '0': '0',
139 | '1': '0.25rem',
140 | '2': '0.5rem',
141 | '3': '0.75rem',
142 | '4': '1rem',
143 | '5': '1.25rem',
144 | '6': '1.5rem',
145 | '8': '2rem',
146 | '10': '2.5rem',
147 | '12': '3rem',
148 | '16': '4rem',
149 | '20': '5rem',
150 | '24': '6rem',
151 | '32': '8rem',
152 | '40': '10rem',
153 | '48': '12rem',
154 | '56': '14rem',
155 | '64': '16rem',
156 | },
157 | backgroundColor: (theme) => theme('colors'),
158 | backgroundImage: {
159 | none: 'none',
160 | 'gradient-to-t': 'linear-gradient(to top, var(--gradient-color-stops))',
161 | 'gradient-to-tr': 'linear-gradient(to top right, var(--gradient-color-stops))',
162 | 'gradient-to-r': 'linear-gradient(to right, var(--gradient-color-stops))',
163 | 'gradient-to-br': 'linear-gradient(to bottom right, var(--gradient-color-stops))',
164 | 'gradient-to-b': 'linear-gradient(to bottom, var(--gradient-color-stops))',
165 | 'gradient-to-bl': 'linear-gradient(to bottom left, var(--gradient-color-stops))',
166 | 'gradient-to-l': 'linear-gradient(to left, var(--gradient-color-stops))',
167 | 'gradient-to-tl': 'linear-gradient(to top left, var(--gradient-color-stops))',
168 | },
169 | gradientColorStops: (theme) => theme('colors'),
170 | backgroundOpacity: (theme) => theme('opacity'),
171 | backgroundPosition: {
172 | bottom: 'bottom',
173 | center: 'center',
174 | left: 'left',
175 | 'left-bottom': 'left bottom',
176 | 'left-top': 'left top',
177 | right: 'right',
178 | 'right-bottom': 'right bottom',
179 | 'right-top': 'right top',
180 | top: 'top',
181 | },
182 | backgroundSize: {
183 | auto: 'auto',
184 | cover: 'cover',
185 | contain: 'contain',
186 | },
187 | borderColor: (theme) => ({
188 | ...theme('colors'),
189 | default: theme('colors.gray.300', 'currentColor'),
190 | }),
191 | borderOpacity: (theme) => theme('opacity'),
192 | borderRadius: {
193 | none: '0',
194 | sm: '0.125rem',
195 | default: '0.25rem',
196 | md: '0.375rem',
197 | lg: '0.5rem',
198 | full: '9999px',
199 | },
200 | borderWidth: {
201 | default: '1px',
202 | '0': '0',
203 | '2': '2px',
204 | '4': '4px',
205 | '8': '8px',
206 | },
207 | boxShadow: {
208 | xs: '0 0 0 1px rgba(0, 0, 0, 0.05)',
209 | sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
210 | default: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
211 | md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
212 | lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
213 | xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
214 | '2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
215 | inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
216 | outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
217 | none: 'none',
218 | },
219 | container: {},
220 | cursor: {
221 | auto: 'auto',
222 | default: 'default',
223 | pointer: 'pointer',
224 | wait: 'wait',
225 | text: 'text',
226 | move: 'move',
227 | 'not-allowed': 'not-allowed',
228 | },
229 | divideColor: (theme) => theme('borderColor'),
230 | divideOpacity: (theme) => theme('borderOpacity'),
231 | divideWidth: (theme) => theme('borderWidth'),
232 | fill: {
233 | current: 'currentColor',
234 | },
235 | flex: {
236 | '1': '1 1 0%',
237 | auto: '1 1 auto',
238 | initial: '0 1 auto',
239 | none: 'none',
240 | },
241 | flexGrow: {
242 | '0': '0',
243 | default: '1',
244 | },
245 | flexShrink: {
246 | '0': '0',
247 | default: '1',
248 | },
249 | fontFamily: {
250 | sans: [
251 | 'system-ui',
252 | '-apple-system',
253 | 'BlinkMacSystemFont',
254 | '"Segoe UI"',
255 | 'Roboto',
256 | '"Helvetica Neue"',
257 | 'Arial',
258 | '"Noto Sans"',
259 | 'sans-serif',
260 | '"Apple Color Emoji"',
261 | '"Segoe UI Emoji"',
262 | '"Segoe UI Symbol"',
263 | '"Noto Color Emoji"',
264 | ],
265 | serif: ['Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'],
266 | mono: ['Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', 'monospace'],
267 | },
268 | fontSize: {
269 | xs: '0.75rem',
270 | sm: '0.875rem',
271 | base: '1rem',
272 | lg: '1.125rem',
273 | xl: '1.25rem',
274 | '2xl': '1.5rem',
275 | '3xl': '1.875rem',
276 | '4xl': '2.25rem',
277 | '5xl': '3rem',
278 | '6xl': '4rem',
279 | },
280 | fontWeight: {
281 | hairline: '100',
282 | thin: '200',
283 | light: '300',
284 | normal: '400',
285 | medium: '500',
286 | semibold: '600',
287 | bold: '700',
288 | extrabold: '800',
289 | black: '900',
290 | },
291 | height: (theme) => ({
292 | auto: 'auto',
293 | ...theme('spacing'),
294 | full: '100%',
295 | screen: '100vh',
296 | }),
297 | inset: {
298 | '0': '0',
299 | auto: 'auto',
300 | },
301 | letterSpacing: {
302 | tighter: '-0.05em',
303 | tight: '-0.025em',
304 | normal: '0',
305 | wide: '0.025em',
306 | wider: '0.05em',
307 | widest: '0.1em',
308 | },
309 | lineHeight: {
310 | none: '1',
311 | tight: '1.25',
312 | snug: '1.375',
313 | normal: '1.5',
314 | relaxed: '1.625',
315 | loose: '2',
316 | '3': '.75rem',
317 | '4': '1rem',
318 | '5': '1.25rem',
319 | '6': '1.5rem',
320 | '7': '1.75rem',
321 | '8': '2rem',
322 | '9': '2.25rem',
323 | '10': '2.5rem',
324 | },
325 | listStyleType: {
326 | none: 'none',
327 | disc: 'disc',
328 | decimal: 'decimal',
329 | },
330 | margin: (theme, { negative }) => ({
331 | auto: 'auto',
332 | ...theme('spacing'),
333 | ...negative(theme('spacing')),
334 | }),
335 | maxHeight: {
336 | full: '100%',
337 | screen: '100vh',
338 | },
339 | maxWidth: (theme, { breakpoints }) => ({
340 | none: 'none',
341 | xs: '20rem',
342 | sm: '24rem',
343 | md: '28rem',
344 | lg: '32rem',
345 | xl: '36rem',
346 | '2xl': '42rem',
347 | '3xl': '48rem',
348 | '4xl': '56rem',
349 | '5xl': '64rem',
350 | '6xl': '72rem',
351 | full: '100%',
352 | ...breakpoints(theme('screens')),
353 | }),
354 | minHeight: {
355 | '0': '0',
356 | full: '100%',
357 | screen: '100vh',
358 | },
359 | minWidth: {
360 | '0': '0',
361 | full: '100%',
362 | },
363 | objectPosition: {
364 | bottom: 'bottom',
365 | center: 'center',
366 | left: 'left',
367 | 'left-bottom': 'left bottom',
368 | 'left-top': 'left top',
369 | right: 'right',
370 | 'right-bottom': 'right bottom',
371 | 'right-top': 'right top',
372 | top: 'top',
373 | },
374 | opacity: {
375 | '0': '0',
376 | '25': '0.25',
377 | '50': '0.5',
378 | '75': '0.75',
379 | '100': '1',
380 | },
381 | order: {
382 | first: '-9999',
383 | last: '9999',
384 | none: '0',
385 | '1': '1',
386 | '2': '2',
387 | '3': '3',
388 | '4': '4',
389 | '5': '5',
390 | '6': '6',
391 | '7': '7',
392 | '8': '8',
393 | '9': '9',
394 | '10': '10',
395 | '11': '11',
396 | '12': '12',
397 | },
398 | padding: (theme) => theme('spacing'),
399 | placeholderColor: (theme) => theme('colors'),
400 | placeholderOpacity: (theme) => theme('opacity'),
401 | space: (theme, { negative }) => ({
402 | ...theme('spacing'),
403 | ...negative(theme('spacing')),
404 | }),
405 | stroke: {
406 | current: 'currentColor',
407 | },
408 | strokeWidth: {
409 | '0': '0',
410 | '1': '1',
411 | '2': '2',
412 | },
413 | textColor: (theme) => theme('colors'),
414 | textOpacity: (theme) => theme('opacity'),
415 | width: (theme) => ({
416 | auto: 'auto',
417 | ...theme('spacing'),
418 | '1/2': '50%',
419 | '1/3': '33.333333%',
420 | '2/3': '66.666667%',
421 | '1/4': '25%',
422 | '2/4': '50%',
423 | '3/4': '75%',
424 | '1/5': '20%',
425 | '2/5': '40%',
426 | '3/5': '60%',
427 | '4/5': '80%',
428 | '1/6': '16.666667%',
429 | '2/6': '33.333333%',
430 | '3/6': '50%',
431 | '4/6': '66.666667%',
432 | '5/6': '83.333333%',
433 | '1/12': '8.333333%',
434 | '2/12': '16.666667%',
435 | '3/12': '25%',
436 | '4/12': '33.333333%',
437 | '5/12': '41.666667%',
438 | '6/12': '50%',
439 | '7/12': '58.333333%',
440 | '8/12': '66.666667%',
441 | '9/12': '75%',
442 | '10/12': '83.333333%',
443 | '11/12': '91.666667%',
444 | full: '100%',
445 | screen: '100vw',
446 | }),
447 | zIndex: {
448 | auto: 'auto',
449 | '0': '0',
450 | '10': '10',
451 | '20': '20',
452 | '30': '30',
453 | '40': '40',
454 | '50': '50',
455 | },
456 | gap: (theme) => theme('spacing'),
457 | gridTemplateColumns: {
458 | none: 'none',
459 | '1': 'repeat(1, minmax(0, 1fr))',
460 | '2': 'repeat(2, minmax(0, 1fr))',
461 | '3': 'repeat(3, minmax(0, 1fr))',
462 | '4': 'repeat(4, minmax(0, 1fr))',
463 | '5': 'repeat(5, minmax(0, 1fr))',
464 | '6': 'repeat(6, minmax(0, 1fr))',
465 | '7': 'repeat(7, minmax(0, 1fr))',
466 | '8': 'repeat(8, minmax(0, 1fr))',
467 | '9': 'repeat(9, minmax(0, 1fr))',
468 | '10': 'repeat(10, minmax(0, 1fr))',
469 | '11': 'repeat(11, minmax(0, 1fr))',
470 | '12': 'repeat(12, minmax(0, 1fr))',
471 | },
472 | gridColumn: {
473 | auto: 'auto',
474 | 'span-1': 'span 1 / span 1',
475 | 'span-2': 'span 2 / span 2',
476 | 'span-3': 'span 3 / span 3',
477 | 'span-4': 'span 4 / span 4',
478 | 'span-5': 'span 5 / span 5',
479 | 'span-6': 'span 6 / span 6',
480 | 'span-7': 'span 7 / span 7',
481 | 'span-8': 'span 8 / span 8',
482 | 'span-9': 'span 9 / span 9',
483 | 'span-10': 'span 10 / span 10',
484 | 'span-11': 'span 11 / span 11',
485 | 'span-12': 'span 12 / span 12',
486 | },
487 | gridColumnStart: {
488 | auto: 'auto',
489 | '1': '1',
490 | '2': '2',
491 | '3': '3',
492 | '4': '4',
493 | '5': '5',
494 | '6': '6',
495 | '7': '7',
496 | '8': '8',
497 | '9': '9',
498 | '10': '10',
499 | '11': '11',
500 | '12': '12',
501 | '13': '13',
502 | },
503 | gridColumnEnd: {
504 | auto: 'auto',
505 | '1': '1',
506 | '2': '2',
507 | '3': '3',
508 | '4': '4',
509 | '5': '5',
510 | '6': '6',
511 | '7': '7',
512 | '8': '8',
513 | '9': '9',
514 | '10': '10',
515 | '11': '11',
516 | '12': '12',
517 | '13': '13',
518 | },
519 | gridTemplateRows: {
520 | none: 'none',
521 | '1': 'repeat(1, minmax(0, 1fr))',
522 | '2': 'repeat(2, minmax(0, 1fr))',
523 | '3': 'repeat(3, minmax(0, 1fr))',
524 | '4': 'repeat(4, minmax(0, 1fr))',
525 | '5': 'repeat(5, minmax(0, 1fr))',
526 | '6': 'repeat(6, minmax(0, 1fr))',
527 | },
528 | gridRow: {
529 | auto: 'auto',
530 | 'span-1': 'span 1 / span 1',
531 | 'span-2': 'span 2 / span 2',
532 | 'span-3': 'span 3 / span 3',
533 | 'span-4': 'span 4 / span 4',
534 | 'span-5': 'span 5 / span 5',
535 | 'span-6': 'span 6 / span 6',
536 | },
537 | gridRowStart: {
538 | auto: 'auto',
539 | '1': '1',
540 | '2': '2',
541 | '3': '3',
542 | '4': '4',
543 | '5': '5',
544 | '6': '6',
545 | '7': '7',
546 | },
547 | gridRowEnd: {
548 | auto: 'auto',
549 | '1': '1',
550 | '2': '2',
551 | '3': '3',
552 | '4': '4',
553 | '5': '5',
554 | '6': '6',
555 | '7': '7',
556 | },
557 | transformOrigin: {
558 | center: 'center',
559 | top: 'top',
560 | 'top-right': 'top right',
561 | right: 'right',
562 | 'bottom-right': 'bottom right',
563 | bottom: 'bottom',
564 | 'bottom-left': 'bottom left',
565 | left: 'left',
566 | 'top-left': 'top left',
567 | },
568 | scale: {
569 | '0': '0',
570 | '50': '.5',
571 | '75': '.75',
572 | '90': '.9',
573 | '95': '.95',
574 | '100': '1',
575 | '105': '1.05',
576 | '110': '1.1',
577 | '125': '1.25',
578 | '150': '1.5',
579 | },
580 | rotate: {
581 | '-180': '-180deg',
582 | '-90': '-90deg',
583 | '-45': '-45deg',
584 | '0': '0',
585 | '45': '45deg',
586 | '90': '90deg',
587 | '180': '180deg',
588 | },
589 | translate: (theme, { negative }) => ({
590 | ...theme('spacing'),
591 | ...negative(theme('spacing')),
592 | '-full': '-100%',
593 | '-1/2': '-50%',
594 | '1/2': '50%',
595 | full: '100%',
596 | }),
597 | skew: {
598 | '-12': '-12deg',
599 | '-6': '-6deg',
600 | '-3': '-3deg',
601 | '0': '0',
602 | '3': '3deg',
603 | '6': '6deg',
604 | '12': '12deg',
605 | },
606 | transitionProperty: {
607 | none: 'none',
608 | all: 'all',
609 | default:
610 | 'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform',
611 | colors: 'background-color, border-color, color, fill, stroke',
612 | opacity: 'opacity',
613 | shadow: 'box-shadow',
614 | transform: 'transform',
615 | },
616 | transitionTimingFunction: {
617 | linear: 'linear',
618 | in: 'cubic-bezier(0.4, 0, 1, 1)',
619 | out: 'cubic-bezier(0, 0, 0.2, 1)',
620 | 'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
621 | },
622 | transitionDuration: {
623 | '75': '75ms',
624 | '100': '100ms',
625 | '150': '150ms',
626 | '200': '200ms',
627 | '300': '300ms',
628 | '500': '500ms',
629 | '700': '700ms',
630 | '1000': '1000ms',
631 | },
632 | transitionDelay: {
633 | '75': '75ms',
634 | '100': '100ms',
635 | '150': '150ms',
636 | '200': '200ms',
637 | '300': '300ms',
638 | '500': '500ms',
639 | '700': '700ms',
640 | '1000': '1000ms',
641 | },
642 | animation: {
643 | none: 'none',
644 | spin: 'spin 1s linear infinite',
645 | ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
646 | pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
647 | bounce: 'bounce 1s infinite',
648 | },
649 | keyframes: {
650 | spin: {
651 | to: { transform: 'rotate(360deg)' },
652 | },
653 | ping: {
654 | '75%, 100%': { transform: 'scale(2)', opacity: '0' },
655 | },
656 | pulse: {
657 | '50%': { opacity: '.5' },
658 | },
659 | bounce: {
660 | '0%, 100%': {
661 | transform: 'translateY(-25%)',
662 | animationTimingFunction: 'cubic-bezier(0.8,0,1,1)',
663 | },
664 | '50%': {
665 | transform: 'none',
666 | animationTimingFunction: 'cubic-bezier(0,0,0.2,1)',
667 | },
668 | },
669 | },
670 | },
671 | variants: {
672 | accessibility: ['responsive', 'focus'],
673 | alignContent: ['responsive'],
674 | alignItems: ['responsive'],
675 | alignSelf: ['responsive'],
676 | appearance: ['responsive'],
677 | backgroundAttachment: ['responsive'],
678 | backgroundClip: ['responsive'],
679 | backgroundColor: ['responsive', 'hover', 'focus'],
680 | backgroundImage: ['responsive'],
681 | gradientColorStops: ['responsive', 'hover', 'focus'],
682 | backgroundOpacity: ['responsive', 'hover', 'focus'],
683 | backgroundPosition: ['responsive'],
684 | backgroundRepeat: ['responsive'],
685 | backgroundSize: ['responsive'],
686 | borderCollapse: ['responsive'],
687 | borderColor: ['responsive', 'hover', 'focus'],
688 | borderOpacity: ['responsive', 'hover', 'focus'],
689 | borderRadius: ['responsive'],
690 | borderStyle: ['responsive'],
691 | borderWidth: ['responsive'],
692 | boxShadow: ['responsive', 'hover', 'focus'],
693 | boxSizing: ['responsive'],
694 | container: ['responsive'],
695 | cursor: ['responsive'],
696 | display: ['responsive'],
697 | divideColor: ['responsive'],
698 | divideOpacity: ['responsive'],
699 | divideStyle: ['responsive'],
700 | divideWidth: ['responsive'],
701 | fill: ['responsive'],
702 | flex: ['responsive'],
703 | flexDirection: ['responsive'],
704 | flexGrow: ['responsive'],
705 | flexShrink: ['responsive'],
706 | flexWrap: ['responsive'],
707 | float: ['responsive'],
708 | clear: ['responsive'],
709 | fontFamily: ['responsive'],
710 | fontSize: ['responsive'],
711 | fontSmoothing: ['responsive'],
712 | fontVariantNumeric: ['responsive'],
713 | fontStyle: ['responsive'],
714 | fontWeight: ['responsive', 'hover', 'focus'],
715 | height: ['responsive'],
716 | inset: ['responsive'],
717 | justifyContent: ['responsive'],
718 | justifyItems: ['responsive'],
719 | justifySelf: ['responsive'],
720 | letterSpacing: ['responsive'],
721 | lineHeight: ['responsive'],
722 | listStylePosition: ['responsive'],
723 | listStyleType: ['responsive'],
724 | margin: ['responsive'],
725 | maxHeight: ['responsive'],
726 | maxWidth: ['responsive'],
727 | minHeight: ['responsive'],
728 | minWidth: ['responsive'],
729 | objectFit: ['responsive'],
730 | objectPosition: ['responsive'],
731 | opacity: ['responsive', 'hover', 'focus'],
732 | order: ['responsive'],
733 | outline: ['responsive', 'focus'],
734 | overflow: ['responsive'],
735 | overscrollBehavior: ['responsive'],
736 | padding: ['responsive'],
737 | placeContent: ['responsive'],
738 | placeItems: ['responsive'],
739 | placeSelf: ['responsive'],
740 | placeholderColor: ['responsive', 'focus'],
741 | placeholderOpacity: ['responsive', 'focus'],
742 | pointerEvents: ['responsive'],
743 | position: ['responsive'],
744 | resize: ['responsive'],
745 | space: ['responsive'],
746 | stroke: ['responsive'],
747 | strokeWidth: ['responsive'],
748 | tableLayout: ['responsive'],
749 | textAlign: ['responsive'],
750 | textColor: ['responsive', 'hover', 'focus'],
751 | textOpacity: ['responsive', 'hover', 'focus'],
752 | textDecoration: ['responsive', 'hover', 'focus'],
753 | textTransform: ['responsive'],
754 | userSelect: ['responsive'],
755 | verticalAlign: ['responsive'],
756 | visibility: ['responsive'],
757 | whitespace: ['responsive'],
758 | width: ['responsive'],
759 | wordBreak: ['responsive'],
760 | zIndex: ['responsive'],
761 | gap: ['responsive'],
762 | gridAutoFlow: ['responsive'],
763 | gridTemplateColumns: ['responsive'],
764 | gridColumn: ['responsive'],
765 | gridColumnStart: ['responsive'],
766 | gridColumnEnd: ['responsive'],
767 | gridTemplateRows: ['responsive'],
768 | gridRow: ['responsive'],
769 | gridRowStart: ['responsive'],
770 | gridRowEnd: ['responsive'],
771 | transform: ['responsive'],
772 | transformOrigin: ['responsive'],
773 | scale: ['responsive', 'hover', 'focus'],
774 | rotate: ['responsive', 'hover', 'focus'],
775 | translate: ['responsive', 'hover', 'focus'],
776 | skew: ['responsive', 'hover', 'focus'],
777 | transitionProperty: ['responsive'],
778 | transitionTimingFunction: ['responsive'],
779 | transitionDuration: ['responsive'],
780 | transitionDelay: ['responsive'],
781 | animation: ['responsive'],
782 | },
783 | corePlugins: {},
784 | plugins: [],
785 | }
786 |
--------------------------------------------------------------------------------
/demo/tailwind.config.js:
--------------------------------------------------------------------------------
1 | const defaultTheme = require('tailwindcss/defaultTheme')
2 |
3 | let tailwindcssCapsize
4 | try {
5 | tailwindcssCapsize = require('../src/index.js')
6 | } catch (e) {
7 | if (e instanceof Error && e.code === 'MODULE_NOT_FOUND') {
8 | tailwindcssCapsize = require('@themosaad/tailwindcss-capsize')
9 | } else throw e
10 | }
11 |
12 | module.exports = {
13 | purge: {
14 | enabled: true,
15 | content: ['./**/*.js'],
16 | // These options are passed through directly to PurgeCSS
17 | options: {
18 | safelist: [
19 | 'font-sans',
20 | 'font-source',
21 | 'font-ubuntu-mono',
22 | 'text-xs',
23 | 'text-sm',
24 | 'text-base',
25 | 'text-lg',
26 | 'text-xl',
27 | 'text-2xl',
28 | 'text-3xl',
29 | 'text-4xl',
30 | 'text-5xl',
31 | 'text-6xl',
32 | 'text-7xl',
33 | 'text-8xl',
34 | 'text-9xl',
35 | 'leading-3',
36 | 'leading-4',
37 | 'leading-5',
38 | 'leading-6',
39 | 'leading-7',
40 | 'leading-8',
41 | 'leading-9',
42 | 'leading-10',
43 | 'leading-none',
44 | 'leading-tight',
45 | 'leading-snug',
46 | 'leading-normal',
47 | 'leading-relaxed',
48 | 'leading-loose',
49 | 'cap-height-2',
50 | 'cap-height-2.5',
51 | 'cap-height-3',
52 | 'cap-height-3.5',
53 | 'cap-height-4',
54 | 'cap-height-5',
55 | 'cap-height-6',
56 | 'cap-height-7',
57 | 'cap-height-8',
58 | 'cap-height-9',
59 | 'cap-height-10',
60 | 'cap-height-11',
61 | 'cap-height-12',
62 | 'cap-height-13',
63 | 'cap-height-14',
64 | 'cap-height-15',
65 | 'line-gap-0',
66 | 'line-gap-2',
67 | 'line-gap-2.5',
68 | 'line-gap-3',
69 | 'line-gap-3.5',
70 | 'line-gap-4',
71 | 'line-gap-5',
72 | 'line-gap-6',
73 | 'line-gap-7',
74 | 'line-gap-8',
75 | 'line-gap-9',
76 | 'line-gap-10',
77 | 'line-gap-11',
78 | 'line-gap-12',
79 | ],
80 | },
81 | },
82 | theme: {
83 | fontFamily: {
84 | sans: ['Inter var', ...defaultTheme.fontFamily.sans],
85 | source: ['Source Sans Pro', ...defaultTheme.fontFamily.sans],
86 | 'ubuntu-mono': ['Ubuntu Mono', ...defaultTheme.fontFamily.mono],
87 | system: defaultTheme.fontFamily.sans,
88 | },
89 | capsize: {
90 | fontMetrics: {
91 | sans: {
92 | capHeight: 2048,
93 | ascent: 2728,
94 | descent: -680,
95 | lineGap: 0,
96 | unitsPerEm: 2816,
97 | },
98 | source: {
99 | capHeight: 710,
100 | ascent: 980,
101 | descent: -270,
102 | lineGap: 0,
103 | unitsPerEm: 1000,
104 | },
105 | 'ubuntu-mono': {
106 | capHeight: 693,
107 | ascent: 830,
108 | descent: -170,
109 | lineGap: 0,
110 | unitsPerEm: 1000,
111 | },
112 | },
113 | rootFontSizePx: {
114 | default: 16,
115 | sm: 18,
116 | lg: 20,
117 | },
118 | // rootLineHeightUnitless: 1.5,
119 | // rootLineGapUnitless: 0.5,
120 | // className: 'capsize',
121 | // keepPadding: true,
122 | },
123 | capHeight: {
124 | 2: ['0.5rem', { lineGap: '0.5rem' }],
125 | 2.5: ['0.625rem', { lineGap: '0.625rem' }],
126 | 3: ['0.75rem', { lineGap: '0.75rem' }],
127 | 3.5: ['0.875rem', { lineGap: '0.875rem' }],
128 | 4: ['1rem', { lineGap: '1rem' }],
129 | 5: ['1.25rem', { lineGap: '1.25rem' }],
130 | 6: ['1.5rem', { lineGap: '1.5rem' }],
131 | 7: ['1.75rem', { lineGap: '1.75rem' }],
132 | 8: ['2rem', { lineGap: '2rem' }],
133 | 9: ['2.25rem', { lineGap: '2.25rem' }],
134 | 10: ['2.5rem', { lineGap: '2.5rem' }],
135 | 11: ['2.75rem', { lineGap: '2.75rem' }],
136 | 12: ['3rem', { lineGap: '3rem' }],
137 | 13: ['3.25rem', { lineGap: '3.25rem' }],
138 | 14: ['3.5rem', { lineGap: '3.5rem' }],
139 | 15: ['3.75rem', { lineGap: '3.55rem' }],
140 | },
141 | lineGap: {
142 | 0: '0',
143 | 2: '0.5rem',
144 | 2.5: '0.625rem',
145 | 3: '0.75rem',
146 | 3.5: '0.875rem',
147 | 4: '1rem',
148 | 5: '1.25rem',
149 | 6: '1.5rem',
150 | 7: '1.75rem',
151 | 8: '2rem',
152 | 9: '2.25rem',
153 | 10: '2.5rem',
154 | 11: '2.75rem',
155 | 12: '3rem',
156 | },
157 | },
158 | variants: {},
159 | plugins: [tailwindcssCapsize],
160 | }
161 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@themosaad/tailwindcss-capsize",
3 | "version": "1.0.0",
4 | "description": "A Tailwind CSS plugin for trimming the whitespace above and below text nodes. This is a port of Capsize.",
5 | "main": "src/index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/theMosaad/tailwindcss-capsize.git"
9 | },
10 | "license": "MIT",
11 | "keywords": [
12 | "tailwindcss",
13 | "capsize",
14 | "leading trim",
15 | "leading",
16 | "typography",
17 | "baseline"
18 | ],
19 | "publishConfig": {
20 | "access": "public"
21 | },
22 | "author": "Mosaad (https://themosaad.com)",
23 | "scripts": {
24 | "release": "np"
25 | },
26 | "bugs": {
27 | "url": "https://github.com/theMosaad/tailwindcss-capsize/issues"
28 | },
29 | "homepage": "https://github.com/theMosaad/tailwindcss-capsize#readme",
30 | "dependencies": {
31 | "lodash": "^4.17.20"
32 | },
33 | "devDependencies": {
34 | "np": "^6.5.0",
35 | "tailwindcss": "^2.0.2"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | singleQuote: true,
4 | printWidth: 100,
5 | trailingComma: 'es5',
6 | arrowParens: 'always',
7 | tabWidth: 2,
8 | useTabs: false,
9 | quoteProps: 'as-needed',
10 | jsxSingleQuote: false,
11 | bracketSpacing: true,
12 | jsxBracketSameLine: false,
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | const plugin = require('tailwindcss/plugin')
2 | const _ = require('lodash')
3 |
4 | module.exports = plugin(
5 | function ({ addBase, addUtilities, e, theme, variants }) {
6 | const screens = theme('screens', {})
7 | const minWidths = extractMinWidths(screens)
8 | const rootSizes = mapMinWidthsToRootSize(
9 | minWidths,
10 | screens,
11 | theme('capsize.rootFontSizePx', { default: 16 })
12 | )
13 |
14 | const generateRootFontSizeFor = (minWidth) => {
15 | const fontSizeConfig = _.find(
16 | rootSizes,
17 | (rootSize) => `${rootSize.minWidth}` === `${minWidth}`
18 | )
19 |
20 | if (!fontSizeConfig || !fontSizeConfig.rootSize) {
21 | return {}
22 | }
23 |
24 | return {
25 | 'font-size': fontSizeConfig.rootSize + 'px',
26 | '--root-font-size-px': fontSizeConfig.rootSize.toString(),
27 | }
28 | }
29 | const atRules = _(minWidths)
30 | .sortBy((minWidth) => parseInt(minWidth))
31 | .sortedUniq()
32 | .map((minWidth) => {
33 | return {
34 | [`@media (min-width: ${minWidth})`]: {
35 | html: {
36 | ...generateRootFontSizeFor(minWidth),
37 | },
38 | },
39 | }
40 | })
41 | .value()
42 |
43 | addBase([
44 | {
45 | html: {
46 | ...generateRootFontSizeFor(0),
47 | 'line-height': theme('capsize.rootLineHeightUnitless', '1.5').toString(),
48 | '--line-height-unitless': theme('capsize.rootLineHeightUnitless', '1.5').toString(),
49 | '--line-gap-unitless': theme('capsize.rootLineGapUnitless', '0.5').toString(),
50 | ...(theme('capsize.keepPadding')
51 | ? {
52 | '--prevent-collapse': '0.05',
53 | }
54 | : {}),
55 | },
56 | },
57 | ...atRules,
58 | ])
59 |
60 | const capsizeContent = {
61 | ...(theme('capsize.keepPadding')
62 | ? {
63 | 'padding-top': 'calc(1px * var(--prevent-collapse))',
64 | 'padding-bottom': 'calc(1px * var(--prevent-collapse))',
65 | 'padding-right': '0',
66 | 'padding-left': '0',
67 | }
68 | : {}),
69 | '&::before': {
70 | content: '""',
71 | ...(theme('capsize.keepPadding')
72 | ? {
73 | display: 'block',
74 | height: '0',
75 | }
76 | : {
77 | display: 'table',
78 | }),
79 | '--line-height-normal': 'calc(var(--line-height-scale) * var(--font-size-px))',
80 | '--specified-line-height-offset-double':
81 | 'calc(var(--line-height-normal) - var(--line-height-px))',
82 | '--specified-line-height-offset': 'calc(var(--specified-line-height-offset-double) / 2 )',
83 | '--specified-line-height-offset-to-scale':
84 | 'calc(var(--specified-line-height-offset) / var(--font-size-px))',
85 | '--line-gap-scale-half': 'calc(var(--line-gap-scale) / 2)',
86 | ...(theme('capsize.keepPadding')
87 | ? {
88 | '--prevent-collapse-to-scale': 'calc(var(--prevent-collapse) / var(--font-size-px))',
89 | '--leading-trim-top':
90 | 'calc( var(--ascent-scale) - var(--cap-height-scale) + var(--line-gap-scale-half) - var(--specified-line-height-offset-to-scale) + var(--prevent-collapse-to-scale) )',
91 | 'margin-top': 'calc(-1em * var(--leading-trim-top))',
92 | }
93 | : {
94 | '--leading-trim-top':
95 | 'calc( var(--ascent-scale) - var(--cap-height-scale) + var(--line-gap-scale-half) - var(--specified-line-height-offset-to-scale) )',
96 | 'margin-bottom': 'calc(-1em * var(--leading-trim-top))',
97 | }),
98 | },
99 | '&::after': {
100 | content: '""',
101 | ...(theme('capsize.keepPadding')
102 | ? {
103 | display: 'block',
104 | height: '0',
105 | }
106 | : {
107 | display: 'table',
108 | }),
109 | '--line-height-normal': 'calc(var(--line-height-scale) * var(--font-size-px))',
110 | '--specified-line-height-offset-double':
111 | 'calc(var(--line-height-normal) - var(--line-height-px))',
112 | '--specified-line-height-offset': 'calc(var(--specified-line-height-offset-double) / 2 )',
113 | '--specified-line-height-offset-to-scale':
114 | 'calc(var(--specified-line-height-offset) / var(--font-size-px))',
115 | '--prevent-collapse-to-scale': 'calc(var(--prevent-collapse) / var(--font-size-px))',
116 | '--line-gap-scale-half': 'calc(var(--line-gap-scale) / 2)',
117 | ...(theme('capsize.keepPadding')
118 | ? {
119 | '--leading-trim-bottom':
120 | 'calc( var(--descent-scale) + var(--line-gap-scale-half) - var(--specified-line-height-offset-to-scale) + var(--prevent-collapse-to-scale) )',
121 | 'margin-bottom': 'calc(-1em * var(--leading-trim-bottom))',
122 | }
123 | : {
124 | '--leading-trim-bottom':
125 | 'calc( var(--descent-scale) + var(--line-gap-scale-half) - var(--specified-line-height-offset-to-scale) )',
126 | 'margin-top': 'calc(-1em * var(--leading-trim-bottom))',
127 | }),
128 | },
129 | }
130 |
131 | if (theme('capsize.className')) {
132 | const capsizeUtilities = {
133 | [`.${e(theme('capsize.className'))}`]: {
134 | ...capsizeContent,
135 | },
136 | }
137 |
138 | addUtilities(capsizeUtilities)
139 | }
140 |
141 | const fontFamilyUtilities = _.fromPairs(
142 | _.map(theme('fontFamily'), (value, modifier) => {
143 | return [
144 | `.${e(`font-${modifier}`)}`,
145 | {
146 | 'font-family': Array.isArray(value) ? value.join(', ') : value,
147 | ...(theme(`capsize.fontMetrics.${modifier}`)
148 | ? {
149 | '--cap-height': theme(`capsize.fontMetrics.${modifier}.capHeight`).toString(),
150 | '--ascent': theme(`capsize.fontMetrics.${modifier}.ascent`).toString(),
151 | '--descent': theme(`capsize.fontMetrics.${modifier}.descent`).toString(),
152 | '--line-gap': theme(`capsize.fontMetrics.${modifier}.lineGap`).toString(),
153 | '--units-per-em': theme(`capsize.fontMetrics.${modifier}.unitsPerEm`).toString(),
154 |
155 | '--absolute-descent': Math.abs(
156 | theme(`capsize.fontMetrics.${modifier}.descent`)
157 | ).toString(),
158 | '--cap-height-scale': (
159 | theme(`capsize.fontMetrics.${modifier}.capHeight`) /
160 | theme(`capsize.fontMetrics.${modifier}.unitsPerEm`)
161 | ).toString(),
162 | '--descent-scale': (
163 | Math.abs(theme(`capsize.fontMetrics.${modifier}.descent`)) /
164 | theme(`capsize.fontMetrics.${modifier}.unitsPerEm`)
165 | ).toString(),
166 | '--ascent-scale': (
167 | theme(`capsize.fontMetrics.${modifier}.ascent`) /
168 | theme(`capsize.fontMetrics.${modifier}.unitsPerEm`)
169 | ).toString(),
170 | '--line-gap-scale': (
171 | theme(`capsize.fontMetrics.${modifier}.lineGap`) /
172 | theme(`capsize.fontMetrics.${modifier}.unitsPerEm`)
173 | ).toString(),
174 | '--line-height-scale': (
175 | (theme(`capsize.fontMetrics.${modifier}.ascent`) +
176 | theme(`capsize.fontMetrics.${modifier}.lineGap`) +
177 | Math.abs(theme(`capsize.fontMetrics.${modifier}.descent`))) /
178 | theme(`capsize.fontMetrics.${modifier}.unitsPerEm`)
179 | ).toString(),
180 | }
181 | : {}),
182 | },
183 | ]
184 | })
185 | )
186 |
187 | addUtilities(fontFamilyUtilities, variants('fontFamily'))
188 |
189 | const fontSizeUtilities = _.fromPairs(
190 | _.map(theme('fontSize'), (value, modifier) => {
191 | const [fontSize, options] = Array.isArray(value) ? value : [value]
192 | const { lineHeight, letterSpacing } = _.isPlainObject(options)
193 | ? options
194 | : {
195 | lineHeight: options,
196 | }
197 |
198 | return [
199 | `.${e(`text-${modifier}`)}`,
200 | {
201 | 'font-size': fontSize,
202 | ...(fontSize.endsWith('rem')
203 | ? {
204 | '--font-size-rem': fontSize.replace('rem', ''),
205 | '--font-size-px': 'calc(var(--font-size-rem) * var(--root-font-size-px))',
206 | }
207 | : fontSize.endsWith('px')
208 | ? { '--font-size-px': fontSize.replace('px', '') }
209 | : {}),
210 | ...(lineHeight === undefined
211 | ? {
212 | '--line-height-px': 'calc(var(--line-height-unitless) * var(--font-size-px))',
213 | }
214 | : {
215 | 'line-height': lineHeight,
216 | ...(lineHeight.endsWith('rem')
217 | ? {
218 | '--line-height-rem': lineHeight.replace('rem', ''),
219 | '--line-height-px':
220 | 'calc(var(--line-height-rem) * var(--root-font-size-px))',
221 | }
222 | : lineHeight.endsWith('px')
223 | ? { '--line-height-px': lineHeight.replace('px', '') }
224 | : !isNaN(parseFloat(lineHeight)) && isFinite(lineHeight)
225 | ? {
226 | '--line-height-unitless': lineHeight,
227 | '--line-height-px':
228 | 'calc(var(--line-height-unitless) * var(--font-size-px))',
229 | }
230 | : {}),
231 | }),
232 | ...(theme('capsize.className') === undefined
233 | ? {
234 | ...capsizeContent,
235 | }
236 | : {}),
237 | ...(letterSpacing === undefined
238 | ? {}
239 | : {
240 | 'letter-spacing': letterSpacing,
241 | }),
242 | },
243 | ]
244 | })
245 | )
246 |
247 | addUtilities(fontSizeUtilities, variants('fontSize'))
248 |
249 | const capHeightUtilities = _.fromPairs(
250 | _.map(theme('capHeight'), (value, modifier) => {
251 | const [capHeight, options] = Array.isArray(value) ? value : [value]
252 | const { lineGap, letterSpacing } = _.isPlainObject(options)
253 | ? options
254 | : {
255 | lineGap: options,
256 | }
257 |
258 | return [
259 | `.${e(`cap-height-${modifier}`)}`,
260 | {
261 | 'font-size': 'calc(1px * var(--font-size-px))',
262 | ...(capHeight.endsWith('rem')
263 | ? {
264 | '--cap-height-rem': capHeight.replace('rem', ''),
265 | '--cap-height-px': 'calc(var(--cap-height-rem) * var(--root-font-size-px))',
266 | '--font-size-px': 'calc(var(--cap-height-px) / var(--cap-height-scale))',
267 | }
268 | : capHeight.endsWith('px')
269 | ? {
270 | '--cap-height-px': capHeight.replace('px', ''),
271 | '--font-size-px': 'calc(var(--cap-height-px) / var(--cap-height-scale))',
272 | }
273 | : {}),
274 | 'line-height': 'calc(1px * var(--line-height-px))',
275 | ...(lineGap === undefined
276 | ? {
277 | '--line-gap-px': 'calc(var(--cap-height-px) * var(--line-gap-unitless))',
278 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
279 | }
280 | : {
281 | ...(lineGap.endsWith('rem')
282 | ? {
283 | '--line-gap-rem': lineGap.replace('rem', ''),
284 | '--line-gap-px': 'calc(var(--line-gap-rem) * var(--root-font-size-px))',
285 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
286 | }
287 | : lineGap.endsWith('px')
288 | ? {
289 | '--line-gap-px': lineGap.replace('px', ''),
290 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
291 | }
292 | : !isNaN(parseFloat(lineGap)) && isFinite(lineGap)
293 | ? {
294 | '--line-gap-unitless': lineGap,
295 | '--line-gap-px': 'calc(var(--cap-height-px) * var(--line-gap-unitless))',
296 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
297 | }
298 | : {}),
299 | }),
300 | ...capsizeContent,
301 | },
302 | ]
303 | })
304 | )
305 |
306 | addUtilities(capHeightUtilities, variants('capHeight'))
307 |
308 | const lineHeightUtilities = _.fromPairs(
309 | _.map(theme('lineHeight'), (lineHeight, modifier) => {
310 | return [
311 | `.${e(`leading-${modifier}`)}`,
312 | {
313 | 'line-height': lineHeight,
314 | ...(lineHeight.endsWith('rem')
315 | ? {
316 | '--line-height-rem': lineHeight.replace('rem', ''),
317 | '--line-height-px': 'calc(var(--line-height-rem) * var(--root-font-size-px))',
318 | }
319 | : lineHeight.endsWith('px')
320 | ? { '--line-height-px': lineHeight.replace('px', '') }
321 | : !isNaN(parseFloat(lineHeight)) && isFinite(lineHeight)
322 | ? {
323 | '--line-height-unitless': lineHeight,
324 | '--line-height-px': 'calc(var(--line-height-unitless) * var(--font-size-px))',
325 | }
326 | : {}),
327 | },
328 | ]
329 | })
330 | )
331 |
332 | addUtilities(lineHeightUtilities, variants('lineHeight'))
333 |
334 | const lineGapUtilities = _.fromPairs(
335 | _.map(theme('lineGap'), (lineGap, modifier) => {
336 | return [
337 | `.${e(`line-gap-${modifier}`)}`,
338 | {
339 | 'line-height': 'calc(1px * var(--line-height-px))',
340 | ...(lineGap.endsWith('rem')
341 | ? {
342 | '--line-gap-rem': lineGap.replace('rem', ''),
343 | '--line-gap-px': 'calc(var(--line-gap-rem) * var(--root-font-size-px))',
344 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
345 | }
346 | : lineGap.endsWith('px')
347 | ? {
348 | '--line-gap-px': lineGap.replace('px', ''),
349 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
350 | }
351 | : !isNaN(parseFloat(lineGap)) && isFinite(lineGap)
352 | ? {
353 | '--line-gap-unitless': lineGap,
354 | '--line-gap-px': 'calc(var(--cap-height-px) * var(--line-gap-unitless))',
355 | '--line-height-px': 'calc(var(--cap-height-px) + var(--line-gap-px))',
356 | }
357 | : {}),
358 | },
359 | ]
360 | })
361 | )
362 |
363 | addUtilities(lineGapUtilities, variants('lineGap'))
364 | },
365 | {
366 | corePlugins: {
367 | fontFamily: false,
368 | fontSize: false,
369 | lineHeight: false,
370 | },
371 | variants: {
372 | capHeight: ['responsive'],
373 | lineGap: ['responsive'],
374 | },
375 | theme: {
376 | capHeight: {
377 | 2: ['0.5rem', { lineGap: '0.5rem' }],
378 | 2.5: ['0.625rem', { lineGap: '0.625rem' }],
379 | 3: ['0.75rem', { lineGap: '0.75rem' }],
380 | 3.5: ['0.875rem', { lineGap: '0.875rem' }],
381 | 4: ['1rem', { lineGap: '1rem' }],
382 | 5: ['1.25rem', { lineGap: '1.25rem' }],
383 | 6: ['1.5rem', { lineGap: '1.5rem' }],
384 | 7: ['1.75rem', { lineGap: '1.75rem' }],
385 | 8: ['2rem', { lineGap: '2rem' }],
386 | 9: ['2.25rem', { lineGap: '2.25rem' }],
387 | 10: ['2.5rem', { lineGap: '2.5rem' }],
388 | 11: ['2.75rem', { lineGap: '2.75rem' }],
389 | 12: ['3rem', { lineGap: '3rem' }],
390 | 13: ['3.25rem', { lineGap: '3.25rem' }],
391 | 14: ['3.5rem', { lineGap: '3.5rem' }],
392 | 15: ['3.75rem', { lineGap: '3.55rem' }],
393 | },
394 | lineGap: {
395 | 0: '0',
396 | 2: '0.5rem',
397 | 2.5: '0.625rem',
398 | 3: '0.75rem',
399 | 3.5: '0.875rem',
400 | 4: '1rem',
401 | 5: '1.25rem',
402 | 6: '1.5rem',
403 | 7: '1.75rem',
404 | 8: '2rem',
405 | 9: '2.25rem',
406 | 10: '2.5rem',
407 | 11: '2.75rem',
408 | 12: '3rem',
409 | },
410 | },
411 | }
412 | )
413 |
414 | function extractMinWidths(breakpoints) {
415 | return _.flatMap(breakpoints, (breakpoints) => {
416 | if (_.isString(breakpoints)) {
417 | breakpoints = { min: breakpoints }
418 | }
419 |
420 | if (!Array.isArray(breakpoints)) {
421 | breakpoints = [breakpoints]
422 | }
423 |
424 | return _(breakpoints)
425 | .filter((breakpoint) => {
426 | return _.has(breakpoint, 'min') || _.has(breakpoint, 'min-width')
427 | })
428 | .map((breakpoint) => {
429 | return _.get(breakpoint, 'min-width', breakpoint.min)
430 | })
431 | .value()
432 | })
433 | }
434 |
435 | function mapMinWidthsToRootSize(minWidths, screens, rootSizes) {
436 | if (typeof rootSizes === 'undefined') {
437 | return []
438 | }
439 |
440 | if (!_.isObject(rootSizes)) {
441 | return [
442 | {
443 | screen: 'default',
444 | minWidth: 0,
445 | rootSize: rootSizes,
446 | },
447 | ]
448 | }
449 |
450 | const mapping = []
451 |
452 | if (rootSizes.default) {
453 | mapping.push({
454 | screen: 'default',
455 | minWidth: 0,
456 | rootSize: rootSizes.default,
457 | })
458 | }
459 |
460 | _.each(minWidths, (minWidth) => {
461 | Object.keys(screens).forEach((screen) => {
462 | if (`${screens[screen]}` === `${minWidth}`) {
463 | mapping.push({
464 | screen,
465 | minWidth,
466 | rootSize: rootSizes[screen],
467 | })
468 | }
469 | })
470 | })
471 |
472 | return mapping
473 | }
474 |
--------------------------------------------------------------------------------