@unocss/transformer-directives 0.45.6 → 0.45.9

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
@@ -64,7 +64,7 @@ To use rules with `:`, you will need to quote the value
64
64
  }
65
65
  ```
66
66
 
67
- This feature is enabled by default (with prefix `--at-`), can you configure it or disable it via:
67
+ This feature is enabled by default (with prefix `--at-`), you can configure it or disable it via:
68
68
 
69
69
  ```js
70
70
  transformerDirective({
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.6",
3
+ "version": "0.45.9",
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.6",
35
- "css-tree": "^2.1.0"
34
+ "@unocss/core": "0.45.9",
35
+ "css-tree": "^2.2.1"
36
36
  },
37
37
  "devDependencies": {
38
38
  "magic-string": "^0.26.2"