tailwind-clamp 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tailwind clamp
2
2
 
3
- Tailwind CSS utilities & plugin to use CSS `clamp` in your project. Enabling fluid interfaces using Tailwind syntax.
3
+ Tailwind CSS plugin to use CSS `clamp` in your project. Enabling fluid interfaces using Tailwind syntax.
4
4
 
5
5
  The plugin is based on the formula presented in this [article](https://chriskirknielsen.com/blog/modern-fluid-typography-with-clamp/)
6
6
 
@@ -8,9 +8,9 @@ The plugin is based on the formula presented in this [article](https://chriskirk
8
8
 
9
9
  - Clamp values between a min and max viewport width, making it grow / shrink with the viewport.
10
10
  - Possibility to use small to large, large to small, negative to positive, positive to negative and negative to negative values. (Negative values only work on properties that allow them, e.g. `margin`)
11
- - Helper functions to simplify the definition of clamped values in your config.
12
- - Tailwind plugin to allow the usage of arbitrary values using the `clamp-[...]` syntax.
13
- - Values are interpreted as pixels and output as `rem`
11
+ - Supports `px`, `rem` and `em` units.
12
+ - Support `text` values with multiple properties (`fontSize`, `lineHeight`, `letterSpacing`).
13
+ - Support using defined in the Tailwind CSS configuration file, arbitrary values or a combination.
14
14
 
15
15
  ## Installation
16
16
 
@@ -20,107 +20,63 @@ Install the plugin from npm:
20
20
  npm install nicolas-cusan/tailwind-clamp
21
21
  ```
22
22
 
23
- ## Usage
24
-
25
- ### Predefine values in your config
26
-
27
- The package provides two helper functions to help you define "clamped" values in your config:
28
-
29
- #### `clamp(start, end, [minViewportWidth=375, maxViewportWidth=1440])`
30
-
31
- ##### Arguments
32
-
33
- - `start` `{number}`: Value at `minViewportWidth` viewport size. The value is interpreted as pixels and outputted as `rem` in the generated CSS.
34
- - `end` `{number}`: Value at `maxViewportWidth` viewport size. The value is interpreted as pixels and outputted as `rem` in the generated CSS.
35
- - `[minViewportWidth=375]` `{number}`: Viewport size, where the clamp starts, defaults to `375`. The value is interpreted as pixels. Value should be smaller than `maxViewportWidth`.
36
- - `[maxViewportWidth=1440]` `{number}`: Viewport size, where the clamp stops, defaults to `1440` The value is interpreted as pixels. Value should be smaller than `minViewportWidth`.
37
-
38
- #### `clampFs(start, end, [tracking=null, minViewportWidth=375, maxViewportWidth=1440])`
39
-
40
- ##### Arguments
41
-
42
- - `start` `{[fontSize: number, lineHeight: number]}`: Array of two numbers: `font-size` and `line-height` respectively at `minViewportWidth` viewport size. Both values are interpreted as pixels and outputted as `rem` in the generated CSS.
43
- - `end` `{[fontSize: number, lineHeight: number]}`: Array of two numbers: `font-size` and `line-height` respectively at `maxViewportWidth` viewport size. Both values are interpreted as pixels and outputted as `rem` in the generated CSS.
44
- - `[tracking=null]` `{string|null}`: `letter-spacing` setting, it is recommended to use the `em` unit as it proportional to the font size, e.g. `-0.01em`
45
- - `[minViewportWidth=375]` `{number}`: Viewport size, where the clamp starts, defaults to `375`. The value is interpreted as pixels. Value should be smaller than `maxViewportWidth`.
46
- - `[maxViewportWidth=1440]` `{number}`: Viewport size, where the clamp stops, defaults to `1440` The value is interpreted as pixels. Value should be smaller than `minViewportWidth`.
23
+ Add the plugin in your Tailwind CSS configuration file:
47
24
 
48
25
  ```js
49
26
  // tailwind.config.js
50
- const { setupClamp } = require('../src/utils.js');
51
-
52
- const clampOptions = {
53
- minViewportWidth: 375,
54
- maxViewportWidth: 1440,
55
- };
56
-
57
- // Setup the clamp helper functions with the default min and max viewport sizes you want to use
58
- const { clamp, clampFs } = setupClamp(options);
59
-
60
27
  module.exports = {
61
28
  theme: {
62
29
  // ...
63
- extend: {
64
- spacing: {
65
- // Use
66
- grid: clamp(10, 20),
67
- },
68
-
69
- fontSize: {
70
- base: clampFs([16, 20], [24, 28], '-0.01em'),
71
- },
72
- },
73
30
  },
74
- // ...
31
+ plugins: [
32
+ require('tailwind-clamp'),
33
+ // ...
34
+ ],
75
35
  };
76
36
  ```
77
37
 
78
- ### Use the plugin with `clamp-[...]`
38
+ ### Configuration
79
39
 
80
- The package also provides a plugin to use arbitrary values via the `clamp-[...]` syntax.
40
+ The plugin allows two configuration options:
41
+
42
+ | Name | Description | Default value |
43
+ | ------------------ | ------------------------------------ | ------------- |
44
+ | `minViewportWidth` | Viewport size where the clamp starts | `375` |
45
+ | `maxViewportWidth` | Viewport size where the clamp end | `1440` |
81
46
 
82
47
  ```js
83
48
  // tailwind.config.js
84
- const clampOptions = {
85
- minViewportWidth: 375,
86
- maxViewportWidth: 1440,
87
- };
88
-
89
49
  module.exports = {
90
50
  theme: {
91
51
  // ...
92
52
  },
93
53
  plugins: [
94
- require('tailwind-clamp')(clampOptions),
54
+ require('tailwind-clamp')({
55
+ minViewportWidth: 375,
56
+ maxViewportWidth: 1440,
57
+ }),
95
58
  // ...
96
59
  ],
97
60
  };
98
61
  ```
99
62
 
100
- #### Configuration
101
-
102
- This plugin allows two configuration options:
103
-
104
- | Name | Description | Default value |
105
- | ------------------ | ------------------------------------ | ------------- |
106
- | `minViewportWidth` | Viewport size where the clamp starts | `375` |
107
- | `maxViewportWidth` | Viewport size where the clamp end | `1440` |
108
-
109
- #### Using the plugin
63
+ ## Usage
110
64
 
111
- The arbitrary values syntax for clamp requires at least three arguments separated by commas without whitespace:
65
+ The plugin relies on the arbitrary values syntax `clamp-[...]`. You need to pass at least three arguments separated by commas without whitespace, optionally you can also pass the `minViewportWidth` and the `maxViewportWidth`:
112
66
 
113
- #### `clamp-[<property>,<start>,<end>,[minViewportWidth,maxViewportWidth]]`
67
+ ```
68
+ clamp-[<property>,<start>,<end>,[minViewportWidth,maxViewportWidth]]
69
+ ```
114
70
 
115
- ##### Arguments
71
+ ### Arguments
116
72
 
117
- - `property` `{string}`: Property that the value should be applied to. See a list of all supported properties below.
118
- - `start` `{number}`: Value at `minViewportWidth` viewport size. The value is interpreted as pixels and output as `rem` in the generated CSS.
119
- - `end` `{number}`: Value at `maxViewportWidth` viewport size. The value is interpreted as pixels and output as `rem` in the generated CSS.
120
- - `[minViewportWidth=375]` `{number}`: Viewport size, where the clamp starts, defaults to `375`. The value is interpreted as pixels. Value should be smaller than `maxViewportWidth`.
121
- - `[maxViewportWidth=1440]` `{number}`: Viewport size, where the clamp stops, defaults to `1440` The value is interpreted as pixels. Value should be smaller than `minViewportWidth`.
73
+ - `property`: Property that the value should be applied to. See a list of all supported properties below.
74
+ - `start`: Value at `minViewportWidth` viewport size. It can be a key from your Tailwind CSS config file, a css value (`px`, `rem`, `em`) or a number (unit will be `px`), the unit will need to match `end`.
75
+ - `end`: Value at `maxViewportWidth` viewport size. It can be a key from your Tailwind CSS config file, a css value (`px`, `rem`, `em`) or a number (unit will be `px`), the unit will need to match `start`.
76
+ - `[minViewportWidth=375]`: Viewport size, where the clamp starts, defaults to `375`. Can be a key from `screens` a css value (`px`, `rem`, `em`) or a number (unit will be `px`), the unit will need to match `maxViewportWidth`. Value needs be smaller than `maxViewportWidth`.
77
+ - `[maxViewportWidth=1440]`: Viewport size, where the clamp stops, defaults to `1440`. Can be a key from `screens` a css value (`px`, `rem`, `em`) or a number (unit will be `px`), the unit will need to match `minViewportWidth`. Value needs to be larger than `minViewportWidth`.
122
78
 
123
- ##### Example
79
+ ### Examples
124
80
 
125
81
  ```html
126
82
  <div class="clamp-[px,20,40] clamp-[py,10,18]">
@@ -137,7 +93,7 @@ The arbitrary values syntax for clamp requires at least three arguments separate
137
93
  - `left`
138
94
  - `right`
139
95
  - `bottom`
140
- - `text` applied to `font-size`.
96
+ - `text` including `font-size`, `line-height` and `letter-spacing` if defined.
141
97
  - `gap` including `gap-x`, `gap-y`.
142
98
  - `w`
143
99
  - `h`
@@ -157,6 +113,5 @@ The arbitrary values syntax for clamp requires at least three arguments separate
157
113
 
158
114
  ## Roadmap
159
115
 
160
- - Support other units e.g `%`
161
116
  - Support directional properties e.g. `ps`
162
117
  - Add showcase
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "tailwind-clamp",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Tailwind CSS plugin to use CSS clamp in your projects",
5
5
  "main": "src/index.js",
6
+ "type": "module",
6
7
  "scripts": {
7
8
  "dev": "next dev demo",
8
9
  "build": "next build demo",
@@ -25,13 +26,14 @@
25
26
  },
26
27
  "homepage": "https://github.com/nicolas-cusan/tailwind-clamp#readme",
27
28
  "dependencies": {
29
+ "chalk": "^5.3.0",
30
+ "next": "14.2.4",
28
31
  "react": "^18",
29
- "react-dom": "^18",
30
- "next": "14.1.4"
32
+ "react-dom": "^18"
31
33
  },
32
34
  "devDependencies": {
33
- "autoprefixer": "^10.0.1",
35
+ "autoprefixer": "^10.4.19",
34
36
  "postcss": "^8",
35
- "tailwindcss": "^3.3.0"
37
+ "tailwindcss": "^3.4.4"
36
38
  }
37
39
  }
package/src/clamp.js ADDED
@@ -0,0 +1,57 @@
1
+ // https://chriskirknielsen.com/blog/modern-fluid-typography-with-clamp/
2
+
3
+ export const clamp = (
4
+ _start,
5
+ _end,
6
+ _minvw = { number: 375, unit: 'px' },
7
+ _maxvw = { number: 1440, unit: 'px' }
8
+ ) => {
9
+ const unit = _start.unit;
10
+ const isPx = unit === 'px';
11
+
12
+ let start = _start.number;
13
+ let end = _end.number;
14
+ let negative = false;
15
+
16
+ let minvw = _minvw.number;
17
+ let maxvw = _maxvw.number;
18
+
19
+ if (_minvw.unit !== 'px' && isPx) {
20
+ minvw = _minvw.number * 16;
21
+ }
22
+
23
+ if (_minvw.unit === 'px' && !isPx) {
24
+ minvw = _minvw.number / 16;
25
+ }
26
+
27
+ if (_maxvw.unit !== 'px' && isPx) {
28
+ maxvw = _maxvw.number * 16;
29
+ }
30
+
31
+ if (_maxvw.unit === 'px' && !isPx) {
32
+ maxvw = _maxvw.number / 16;
33
+ }
34
+
35
+ if (end < start && start < 0 && end < 0) {
36
+ start = Math.abs(start);
37
+ end = Math.abs(end);
38
+ negative = true;
39
+ } else if (end < start && start > 0 && end > 0) {
40
+ start = start * -1;
41
+ end = end * -1;
42
+ negative = true;
43
+ } else if (end < start) {
44
+ start = Math.abs(start) * -1;
45
+ end = Math.abs(end);
46
+ negative = true;
47
+ }
48
+
49
+ const slope = (end - start) / (maxvw - minvw);
50
+ const calc = `${(start - minvw * slope).toFixed(6)}${unit} + ${(
51
+ 100 * slope
52
+ ).toFixed(6)}vw`;
53
+
54
+ const value = `clamp(${start}${unit}, ${calc}, ${end}${unit})`;
55
+
56
+ return negative ? `calc(${value} * -1)` : value;
57
+ };
package/src/index.js CHANGED
@@ -1,288 +1,92 @@
1
- const plugin = require('tailwindcss/plugin');
2
- const { clamp } = require('./utils.js');
1
+ import plugin from 'tailwindcss/plugin';
2
+ import { resolveProperty } from './resolve-property.js';
3
+ import { log } from './log.js';
4
+ import { parseValue, parseFontSizeValue, checkValues } from './parse-value.js';
5
+ import { clamp } from './clamp.js';
3
6
 
4
- let cssTransformValue = [
5
- 'translate(var(--tw-translate-x), var(--tw-translate-y))',
6
- 'rotate(var(--tw-rotate))',
7
- 'skewX(var(--tw-skew-x))',
8
- 'skewY(var(--tw-skew-y))',
9
- 'scaleX(var(--tw-scale-x))',
10
- 'scaleY(var(--tw-scale-y))',
11
- ].join(' ');
12
-
13
- function resolveProperty(property, value) {
14
- switch (property) {
15
- case 'p':
16
- return {
17
- padding: value,
18
- };
19
- case 'pt':
20
- return {
21
- paddingTop: value,
22
- };
23
- case 'pb':
24
- return {
25
- paddingBottom: value,
26
- };
27
- case 'pl':
28
- return {
29
- paddingLeft: value,
30
- };
31
- case 'pr':
32
- return {
33
- paddingRight: value,
34
- };
35
- case 'px':
36
- return {
37
- paddingLeft: value,
38
- paddingRight: value,
39
- };
40
- case 'py':
41
- return {
42
- paddingTop: value,
43
- paddingBottom: value,
44
- };
45
- case 'm':
46
- return {
47
- margin: value,
48
- };
49
- case 'mt':
50
- return {
51
- marginTop: value,
52
- };
53
- case 'mb':
54
- return {
55
- marginBottom: value,
56
- };
57
- case 'ml':
58
- return {
59
- marginLeft: value,
60
- };
61
- case 'mr':
62
- return {
63
- marginRight: value,
64
- };
65
- case 'mx':
66
- return {
67
- marginLeft: value,
68
- marginRight: value,
69
- };
70
- case 'my':
71
- return {
72
- marginTop: value,
73
- marginBottom: value,
74
- };
75
- case 'inset':
76
- return {
77
- top: value,
78
- left: value,
79
- right: value,
80
- bottom: value,
81
- };
82
- case 'top':
83
- return {
84
- top: value,
85
- };
86
- case 'left':
87
- return {
88
- left: value,
89
- };
90
- case 'right':
91
- return {
92
- right: value,
93
- };
94
- case 'bottom':
95
- return {
96
- bottom: value,
97
- };
98
- case 'text':
99
- return {
100
- fontSize: value,
101
- };
102
- case 'gap':
103
- return {
104
- gap: value,
105
- };
106
- case 'gap-x':
107
- return {
108
- columnGap: value,
109
- };
110
- case 'gap-y':
111
- return {
112
- rowGap: value,
113
- };
114
- case 'w':
115
- return {
116
- width: value,
117
- };
118
- case 'h':
119
- return {
120
- height: value,
121
- };
122
- case 'size':
123
- return {
124
- width: value,
125
- height: value,
126
- };
127
- case 'min-w':
128
- return {
129
- minWidth: value,
130
- };
131
- case 'min-h':
132
- return {
133
- minHeight: value,
134
- };
135
- case 'max-w':
136
- return {
137
- maxWidth: value,
138
- };
139
- case 'max-h':
140
- return {
141
- maxHeight: value,
142
- };
143
- case 'rounded':
144
- return {
145
- borderRadius: value,
146
- };
147
- case 'rounded-t':
148
- return {
149
- borderTopLeftRadius: value,
150
- borderTopRightRadius: value,
151
- };
152
- case 'rounded-r':
153
- return {
154
- borderTopRightRadius: value,
155
- borderBottomRightRadius: value,
156
- };
157
- case 'rounded-b':
158
- return {
159
- borderBottomLeftRadius: value,
160
- borderBottomRightRadius: value,
161
- };
162
- case 'rounded-l':
163
- return {
164
- borderTopLeftRadius: value,
165
- borderBottomLeftRadius: value,
166
- };
167
- case 'rounded-tl':
168
- return {
169
- borderTopLeftRadius: value,
170
- };
171
- case 'rounded-tr':
172
- return {
173
- borderTopRightRadius: value,
174
- };
175
- case 'rounded-bl':
176
- return {
177
- borderBottomLeftRadius: value,
178
- };
179
- case 'rounded-br':
180
- return {
181
- borderBottomRightRadius: value,
182
- };
183
- case 'translate-x':
184
- return {
185
- '--tw-translate-x': value,
186
- '@defaults transform': {},
187
- transform: cssTransformValue,
188
- };
189
- case 'translate-y':
190
- return {
191
- '--tw-translate-y': value,
192
- '@defaults transform': {},
193
- transform: cssTransformValue,
194
- };
195
- case 'text-stroke':
196
- return {
197
- '-webkit-text-stroke': value,
198
- textStroke: value,
199
- };
200
- case 'stroke':
201
- return {
202
- strokeWidth: value,
203
- };
204
- case 'leading':
205
- return {
206
- lineHeight: value,
207
- };
208
- case 'border':
209
- return {
210
- borderWidth: value,
211
- };
212
- case 'border-t':
213
- return {
214
- borderTopWidth: value,
215
- };
216
- case 'border-b':
217
- return {
218
- borderBottomWidth: value,
219
- };
220
- case 'border-l':
221
- return {
222
- borderLeftWidth: value,
223
- };
224
- case 'border-r':
225
- return {
226
- borderRightWidth: value,
227
- };
228
- case 'border-x':
229
- return {
230
- borderLeftWidth: value,
231
- borderRightWidth: value,
232
- };
233
- case 'border-y':
234
- return {
235
- borderTopWidth: value,
236
- borderBottomWidth: value,
237
- };
238
- case 'scroll-m':
239
- return {
240
- scrollMargin: value,
241
- };
242
- default:
243
- return null;
244
- }
245
- }
246
-
247
- module.exports = plugin.withOptions(function (
7
+ export default plugin.withOptions(function (
248
8
  options = {
249
9
  minViewportWidth: 375,
250
10
  maxViewportWidth: 1440,
251
11
  }
252
12
  ) {
253
- return function ({ matchUtilities, theme }) {
13
+ return function ({ matchUtilities, theme, config }) {
254
14
  matchUtilities(
255
15
  {
256
16
  clamp: (value) => {
257
- const props = value.split(',');
258
- props[1] = parseFloat(props[1]);
259
- props[2] = parseFloat(props[2]);
17
+ const args = value.split(',');
18
+
19
+ const minvw = parseValue(
20
+ config().theme.screens[args[3]] ||
21
+ args[3] ||
22
+ `${options.minViewportWidth}`
23
+ );
260
24
 
261
- if (props.length < 3) {
262
- throw new Error('The clamp utility requires at least 3 arguments.');
25
+ const maxvw = parseValue(
26
+ config().theme.screens[args[4]] ||
27
+ args[4] ||
28
+ `${options.maxViewportWidth}`
29
+ );
30
+
31
+ if (args.length < 3) {
32
+ log.error(
33
+ `The clamp utility requires at least 3 arguments: "clamp-[${value}]".`
34
+ );
35
+ return null;
263
36
  }
264
37
 
265
- if (typeof props[1] !== 'number' || typeof props[2] !== 'number') {
266
- throw new Error(
267
- 'The clamp utility requires that the second and third arguments are numbers representing a pixel value.'
38
+ const resolvedProp = resolveProperty(args[0]);
39
+
40
+ if (!resolvedProp) {
41
+ log.error(
42
+ `Property "${args[0]}" is not supported: "clamp-[${value}]".`
268
43
  );
44
+ return null;
269
45
  }
270
46
 
271
- const prop = resolveProperty(
272
- props[0],
273
- clamp(
274
- props[1],
275
- props[2],
276
- props[3] || options.minViewportWidth,
277
- props[4] || options.maxViewportWidth
278
- )
279
- );
47
+ const { key, props } = resolvedProp;
280
48
 
281
- if (prop === null) {
282
- throw new Error(`Property "${props[0]}" is not supported.`);
49
+ // handle fontSize separately
50
+ if (key === 'fontSize') {
51
+ const start = parseFontSizeValue(
52
+ config().theme[key][args[1]] || args[1]
53
+ );
54
+ const end = parseFontSizeValue(
55
+ config().theme[key][args[2]] || args[2]
56
+ );
57
+
58
+ const css = {};
59
+
60
+ Object.keys(start).forEach((k) => {
61
+ if (k in end && checkValues(start[k], end[k], value, k)) {
62
+ const val = clamp(start[k], end[k], minvw, maxvw);
63
+ css[k] = val;
64
+ }
65
+ });
66
+
67
+ return Object.keys(css).length > 0 ? css : null;
283
68
  }
284
69
 
285
- return prop;
70
+ // handle other properties
71
+ const start = parseValue(config().theme[key][args[1]] || args[1]);
72
+ const end = parseValue(config().theme[key][args[2]] || args[2]);
73
+
74
+ if (!checkValues(start, end, value)) {
75
+ return null;
76
+ }
77
+
78
+ const val = clamp(start, end, minvw, maxvw);
79
+
80
+ const css = props.reduce((acc, prop) => {
81
+ if (typeof prop === 'string') {
82
+ acc[prop] = val;
83
+ } else {
84
+ acc = { ...acc, ...prop };
85
+ }
86
+ return acc;
87
+ }, {});
88
+
89
+ return css;
286
90
  },
287
91
  },
288
92
  { values: theme('clamp') }
package/src/log.js ADDED
@@ -0,0 +1,16 @@
1
+ import chalk from 'chalk';
2
+
3
+ export const log = {
4
+ error() {
5
+ console.log(chalk.red(...arguments));
6
+ },
7
+ warn() {
8
+ console.log(chalk.yellow(...arguments));
9
+ },
10
+ info() {
11
+ console.log(chalk.blue(...arguments));
12
+ },
13
+ log() {
14
+ console.log(chalk.gray(...arguments));
15
+ },
16
+ };
@@ -0,0 +1,66 @@
1
+ import { log } from './log.js';
2
+
3
+ export const parseValue = (value) => {
4
+ const number = parseFloat(value);
5
+ let unit = 'unsupported';
6
+
7
+ if (/^\d+$/.test(value)) {
8
+ unit = 'px';
9
+ }
10
+
11
+ const match = value.match(/px|rem|em/);
12
+ if (match) {
13
+ unit = match[0];
14
+ }
15
+
16
+ return { number, unit };
17
+ };
18
+
19
+ export const parseFontSizeValue = (value) => {
20
+ const values = {};
21
+ if (typeof value === 'string') {
22
+ values.fontSize = parseValue(value);
23
+ } else if (Array.isArray(value)) {
24
+ values.fontSize = parseValue(value[0]);
25
+ if (typeof value[1] === 'string') {
26
+ values.lineHeight = parseValue(value[1]);
27
+ } else if (typeof value[1] === 'object') {
28
+ if ('lineHeight' in value[1]) {
29
+ values.lineHeight = parseValue(value[1].lineHeight);
30
+ }
31
+ if ('letterSpacing' in value[1]) {
32
+ values.letterSpacing = parseValue(value[1].letterSpacing);
33
+ }
34
+ }
35
+ }
36
+ return values;
37
+ };
38
+
39
+ export const checkValues = (start, end, value, prop = null) => {
40
+ if (start.number === end.number) {
41
+ log.error(
42
+ `Same value for start an end${
43
+ prop ? ` (${prop})` : ''
44
+ }: "clamp-[${value}]".`
45
+ );
46
+ return null;
47
+ }
48
+
49
+ if (start.unit !== end.unit) {
50
+ log.error(
51
+ `Units need to match${prop ? ` (${prop})` : ''}: "clamp-[${value}]".`
52
+ );
53
+ return null;
54
+ }
55
+
56
+ if (start.unit === 'unsupported' || end.unit === 'unsupported') {
57
+ log.error(
58
+ `Only px, rem and em units are supported${
59
+ prop ? ` (${prop})` : ''
60
+ }: "clamp-[${value}]".`
61
+ );
62
+ return null;
63
+ }
64
+
65
+ return true;
66
+ };
@@ -0,0 +1,302 @@
1
+ const cssTransformValue = [
2
+ 'translate(var(--tw-translate-x), var(--tw-translate-y))',
3
+ 'rotate(var(--tw-rotate))',
4
+ 'skewX(var(--tw-skew-x))',
5
+ 'skewY(var(--tw-skew-y))',
6
+ 'scaleX(var(--tw-scale-x))',
7
+ 'scaleY(var(--tw-scale-y))',
8
+ ].join(' ');
9
+
10
+ export const resolveProperty = (name) => {
11
+ switch (name) {
12
+ case 'p':
13
+ return {
14
+ key: 'padding',
15
+ props: ['padding'],
16
+ };
17
+ case 'pt':
18
+ return {
19
+ key: 'padding',
20
+ props: ['paddingTop'],
21
+ };
22
+ case 'pb':
23
+ return {
24
+ key: 'padding',
25
+ props: ['paddingBottom'],
26
+ };
27
+ case 'pl':
28
+ return {
29
+ key: 'padding',
30
+ props: ['paddingLeft'],
31
+ };
32
+ case 'pr':
33
+ return {
34
+ key: 'padding',
35
+ props: ['paddingRight'],
36
+ };
37
+ case 'px':
38
+ return {
39
+ key: 'padding',
40
+ props: ['paddingLeft', 'paddingRight'],
41
+ };
42
+ case 'py':
43
+ return {
44
+ key: 'padding',
45
+ props: ['paddingTop', 'paddingBottom'],
46
+ };
47
+ case 'm':
48
+ return {
49
+ key: 'margin',
50
+ props: ['margin'],
51
+ };
52
+ case 'mt':
53
+ return {
54
+ key: 'margin',
55
+ props: ['marginTop'],
56
+ };
57
+ case 'mb':
58
+ return {
59
+ key: 'margin',
60
+ props: ['marginBottom'],
61
+ };
62
+ case 'ml':
63
+ return {
64
+ key: 'margin',
65
+ props: ['marginLeft'],
66
+ };
67
+ case 'mr':
68
+ return {
69
+ key: 'margin',
70
+ props: ['marginRight'],
71
+ };
72
+ case 'mx':
73
+ return {
74
+ key: 'margin',
75
+ props: ['marginLeft', 'marginRight'],
76
+ };
77
+ case 'my':
78
+ return {
79
+ key: 'margin',
80
+ props: ['marginTop', 'marginBottom'],
81
+ };
82
+ case 'inset':
83
+ return {
84
+ key: 'inset',
85
+ props: ['top', 'left', 'right', 'bottom'],
86
+ };
87
+ case 'top':
88
+ return {
89
+ key: 'inset',
90
+ props: ['top'],
91
+ };
92
+
93
+ case 'left':
94
+ return {
95
+ key: 'inset',
96
+ props: ['left'],
97
+ };
98
+ case 'right':
99
+ return {
100
+ key: 'inset',
101
+ props: ['right'],
102
+ };
103
+ case 'bottom':
104
+ return {
105
+ key: 'inset',
106
+ props: ['bottom'],
107
+ };
108
+ case 'text':
109
+ return {
110
+ key: 'fontSize',
111
+ props: ['fontSize'],
112
+ };
113
+ case 'gap':
114
+ return {
115
+ key: 'gap',
116
+ props: ['gap'],
117
+ };
118
+ case 'gap-x':
119
+ return {
120
+ key: 'gap',
121
+ props: ['columnGap'],
122
+ };
123
+ case 'gap-y':
124
+ return {
125
+ key: 'gap',
126
+ props: ['rowGap'],
127
+ };
128
+ case 'w':
129
+ return {
130
+ key: 'width',
131
+ props: ['width'],
132
+ };
133
+ case 'h':
134
+ return {
135
+ key: 'height',
136
+ props: ['height'],
137
+ };
138
+ case 'size':
139
+ return {
140
+ key: 'size',
141
+ props: ['width', 'height'],
142
+ };
143
+
144
+ case 'min-w':
145
+ return {
146
+ key: 'minWidth',
147
+ props: ['minWidth'],
148
+ };
149
+
150
+ case 'min-h':
151
+ return {
152
+ key: 'minHeight',
153
+ props: ['minHeight'],
154
+ };
155
+
156
+ case 'max-w':
157
+ return {
158
+ key: 'maxWidth',
159
+ props: ['maxWidth'],
160
+ };
161
+
162
+ case 'max-h':
163
+ return {
164
+ key: 'maxHeight',
165
+ props: ['maxHeight'],
166
+ };
167
+
168
+ case 'rounded':
169
+ return {
170
+ key: 'borderRadius',
171
+ props: ['borderRadius'],
172
+ };
173
+
174
+ case 'rounded-t':
175
+ return {
176
+ key: 'borderRadius',
177
+ props: ['borderTopLeftRadius', 'borderTopRightRadius'],
178
+ };
179
+
180
+ case 'rounded-r':
181
+ return {
182
+ key: 'borderRadius',
183
+ props: ['borderTopRightRadius', 'borderBottomRightRadius'],
184
+ };
185
+
186
+ case 'rounded-b':
187
+ return {
188
+ key: 'borderRadius',
189
+ props: ['borderBottomLeftRadius', 'borderBottomRightRadius'],
190
+ };
191
+
192
+ case 'rounded-l':
193
+ return {
194
+ key: 'borderRadius',
195
+ props: ['borderTopLeftRadius', 'borderBottomLeftRadius'],
196
+ };
197
+
198
+ case 'rounded-tl':
199
+ return {
200
+ key: 'borderRadius',
201
+ props: ['borderTopLeftRadius'],
202
+ };
203
+
204
+ case 'rounded-tr':
205
+ return {
206
+ key: 'borderRadius',
207
+ props: ['borderTopRightRadius'],
208
+ };
209
+
210
+ case 'rounded-bl':
211
+ return {
212
+ key: 'borderRadius',
213
+ props: ['borderBottomLeftRadius'],
214
+ };
215
+
216
+ case 'rounded-br':
217
+ return {
218
+ key: 'borderRadius',
219
+ props: ['borderBottomRightRadius'],
220
+ };
221
+
222
+ case 'translate-x':
223
+ return {
224
+ key: 'translate',
225
+ props: [
226
+ '--tw-translate-x',
227
+ { '@defaults transform': {} },
228
+ { transform: cssTransformValue },
229
+ ],
230
+ };
231
+
232
+ case 'translate-y':
233
+ return {
234
+ key: 'translate',
235
+ props: [
236
+ '--tw-translate-y',
237
+ { '@defaults transform': {} },
238
+ { transform: cssTransformValue },
239
+ ],
240
+ };
241
+ case 'stroke':
242
+ return {
243
+ key: 'strokeWidth',
244
+ props: ['strokeWidth'],
245
+ };
246
+
247
+ case 'leading':
248
+ return {
249
+ key: 'lineHeight',
250
+ props: ['lineHeight'],
251
+ };
252
+
253
+ case 'border':
254
+ return {
255
+ key: 'borderWidth',
256
+ props: ['borderWidth'],
257
+ };
258
+ case 'border-t':
259
+ return {
260
+ key: 'borderWidth',
261
+ props: ['borderTopWidth'],
262
+ };
263
+ case 'border-b':
264
+ return {
265
+ key: 'borderWidth',
266
+ props: ['borderBottomWidth'],
267
+ };
268
+
269
+ case 'border-l':
270
+ return {
271
+ key: 'borderWidth',
272
+ props: ['borderLeftWidth'],
273
+ };
274
+
275
+ case 'border-r':
276
+ return {
277
+ key: 'borderWidth',
278
+ props: ['borderRightWidth'],
279
+ };
280
+
281
+ case 'border-x':
282
+ return {
283
+ key: 'borderWidth',
284
+ props: ['borderLeftWidth', 'borderRightWidth'],
285
+ };
286
+
287
+ case 'border-y':
288
+ return {
289
+ key: 'borderWidth',
290
+ props: ['borderTopWidth', 'borderBottomWidth'],
291
+ };
292
+
293
+ case 'scroll-m':
294
+ return {
295
+ key: 'scrollMargin',
296
+ props: ['scrollMargin'],
297
+ };
298
+
299
+ default:
300
+ return null;
301
+ }
302
+ };
package/src/utils.js DELETED
@@ -1,82 +0,0 @@
1
- // https://chriskirknielsen.com/blog/modern-fluid-typography-with-clamp/
2
-
3
- const clamp = (_start, _end, minvw = 375, maxvw = 1440) => {
4
- let start = _start;
5
- let end = _end;
6
- let negative = false;
7
-
8
- if (_end < _start && _start < 0 && _end < 0) {
9
- start = Math.abs(_start);
10
- end = Math.abs(_end);
11
- negative = true;
12
- } else if (_end < _start && _start > 0 && _end > 0) {
13
- start = _start * -1;
14
- end = _end * -1;
15
- negative = true;
16
- } else if (_end < _start) {
17
- start = Math.abs(_start) * -1;
18
- end = Math.abs(_end);
19
- negative = true;
20
- }
21
-
22
- const rem = (px) => `${px / 16}rem`;
23
- const factor = (1 / (maxvw - minvw)) * (end - start);
24
- const calc = `${rem(start - minvw * factor)} + ${100 * factor}vw`;
25
-
26
- const value = `clamp(${rem(start)}, ${calc}, ${rem(end)})`;
27
-
28
- return negative ? `calc(${value} * -1)` : value;
29
- };
30
-
31
- const clampFs = (start, end, tracking = null, minvw = 375, maxvw = 1440) => {
32
- const [startFs, startLh] = start;
33
- const [endFs, endLh] = end;
34
-
35
- const sameLh =
36
- (startFs == startLh && endFs === endLh) ||
37
- startLh / startFs === endLh / endFs;
38
-
39
- const settings = [
40
- clamp(startFs, endFs, minvw, maxvw),
41
- {
42
- lineHeight: sameLh
43
- ? startLh / startFs
44
- : clamp(startLh, endLh, minvw, maxvw),
45
- },
46
- ];
47
-
48
- if (tracking) {
49
- settings[1].letterSpacing = tracking;
50
- }
51
-
52
- return settings;
53
- };
54
-
55
- const setupClamp = (
56
- options = {
57
- minViewportWidth: 375,
58
- maxViewportWidth: 1440,
59
- }
60
- ) => {
61
- return {
62
- clamp: (
63
- start,
64
- end,
65
- minvw = options.minViewportWidth,
66
- maxvw = options.maxViewportWidth
67
- ) => clamp(start, end, minvw, maxvw),
68
- clampFs: (
69
- start,
70
- end,
71
- tracking = null,
72
- minvw = options.minViewportWidth,
73
- maxvw = options.maxViewportWidth
74
- ) => clampFs(start, end, tracking, minvw, maxvw),
75
- };
76
- };
77
-
78
- module.exports = {
79
- clamp,
80
- clampFs,
81
- setupClamp,
82
- };