tailwind-clamp 1.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/LICENSE +21 -0
- package/README.md +162 -0
- package/package.json +37 -0
- package/src/index.js +291 -0
- package/src/utils.js +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Nicolas Cusan
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Tailwind clamp
|
|
2
|
+
|
|
3
|
+
Tailwind CSS utilities & plugin to use CSS `clamp` in your project. Enabling fluid interfaces using Tailwind syntax.
|
|
4
|
+
|
|
5
|
+
The plugin is based on the formula presented in this [article](https://chriskirknielsen.com/blog/modern-fluid-typography-with-clamp/)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Clamp values between a min and max viewport width, making it grow / shrink with the viewport.
|
|
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`
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Install the plugin from npm:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install nicolas-cusan/tailwind-clamp
|
|
21
|
+
```
|
|
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`.
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// 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
|
+
module.exports = {
|
|
61
|
+
theme: {
|
|
62
|
+
// ...
|
|
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
|
+
},
|
|
74
|
+
// ...
|
|
75
|
+
};
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Use the plugin with `clamp-[...]`
|
|
79
|
+
|
|
80
|
+
The package also provides a plugin to use arbitrary values via the `clamp-[...]` syntax.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
// tailwind.config.js
|
|
84
|
+
const clampOptions = {
|
|
85
|
+
minViewportWidth: 375,
|
|
86
|
+
maxViewportWidth: 1440,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
theme: {
|
|
91
|
+
// ...
|
|
92
|
+
},
|
|
93
|
+
plugins: [
|
|
94
|
+
require('tailwind-clamp')(clampOptions),
|
|
95
|
+
// ...
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
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
|
|
110
|
+
|
|
111
|
+
The arbitrary values syntax for clamp requires at least three arguments separated by commas without whitespace:
|
|
112
|
+
|
|
113
|
+
#### `clamp-[<property>,<start>,<end>,[minViewportWidth,maxViewportWidth]]`
|
|
114
|
+
|
|
115
|
+
##### Arguments
|
|
116
|
+
|
|
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`.
|
|
122
|
+
|
|
123
|
+
##### Example
|
|
124
|
+
|
|
125
|
+
```html
|
|
126
|
+
<div class="clamp-[px,20,40] clamp-[py,10,18]">
|
|
127
|
+
Add some fluid padding here.
|
|
128
|
+
</div>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
##### Supported properties
|
|
132
|
+
|
|
133
|
+
- `p` including `pt`, `pb`, `pl`, `pr`, `px`, `py`.
|
|
134
|
+
- `m` including `mt`, `mb`, `ml`, `mr`, `mx`, `my`.
|
|
135
|
+
- `inset`
|
|
136
|
+
- `top`
|
|
137
|
+
- `left`
|
|
138
|
+
- `right`
|
|
139
|
+
- `bottom`
|
|
140
|
+
- `text` applied to `font-size`.
|
|
141
|
+
- `gap` including `gap-x`, `gap-y`.
|
|
142
|
+
- `w`
|
|
143
|
+
- `h`
|
|
144
|
+
- `size`
|
|
145
|
+
- `min-w`
|
|
146
|
+
- `min-h`
|
|
147
|
+
- `max-w`
|
|
148
|
+
- `max-h`
|
|
149
|
+
- `rounded` including `rounded-t`, `rounded-r`, `rounded-b`, `rounded-l`, `rounded-tl`, `rounded-tr`, `rounded-bl`, `rounded-br`.
|
|
150
|
+
- `translate-x`
|
|
151
|
+
- `translate-y`
|
|
152
|
+
- `text-stroke`
|
|
153
|
+
- `stroke`
|
|
154
|
+
- `leading`
|
|
155
|
+
- `border` including `border-t`, `border-b`, `border-l`, `border-r`, `border-x`, `border-y`.
|
|
156
|
+
- `scroll-m`
|
|
157
|
+
|
|
158
|
+
## Roadmap
|
|
159
|
+
|
|
160
|
+
- Support other units e.g `%`
|
|
161
|
+
- Support directional properties e.g. `ps`
|
|
162
|
+
- Add showcase
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tailwind-clamp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Tailwind CSS plugin to use CSS clamp in your projects",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev demo",
|
|
8
|
+
"build": "next build demo",
|
|
9
|
+
"start": "next start demo",
|
|
10
|
+
"lint": "next lint demo"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/nicolas-cusan/tailwind-clamp.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"tailwind",
|
|
18
|
+
"css",
|
|
19
|
+
"clamp"
|
|
20
|
+
],
|
|
21
|
+
"author": "Nicolas Cusan",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/nicolas-cusan/tailwind-clamp/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/nicolas-cusan/tailwind-clamp#readme",
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"react": "^18",
|
|
29
|
+
"react-dom": "^18",
|
|
30
|
+
"next": "14.1.4"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"autoprefixer": "^10.0.1",
|
|
34
|
+
"postcss": "^8",
|
|
35
|
+
"tailwindcss": "^3.3.0"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
const plugin = require('tailwindcss/plugin');
|
|
2
|
+
const { clamp } = require('./utils.js');
|
|
3
|
+
|
|
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 (
|
|
248
|
+
options = {
|
|
249
|
+
minViewportWidth: 375,
|
|
250
|
+
maxViewportWidth: 1440,
|
|
251
|
+
}
|
|
252
|
+
) {
|
|
253
|
+
return function ({ matchUtilities, theme }) {
|
|
254
|
+
matchUtilities(
|
|
255
|
+
{
|
|
256
|
+
clamp: (value) => {
|
|
257
|
+
const props = value.split(',');
|
|
258
|
+
props[1] = parseFloat(props[1]);
|
|
259
|
+
props[2] = parseFloat(props[2]);
|
|
260
|
+
|
|
261
|
+
if (props.length < 3) {
|
|
262
|
+
throw new Error('The clamp utility requires at least 3 arguments.');
|
|
263
|
+
}
|
|
264
|
+
|
|
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.'
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
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
|
+
);
|
|
280
|
+
|
|
281
|
+
if (prop === null) {
|
|
282
|
+
throw new Error(`Property "${props[0]}" is not supported.`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return prop;
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
{ values: theme('clamp') }
|
|
289
|
+
);
|
|
290
|
+
};
|
|
291
|
+
});
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
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
|
+
};
|