@unocss/transformer-directives 0.45.8 → 0.45.13
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 +134 -3
- package/dist/index.cjs +59 -1
- package/dist/index.mjs +59 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- @unocss-ignore -->
|
|
4
4
|
|
|
5
|
-
UnoCSS transformer for `@apply` and `theme()` directive
|
|
5
|
+
UnoCSS transformer for `@apply`、`@screen` and `theme()` directive
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -44,8 +44,6 @@ Will be transformed to:
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
> Currently only `@apply` is supported.
|
|
48
|
-
|
|
49
47
|
#### CSS Variable Style
|
|
50
48
|
|
|
51
49
|
To be compatible with vanilla CSS, you can use CSS Variables to replace the `@apply` directive.
|
|
@@ -74,6 +72,139 @@ transformerDirective({
|
|
|
74
72
|
})
|
|
75
73
|
```
|
|
76
74
|
|
|
75
|
+
### `@screen`
|
|
76
|
+
|
|
77
|
+
The `@screen` directive allows you to create media queries that reference your breakpoints by name comes from [`theme.breakpoints`](https://github.com/unocss/unocss/blob/main/README.md#extend-theme).
|
|
78
|
+
|
|
79
|
+
```css
|
|
80
|
+
.grid {
|
|
81
|
+
@apply grid grid-cols-2;
|
|
82
|
+
}
|
|
83
|
+
@screen xs {
|
|
84
|
+
.grid {
|
|
85
|
+
@apply grid-cols-1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
@screen sm {
|
|
89
|
+
.grid {
|
|
90
|
+
@apply grid-cols-3;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/* ... */
|
|
94
|
+
...
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Will be transformed to:
|
|
98
|
+
|
|
99
|
+
```css
|
|
100
|
+
.grid {
|
|
101
|
+
display: grid;
|
|
102
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
103
|
+
}
|
|
104
|
+
@media (min-width: 320px) {
|
|
105
|
+
.grid {
|
|
106
|
+
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
@media (min-width: 640px) {
|
|
110
|
+
.grid {
|
|
111
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/* ... */
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Breakpoint Variant Support
|
|
118
|
+
`@screen` also supports `lt`、`at` variants
|
|
119
|
+
|
|
120
|
+
##### `@screen lt`
|
|
121
|
+
|
|
122
|
+
```css
|
|
123
|
+
.grid {
|
|
124
|
+
@apply grid grid-cols-2;
|
|
125
|
+
}
|
|
126
|
+
@screen lt-xs {
|
|
127
|
+
.grid {
|
|
128
|
+
@apply grid-cols-1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
@screen lt-sm {
|
|
132
|
+
.grid {
|
|
133
|
+
@apply grid-cols-3;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/* ... */
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Will be transformed to:
|
|
140
|
+
|
|
141
|
+
```css
|
|
142
|
+
.grid {
|
|
143
|
+
display: grid;
|
|
144
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
145
|
+
}
|
|
146
|
+
@media (max-width: 319.9px) {
|
|
147
|
+
.grid {
|
|
148
|
+
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
@media (max-width: 639.9px) {
|
|
152
|
+
.grid {
|
|
153
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/* ... */
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
##### `@screen at`
|
|
160
|
+
|
|
161
|
+
```css
|
|
162
|
+
.grid {
|
|
163
|
+
@apply grid grid-cols-2;
|
|
164
|
+
}
|
|
165
|
+
@screen at-xs {
|
|
166
|
+
.grid {
|
|
167
|
+
@apply grid-cols-1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
@screen at-xl {
|
|
171
|
+
.grid {
|
|
172
|
+
@apply grid-cols-3;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
@screen at-xxl {
|
|
176
|
+
.grid {
|
|
177
|
+
@apply grid-cols-4;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/* ... */
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Will be transformed to:
|
|
184
|
+
|
|
185
|
+
```css
|
|
186
|
+
.grid {
|
|
187
|
+
display: grid;
|
|
188
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
189
|
+
}
|
|
190
|
+
@media (min-width: 320px) and (max-width: 639.9px) {
|
|
191
|
+
.grid {
|
|
192
|
+
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
@media (min-width: 1280px) and (max-width: 1535.9px) {
|
|
196
|
+
.grid {
|
|
197
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
@media (min-width: 1536px) {
|
|
201
|
+
.grid {
|
|
202
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/* ... */
|
|
206
|
+
```
|
|
207
|
+
|
|
77
208
|
### `theme()`
|
|
78
209
|
|
|
79
210
|
Use the `theme()` function to access your theme config values using dot notation.
|
package/dist/index.cjs
CHANGED
|
@@ -16,14 +16,16 @@ function transformerDirectives(options = {}) {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
const themeFnRE = /theme\((.*?)\)/g;
|
|
19
|
+
const screenRuleRE = /(@screen) (.+) /g;
|
|
19
20
|
async function transformDirectives(code, uno, options, filename, originalCode, offset) {
|
|
20
21
|
const {
|
|
21
22
|
varStyle = "--at-",
|
|
22
23
|
throwOnMissing = true
|
|
23
24
|
} = options;
|
|
24
25
|
const isApply = code.original.includes("@apply") || varStyle !== false && code.original.includes(varStyle);
|
|
26
|
+
const isScreen = code.original.includes("@screen");
|
|
25
27
|
const hasThemeFn = code.original.match(themeFnRE);
|
|
26
|
-
if (!isApply && !hasThemeFn)
|
|
28
|
+
if (!isApply && !hasThemeFn && !isScreen)
|
|
27
29
|
return;
|
|
28
30
|
const ast = cssTree.parse(originalCode || code.original, {
|
|
29
31
|
parseAtrulePrelude: false,
|
|
@@ -123,8 +125,58 @@ async function transformDirectives(code, uno, options, filename, originalCode, o
|
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
127
|
};
|
|
128
|
+
const handleScreen = (node) => {
|
|
129
|
+
let breakpointName = "";
|
|
130
|
+
let prefix;
|
|
131
|
+
if (node.name === "screen" && node.prelude?.type === "Raw")
|
|
132
|
+
breakpointName = node.prelude.value.trim();
|
|
133
|
+
if (!breakpointName)
|
|
134
|
+
return;
|
|
135
|
+
const match = breakpointName.match(/^(?:(lt|at)-)?(\w+)$/);
|
|
136
|
+
if (match) {
|
|
137
|
+
prefix = match[1];
|
|
138
|
+
breakpointName = match[2];
|
|
139
|
+
}
|
|
140
|
+
const resolveBreakpoints = () => {
|
|
141
|
+
let breakpoints;
|
|
142
|
+
if (uno.userConfig && uno.userConfig.theme)
|
|
143
|
+
breakpoints = uno.userConfig.theme.breakpoints;
|
|
144
|
+
if (!breakpoints)
|
|
145
|
+
breakpoints = uno.config.theme.breakpoints;
|
|
146
|
+
return breakpoints;
|
|
147
|
+
};
|
|
148
|
+
const variantEntries = Object.entries(resolveBreakpoints() ?? {}).map(([point, size], idx) => [point, size, idx]);
|
|
149
|
+
const generateMediaQuery = (breakpointName2, prefix2) => {
|
|
150
|
+
const [, size, idx] = variantEntries.find((i) => i[0] === breakpointName2);
|
|
151
|
+
if (prefix2) {
|
|
152
|
+
if (prefix2 === "lt")
|
|
153
|
+
return `@media (max-width: ${calcMaxWidthBySize(size)})`;
|
|
154
|
+
else if (prefix2 === "at")
|
|
155
|
+
return `@media (min-width: ${size})${variantEntries[idx + 1] ? ` and (max-width: ${calcMaxWidthBySize(variantEntries[idx + 1][1])})` : ""}`;
|
|
156
|
+
else
|
|
157
|
+
throw new Error(`breakpoint variant not surpported: ${prefix2}`);
|
|
158
|
+
}
|
|
159
|
+
return `@media (min-width: ${size})`;
|
|
160
|
+
};
|
|
161
|
+
if (!variantEntries.find((i) => i[0] === breakpointName))
|
|
162
|
+
throw new Error(`breakpoint ${breakpointName} not found`);
|
|
163
|
+
const offset2 = node.loc.start.offset;
|
|
164
|
+
const str = code.original.slice(offset2, node.loc.end.offset);
|
|
165
|
+
const matches = Array.from(str.matchAll(screenRuleRE));
|
|
166
|
+
if (!matches.length)
|
|
167
|
+
return;
|
|
168
|
+
for (const match2 of matches) {
|
|
169
|
+
code.overwrite(
|
|
170
|
+
offset2 + match2.index,
|
|
171
|
+
offset2 + match2.index + match2[0].length,
|
|
172
|
+
`${generateMediaQuery(breakpointName, prefix)} `
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
126
176
|
const stack = [];
|
|
127
177
|
const processNode = async (node, _item, _list) => {
|
|
178
|
+
if (isScreen && node.type === "Atrule")
|
|
179
|
+
handleScreen(node);
|
|
128
180
|
if (hasThemeFn && node.type === "Declaration")
|
|
129
181
|
handleThemeFn(node);
|
|
130
182
|
if (isApply && node.type === "Rule") {
|
|
@@ -140,6 +192,12 @@ async function transformDirectives(code, uno, options, filename, originalCode, o
|
|
|
140
192
|
cssTree.walk(ast, (...args) => stack.push(processNode(...args)));
|
|
141
193
|
await Promise.all(stack);
|
|
142
194
|
}
|
|
195
|
+
function calcMaxWidthBySize(size) {
|
|
196
|
+
const value = size.match(/^-?[0-9]+\.?[0-9]*/)?.[0] || "";
|
|
197
|
+
const unit = size.slice(value.length);
|
|
198
|
+
const maxWidth = parseFloat(value) - 0.1;
|
|
199
|
+
return Number.isNaN(maxWidth) ? size : `${maxWidth}${unit}`;
|
|
200
|
+
}
|
|
143
201
|
|
|
144
202
|
exports["default"] = transformerDirectives;
|
|
145
203
|
exports.transformDirectives = transformDirectives;
|
package/dist/index.mjs
CHANGED
|
@@ -12,14 +12,16 @@ function transformerDirectives(options = {}) {
|
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
const themeFnRE = /theme\((.*?)\)/g;
|
|
15
|
+
const screenRuleRE = /(@screen) (.+) /g;
|
|
15
16
|
async function transformDirectives(code, uno, options, filename, originalCode, offset) {
|
|
16
17
|
const {
|
|
17
18
|
varStyle = "--at-",
|
|
18
19
|
throwOnMissing = true
|
|
19
20
|
} = options;
|
|
20
21
|
const isApply = code.original.includes("@apply") || varStyle !== false && code.original.includes(varStyle);
|
|
22
|
+
const isScreen = code.original.includes("@screen");
|
|
21
23
|
const hasThemeFn = code.original.match(themeFnRE);
|
|
22
|
-
if (!isApply && !hasThemeFn)
|
|
24
|
+
if (!isApply && !hasThemeFn && !isScreen)
|
|
23
25
|
return;
|
|
24
26
|
const ast = parse(originalCode || code.original, {
|
|
25
27
|
parseAtrulePrelude: false,
|
|
@@ -119,8 +121,58 @@ async function transformDirectives(code, uno, options, filename, originalCode, o
|
|
|
119
121
|
}
|
|
120
122
|
}
|
|
121
123
|
};
|
|
124
|
+
const handleScreen = (node) => {
|
|
125
|
+
let breakpointName = "";
|
|
126
|
+
let prefix;
|
|
127
|
+
if (node.name === "screen" && node.prelude?.type === "Raw")
|
|
128
|
+
breakpointName = node.prelude.value.trim();
|
|
129
|
+
if (!breakpointName)
|
|
130
|
+
return;
|
|
131
|
+
const match = breakpointName.match(/^(?:(lt|at)-)?(\w+)$/);
|
|
132
|
+
if (match) {
|
|
133
|
+
prefix = match[1];
|
|
134
|
+
breakpointName = match[2];
|
|
135
|
+
}
|
|
136
|
+
const resolveBreakpoints = () => {
|
|
137
|
+
let breakpoints;
|
|
138
|
+
if (uno.userConfig && uno.userConfig.theme)
|
|
139
|
+
breakpoints = uno.userConfig.theme.breakpoints;
|
|
140
|
+
if (!breakpoints)
|
|
141
|
+
breakpoints = uno.config.theme.breakpoints;
|
|
142
|
+
return breakpoints;
|
|
143
|
+
};
|
|
144
|
+
const variantEntries = Object.entries(resolveBreakpoints() ?? {}).map(([point, size], idx) => [point, size, idx]);
|
|
145
|
+
const generateMediaQuery = (breakpointName2, prefix2) => {
|
|
146
|
+
const [, size, idx] = variantEntries.find((i) => i[0] === breakpointName2);
|
|
147
|
+
if (prefix2) {
|
|
148
|
+
if (prefix2 === "lt")
|
|
149
|
+
return `@media (max-width: ${calcMaxWidthBySize(size)})`;
|
|
150
|
+
else if (prefix2 === "at")
|
|
151
|
+
return `@media (min-width: ${size})${variantEntries[idx + 1] ? ` and (max-width: ${calcMaxWidthBySize(variantEntries[idx + 1][1])})` : ""}`;
|
|
152
|
+
else
|
|
153
|
+
throw new Error(`breakpoint variant not surpported: ${prefix2}`);
|
|
154
|
+
}
|
|
155
|
+
return `@media (min-width: ${size})`;
|
|
156
|
+
};
|
|
157
|
+
if (!variantEntries.find((i) => i[0] === breakpointName))
|
|
158
|
+
throw new Error(`breakpoint ${breakpointName} not found`);
|
|
159
|
+
const offset2 = node.loc.start.offset;
|
|
160
|
+
const str = code.original.slice(offset2, node.loc.end.offset);
|
|
161
|
+
const matches = Array.from(str.matchAll(screenRuleRE));
|
|
162
|
+
if (!matches.length)
|
|
163
|
+
return;
|
|
164
|
+
for (const match2 of matches) {
|
|
165
|
+
code.overwrite(
|
|
166
|
+
offset2 + match2.index,
|
|
167
|
+
offset2 + match2.index + match2[0].length,
|
|
168
|
+
`${generateMediaQuery(breakpointName, prefix)} `
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
122
172
|
const stack = [];
|
|
123
173
|
const processNode = async (node, _item, _list) => {
|
|
174
|
+
if (isScreen && node.type === "Atrule")
|
|
175
|
+
handleScreen(node);
|
|
124
176
|
if (hasThemeFn && node.type === "Declaration")
|
|
125
177
|
handleThemeFn(node);
|
|
126
178
|
if (isApply && node.type === "Rule") {
|
|
@@ -136,5 +188,11 @@ async function transformDirectives(code, uno, options, filename, originalCode, o
|
|
|
136
188
|
walk(ast, (...args) => stack.push(processNode(...args)));
|
|
137
189
|
await Promise.all(stack);
|
|
138
190
|
}
|
|
191
|
+
function calcMaxWidthBySize(size) {
|
|
192
|
+
const value = size.match(/^-?[0-9]+\.?[0-9]*/)?.[0] || "";
|
|
193
|
+
const unit = size.slice(value.length);
|
|
194
|
+
const maxWidth = parseFloat(value) - 0.1;
|
|
195
|
+
return Number.isNaN(maxWidth) ? size : `${maxWidth}${unit}`;
|
|
196
|
+
}
|
|
139
197
|
|
|
140
198
|
export { transformerDirectives as default, transformDirectives };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unocss/transformer-directives",
|
|
3
|
-
"version": "0.45.
|
|
3
|
+
"version": "0.45.13",
|
|
4
4
|
"description": "UnoCSS transformer for `@apply` directive",
|
|
5
5
|
"author": "hannoeru <me@hanlee.co>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"dist"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@unocss/core": "0.45.
|
|
35
|
-
"css-tree": "^2.1
|
|
34
|
+
"@unocss/core": "0.45.13",
|
|
35
|
+
"css-tree": "^2.2.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"magic-string": "^0.26.2"
|