next-yak 0.0.30 → 0.0.32
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/dist/runtime-internals/index.cjs +2 -0
- package/dist/runtime-internals/index.cjs.map +1 -0
- package/dist/runtime-internals/index.js +2 -0
- package/dist/runtime-internals/index.js.map +1 -0
- package/loaders/__tests__/cssloader.test.ts +54 -0
- package/loaders/__tests__/tsloader.test.ts +143 -2
- package/loaders/babel-yak-plugin.cjs +37 -7
- package/loaders/cssloader.cjs +45 -25
- package/loaders/lib/appendCssUnitToExpressionValue.cjs +51 -0
- package/loaders/tsloader.cjs +3 -2
- package/package.json +6 -1
- package/runtime/internals/index.ts +1 -0
- package/runtime/internals/unitPostFix.tsx +16 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var s=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var e=Object.prototype.hasOwnProperty;var p=(o,t)=>{for(var i in t)s(o,i,{get:t[i],enumerable:!0})},u=(o,t,i,x)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of y(t))!e.call(o,n)&&n!==i&&s(o,n,{get:()=>t[n],enumerable:!(x=r(t,n))||x.enumerable});return o};var F=o=>u(s({},"__esModule",{value:!0}),o);var P={};p(P,{__yak_unitPostFix:()=>a});module.exports=F(P);var a=(o,t)=>typeof o=="function"?(...i)=>o(...i)+t:o+t;0&&(module.exports={__yak_unitPostFix});
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../runtime/internals/index.ts","../../runtime/internals/unitPostFix.tsx"],"sourcesContent":["export { unitPostFix as __yak_unitPostFix } from \"./unitPostFix.js\";\n","/**\n * Takes a function and a css unit and returns the result of the function concatenated with the unit\n *\n * @usage\n *\n * ```tsx\n * import { styled, atoms } from \"next-yak\";\n *\n * const Button = styled.button<{ $primary?: boolean }>`\n * ${atoms(\"text-teal-600\", \"text-base\", \"rounded-md\")}\n * ${props => props.$primary && atoms(\"shadow-md\")}\n * `;\n * ```\n */\nexport const unitPostFix = (fn: any, unit: string) =>\n typeof fn === \"function\" ? (...args: any[]) => fn(...args) + unit : fn + unit;\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,uBAAAE,IAAA,eAAAC,EAAAH,GCcO,IAAMI,EAAc,CAACC,EAASC,IACnC,OAAOD,GAAO,WAAa,IAAIE,IAAgBF,EAAG,GAAGE,CAAI,EAAID,EAAOD,EAAKC","names":["internals_exports","__export","unitPostFix","__toCommonJS","unitPostFix","fn","unit","args"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../runtime/internals/unitPostFix.tsx"],"sourcesContent":["/**\n * Takes a function and a css unit and returns the result of the function concatenated with the unit\n *\n * @usage\n *\n * ```tsx\n * import { styled, atoms } from \"next-yak\";\n *\n * const Button = styled.button<{ $primary?: boolean }>`\n * ${atoms(\"text-teal-600\", \"text-base\", \"rounded-md\")}\n * ${props => props.$primary && atoms(\"shadow-md\")}\n * `;\n * ```\n */\nexport const unitPostFix = (fn: any, unit: string) =>\n typeof fn === \"function\" ? (...args: any[]) => fn(...args) + unit : fn + unit;\n"],"mappings":"AAcO,IAAMA,EAAc,CAACC,EAASC,IACnC,OAAOD,GAAO,WAAa,IAAIE,IAAgBF,EAAG,GAAGE,CAAI,EAAID,EAAOD,EAAKC","names":["unitPostFix","fn","unit","args"]}
|
|
@@ -649,4 +649,58 @@ const headline = css\`
|
|
|
649
649
|
}"
|
|
650
650
|
`);
|
|
651
651
|
});
|
|
652
|
+
|
|
653
|
+
it("should detect expressions with units automatically in arrow function expressions", async () => {
|
|
654
|
+
expect(
|
|
655
|
+
await cssloader.call(
|
|
656
|
+
loaderContext,
|
|
657
|
+
`
|
|
658
|
+
import styles from "./page.module.css";
|
|
659
|
+
import { css } from "next-yak";
|
|
660
|
+
const case3 = css\`
|
|
661
|
+
padding: \${({$indent}) => {
|
|
662
|
+
if ($indent > 4) return 10;
|
|
663
|
+
return $indent
|
|
664
|
+
}}px;
|
|
665
|
+
transform: translate(-50%, -50%) rotate(\${({ index }) => index * 30}deg);
|
|
666
|
+
translate(0, -88px) rotate(\${({ index }) => -index * 30}deg);
|
|
667
|
+
\`
|
|
668
|
+
`
|
|
669
|
+
)
|
|
670
|
+
).toMatchInlineSnapshot(`
|
|
671
|
+
".case3_0 {
|
|
672
|
+
padding: var(--🦬18fi82j0);
|
|
673
|
+
transform: translate(-50%, -50%) rotate(var(--🦬18fi82j1));
|
|
674
|
+
translate(0, -88px) rotate(var(--🦬18fi82j2));
|
|
675
|
+
}"
|
|
676
|
+
`);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
it("should detect expressions with units automatically in edge cases", async () => {
|
|
680
|
+
expect(
|
|
681
|
+
await cssloader.call(
|
|
682
|
+
loaderContext,
|
|
683
|
+
`
|
|
684
|
+
import styles from "./page.module.css";
|
|
685
|
+
import { css } from "next-yak";
|
|
686
|
+
const value = 10;
|
|
687
|
+
const case3 = css\`
|
|
688
|
+
margin: \${size}px;
|
|
689
|
+
top: \${spacing.xs}px;
|
|
690
|
+
bottom: \${spacing[0]}PX;
|
|
691
|
+
left: \${spacing()}px;
|
|
692
|
+
right: \${value}px;
|
|
693
|
+
\`
|
|
694
|
+
`
|
|
695
|
+
)
|
|
696
|
+
).toMatchInlineSnapshot(`
|
|
697
|
+
".case3_0 {
|
|
698
|
+
margin: var(--🦬18fi82j0);
|
|
699
|
+
top: var(--🦬18fi82j1);
|
|
700
|
+
bottom: var(--🦬18fi82j2);
|
|
701
|
+
left: var(--🦬18fi82j3);
|
|
702
|
+
right: 10px;
|
|
703
|
+
}"
|
|
704
|
+
`);
|
|
705
|
+
});
|
|
652
706
|
});
|
|
@@ -271,7 +271,7 @@ const fadeIn = keyframes\`
|
|
|
271
271
|
\`
|
|
272
272
|
|
|
273
273
|
const FadeInButton = styled.button\`
|
|
274
|
-
animation: 1s \${() => fadeIn} ease-out;
|
|
274
|
+
animation: 1s \${() => fadeIn} ease-out 1s infinite reverse both paused slidein;
|
|
275
275
|
\`
|
|
276
276
|
`
|
|
277
277
|
)
|
|
@@ -482,7 +482,7 @@ const headline = css\`
|
|
|
482
482
|
const red = \\"#E50914\\";
|
|
483
483
|
const zIndex = 14;
|
|
484
484
|
const headline = css(__styleYak.headline_0);"
|
|
485
|
-
`)
|
|
485
|
+
`);
|
|
486
486
|
});
|
|
487
487
|
|
|
488
488
|
it("should show error when using a runtime value from top level", async () => {
|
|
@@ -779,4 +779,145 @@ const Button = styled.button\`
|
|
|
779
779
|
}) => $primary && css(__styleYak.primary_0));"
|
|
780
780
|
`);
|
|
781
781
|
});
|
|
782
|
+
|
|
783
|
+
it("should detect expressions with units and correctly append them in the css variable value", async () => {
|
|
784
|
+
expect(
|
|
785
|
+
await tsloader.call(
|
|
786
|
+
loaderContext,
|
|
787
|
+
`
|
|
788
|
+
import styles from "./page.module.css";
|
|
789
|
+
import { styled } from "next-yak";
|
|
790
|
+
const Button = styled.button\`
|
|
791
|
+
padding: \${10}rem;
|
|
792
|
+
margin: \${4 * 2}px;
|
|
793
|
+
z-index: \${10 + 4};
|
|
794
|
+
transform: translateX(\${10}px) translateY(\${10 / 2}px);
|
|
795
|
+
font-family: "Arial", sans-serif;
|
|
796
|
+
\`;
|
|
797
|
+
|
|
798
|
+
`
|
|
799
|
+
)
|
|
800
|
+
).toMatchInlineSnapshot(`
|
|
801
|
+
"import styles from \\"./page.module.css\\";
|
|
802
|
+
import { styled } from \\"next-yak\\";
|
|
803
|
+
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
804
|
+
const Button = styled.button(__styleYak.Button, {
|
|
805
|
+
\\"style\\": {
|
|
806
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j0\\": 10 + \\"rem\\",
|
|
807
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j1\\": 4 * 2 + \\"px\\",
|
|
808
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j2\\": 10 + 4,
|
|
809
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j3\\": 10 + \\"px\\",
|
|
810
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j4\\": 10 / 2 + \\"px\\"
|
|
811
|
+
}
|
|
812
|
+
});"
|
|
813
|
+
`);
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
it("should detect expressions with units in simple arrow functions", async () => {
|
|
817
|
+
expect(
|
|
818
|
+
await tsloader.call(
|
|
819
|
+
loaderContext,
|
|
820
|
+
`
|
|
821
|
+
import styles from "./page.module.css";
|
|
822
|
+
import { styled } from "next-yak";
|
|
823
|
+
const ClockNumber = styled.div<{ index: number; children: ReactNode }>\`
|
|
824
|
+
transform: translate(-50%, -50%) rotate(\${({ index }) => index * 30}deg)
|
|
825
|
+
translate(0, -88px) rotate(\${({ index }) => -index * 30}deg);
|
|
826
|
+
\`;
|
|
827
|
+
`
|
|
828
|
+
)
|
|
829
|
+
).toMatchInlineSnapshot(`
|
|
830
|
+
"import styles from \\"./page.module.css\\";
|
|
831
|
+
import { styled } from \\"next-yak\\";
|
|
832
|
+
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
833
|
+
const ClockNumber = styled.div(__styleYak.ClockNumber, {
|
|
834
|
+
\\"style\\": {
|
|
835
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j0\\": ({
|
|
836
|
+
index
|
|
837
|
+
}) => (index * 30) + \\"deg\\",
|
|
838
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j1\\": ({
|
|
839
|
+
index
|
|
840
|
+
}) => (-index * 30) + \\"deg\\"
|
|
841
|
+
}
|
|
842
|
+
});"
|
|
843
|
+
`);
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
it("should detect expressions with units in complex arrow functions and wrap them with __yak_unitPostFix helper", async () => {
|
|
847
|
+
expect(
|
|
848
|
+
await tsloader.call(
|
|
849
|
+
loaderContext,
|
|
850
|
+
`
|
|
851
|
+
import styles from "./page.module.css";
|
|
852
|
+
import { css } from "next-yak";
|
|
853
|
+
const case1 = css\`
|
|
854
|
+
padding: \${({$indent}) => {
|
|
855
|
+
if ($indent > 0) {
|
|
856
|
+
return $indent * 3;
|
|
857
|
+
}
|
|
858
|
+
return 0;
|
|
859
|
+
}}px;
|
|
860
|
+
\`;
|
|
861
|
+
|
|
862
|
+
`
|
|
863
|
+
)
|
|
864
|
+
).toMatchInlineSnapshot(`
|
|
865
|
+
"import styles from \\"./page.module.css\\";
|
|
866
|
+
import { css } from \\"next-yak\\";
|
|
867
|
+
import { __yak_unitPostFix } from \\"next-yak/runtime-internals\\";
|
|
868
|
+
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
869
|
+
const case1 = css(__styleYak.case1_0, {
|
|
870
|
+
\\"style\\": {
|
|
871
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j0\\": __yak_unitPostFix(({
|
|
872
|
+
$indent
|
|
873
|
+
}) => {
|
|
874
|
+
if ($indent > 0) {
|
|
875
|
+
return $indent * 3;
|
|
876
|
+
}
|
|
877
|
+
return 0;
|
|
878
|
+
}, \\"px\\")
|
|
879
|
+
}
|
|
880
|
+
});"
|
|
881
|
+
`);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
it("should detect expressions with units in mixins", async () => {
|
|
885
|
+
expect(
|
|
886
|
+
await tsloader.call(
|
|
887
|
+
loaderContext,
|
|
888
|
+
`
|
|
889
|
+
import { css } from "next-yak";
|
|
890
|
+
const mixin1 = css\`
|
|
891
|
+
padding: \${4}px;
|
|
892
|
+
\`;
|
|
893
|
+
const value = 10;
|
|
894
|
+
const mixin2 = css\`
|
|
895
|
+
margin: \${size}px;
|
|
896
|
+
top: \${spacing.xs}px;
|
|
897
|
+
bottom: \${spacing[0]}PX;
|
|
898
|
+
left: \${spacing()}px;
|
|
899
|
+
right: \${value}px;
|
|
900
|
+
\`
|
|
901
|
+
`
|
|
902
|
+
)
|
|
903
|
+
).toMatchInlineSnapshot(`
|
|
904
|
+
"import { css } from \\"next-yak\\";
|
|
905
|
+
import { __yak_unitPostFix } from \\"next-yak/runtime-internals\\";
|
|
906
|
+
import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\";
|
|
907
|
+
const mixin1 = css(__styleYak.mixin1_0, {
|
|
908
|
+
\\"style\\": {
|
|
909
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j0\\": 4 + \\"px\\"
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
const value = 10;
|
|
913
|
+
const mixin2 = css(__styleYak.mixin2_1, {
|
|
914
|
+
\\"style\\": {
|
|
915
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j1\\": size + \\"px\\",
|
|
916
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j2\\": __yak_unitPostFix(spacing.xs, \\"px\\"),
|
|
917
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j3\\": __yak_unitPostFix(spacing[0], \\"PX\\"),
|
|
918
|
+
\\"--\\\\uD83E\\\\uDDAC18fi82j4\\": __yak_unitPostFix(spacing(), \\"px\\")
|
|
919
|
+
}
|
|
920
|
+
});"
|
|
921
|
+
`);
|
|
922
|
+
});
|
|
782
923
|
});
|
|
@@ -5,6 +5,7 @@ const murmurhash2_32_gc = require("./lib/hash.cjs");
|
|
|
5
5
|
const { relative, resolve, basename } = require("path");
|
|
6
6
|
const localIdent = require("./lib/localIdent.cjs");
|
|
7
7
|
const getStyledComponentName = require("./lib/getStyledComponentName.cjs");
|
|
8
|
+
const appendCssUnitToExpressionValue = require("./lib/appendCssUnitToExpressionValue.cjs");
|
|
8
9
|
const getCssName = require("./lib/getCssName.cjs");
|
|
9
10
|
const {
|
|
10
11
|
getConstantName,
|
|
@@ -32,6 +33,8 @@ const {
|
|
|
32
33
|
* className: string,
|
|
33
34
|
* astNode: import("@babel/types").CallExpression
|
|
34
35
|
* }>
|
|
36
|
+
* yakImportPath?: import("@babel/core").NodePath<import("@babel/core").types.ImportDeclaration>
|
|
37
|
+
* runtimeInternalHelpers: Set<string>
|
|
35
38
|
* }>}
|
|
36
39
|
*/
|
|
37
40
|
module.exports = function (babel, options) {
|
|
@@ -128,10 +131,24 @@ module.exports = function (babel, options) {
|
|
|
128
131
|
this.varIndex = 0;
|
|
129
132
|
this.variableNameToStyledCall = new Map();
|
|
130
133
|
this.topLevelConstBindings = new Map();
|
|
134
|
+
this.runtimeInternalHelpers = new Set();
|
|
131
135
|
},
|
|
132
136
|
visitor: {
|
|
133
|
-
Program
|
|
134
|
-
|
|
137
|
+
Program: {
|
|
138
|
+
enter(path, state) {
|
|
139
|
+
this.topLevelConstBindings = getConstantValues(path, t);
|
|
140
|
+
},
|
|
141
|
+
exit(path, state) {
|
|
142
|
+
if (this.runtimeInternalHelpers.size && this.yakImportPath) {
|
|
143
|
+
const newImport = t.importDeclaration(
|
|
144
|
+
[...this.runtimeInternalHelpers].map((helper) =>
|
|
145
|
+
t.importSpecifier(t.identifier(helper), t.identifier(helper))
|
|
146
|
+
),
|
|
147
|
+
t.stringLiteral("next-yak/runtime-internals")
|
|
148
|
+
);
|
|
149
|
+
this.yakImportPath.insertAfter(newImport);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
135
152
|
},
|
|
136
153
|
/**
|
|
137
154
|
* Store the name of the imported 'css' and 'styled' variables e.g.:
|
|
@@ -164,6 +181,7 @@ module.exports = function (babel, options) {
|
|
|
164
181
|
)
|
|
165
182
|
)
|
|
166
183
|
);
|
|
184
|
+
this.yakImportPath = path;
|
|
167
185
|
|
|
168
186
|
// Process import specifiers
|
|
169
187
|
node.specifiers.forEach((specifier) => {
|
|
@@ -327,6 +345,7 @@ module.exports = function (babel, options) {
|
|
|
327
345
|
this.file
|
|
328
346
|
);
|
|
329
347
|
}
|
|
348
|
+
|
|
330
349
|
// expressions after a partial css are converted into css variables
|
|
331
350
|
if (
|
|
332
351
|
expression &&
|
|
@@ -356,23 +375,34 @@ module.exports = function (babel, options) {
|
|
|
356
375
|
);
|
|
357
376
|
}
|
|
358
377
|
|
|
359
|
-
if (!cssVariablesInlineStyle) {
|
|
360
|
-
cssVariablesInlineStyle = t.objectExpression([]);
|
|
361
|
-
}
|
|
362
378
|
if (!cssVariablesInlineStyle) {
|
|
363
379
|
cssVariablesInlineStyle = t.objectExpression([]);
|
|
364
380
|
}
|
|
365
381
|
const cssVariableName = `--🦬${getHashedFilePath(state.file)}${this
|
|
366
382
|
.varIndex++}`;
|
|
383
|
+
|
|
384
|
+
// Extracts the css unit from a css string after the current expression
|
|
385
|
+
const cssUnit = quasis[i + 1]?.value.raw.match(/^([a-z]+|%)/i)?.[0];
|
|
386
|
+
const transformedExpression = cssUnit
|
|
387
|
+
? appendCssUnitToExpressionValue(
|
|
388
|
+
cssUnit,
|
|
389
|
+
expression,
|
|
390
|
+
this.runtimeInternalHelpers,
|
|
391
|
+
t
|
|
392
|
+
)
|
|
393
|
+
: expression;
|
|
394
|
+
|
|
367
395
|
// expression: `x`
|
|
368
396
|
// { style: { --v0: x}}
|
|
369
397
|
cssVariablesInlineStyle.properties.push(
|
|
370
398
|
t.objectProperty(
|
|
371
399
|
t.stringLiteral(cssVariableName),
|
|
372
|
-
/** @type {babel.types.Expression} */ (
|
|
400
|
+
/** @type {babel.types.Expression} */ (transformedExpression)
|
|
373
401
|
)
|
|
374
402
|
);
|
|
375
|
-
}
|
|
403
|
+
}
|
|
404
|
+
// handle mixins
|
|
405
|
+
else {
|
|
376
406
|
wasInsideCssValue = false;
|
|
377
407
|
if (expression) {
|
|
378
408
|
if (quasiTypes[i].currentNestingScopes.length > 0) {
|
package/loaders/cssloader.cjs
CHANGED
|
@@ -93,7 +93,6 @@ module.exports = async function cssLoader(source) {
|
|
|
93
93
|
/** @type {Map<string, number | string | null>} */
|
|
94
94
|
let topLevelConstBindings = new Map();
|
|
95
95
|
|
|
96
|
-
|
|
97
96
|
babel.traverse(ast, {
|
|
98
97
|
Program(path) {
|
|
99
98
|
topLevelConstBindings = getConstantValues(path, t);
|
|
@@ -204,8 +203,9 @@ module.exports = async function cssLoader(source) {
|
|
|
204
203
|
const variableName =
|
|
205
204
|
isStyledLiteral || isStyledCall || isAttrsCall || isKeyFrameLiteral
|
|
206
205
|
? getStyledComponentName(path)
|
|
207
|
-
: isCssLiteral
|
|
208
|
-
|
|
206
|
+
: isCssLiteral
|
|
207
|
+
? getCssName(path)
|
|
208
|
+
: null;
|
|
209
209
|
|
|
210
210
|
const literalSelector = localIdent(
|
|
211
211
|
variableName || "_yak",
|
|
@@ -217,14 +217,19 @@ module.exports = async function cssLoader(source) {
|
|
|
217
217
|
const currentCssParts = {
|
|
218
218
|
quasiCode: [],
|
|
219
219
|
cssPartExpressions: [],
|
|
220
|
-
selector: !parentLocation
|
|
220
|
+
selector: !parentLocation
|
|
221
|
+
? literalSelector
|
|
222
|
+
: `&:where(${literalSelector})`,
|
|
221
223
|
hasParent: Boolean(parentLocation),
|
|
222
224
|
};
|
|
223
|
-
const parentCssParts =
|
|
225
|
+
const parentCssParts =
|
|
226
|
+
parentLocation && cssParts.get(parentLocation.parent);
|
|
224
227
|
cssParts.set(path, currentCssParts);
|
|
225
228
|
if (parentCssParts) {
|
|
226
229
|
parentCssParts.cssPartExpressions[parentLocation.currentIndex] ||= [];
|
|
227
|
-
parentCssParts.cssPartExpressions[parentLocation.currentIndex].push(
|
|
230
|
+
parentCssParts.cssPartExpressions[parentLocation.currentIndex].push(
|
|
231
|
+
currentCssParts
|
|
232
|
+
);
|
|
228
233
|
}
|
|
229
234
|
|
|
230
235
|
// Replace the tagged template expression with a call to the 'styled' function
|
|
@@ -234,11 +239,22 @@ module.exports = async function cssLoader(source) {
|
|
|
234
239
|
);
|
|
235
240
|
|
|
236
241
|
let wasInsideCssValue = false;
|
|
242
|
+
let removeCssUnit = false;
|
|
237
243
|
for (let i = 0; i < quasis.length; i++) {
|
|
238
244
|
const quasi = quasis[i];
|
|
239
245
|
const expression = path.node.quasi.expressions[i];
|
|
240
246
|
// loop over all quasis belonging to the same css block
|
|
241
247
|
const type = quasiTypes[i];
|
|
248
|
+
|
|
249
|
+
let code = unEscapeCssCode(quasi.value.raw);
|
|
250
|
+
if (removeCssUnit) {
|
|
251
|
+
// a quasi might start with a css unit e.g. css`margin: ${value}px 0;`
|
|
252
|
+
// the css unit will be part of the typescript runtime code and must
|
|
253
|
+
// must be removed from the css code as `var(--foo)px` would be invalid css
|
|
254
|
+
code = code.replace(/^([a-z]+|%)/i, "");
|
|
255
|
+
removeCssUnit = false;
|
|
256
|
+
}
|
|
257
|
+
|
|
242
258
|
// expressions after a partial css are converted into css variables
|
|
243
259
|
if (
|
|
244
260
|
expression &&
|
|
@@ -251,20 +267,23 @@ module.exports = async function cssLoader(source) {
|
|
|
251
267
|
const relativePath = relative(rootContext, resourcePath);
|
|
252
268
|
hashedFile = murmurhash2_32_gc(relativePath);
|
|
253
269
|
}
|
|
254
|
-
const variableName =
|
|
255
|
-
|
|
270
|
+
const variableName =
|
|
271
|
+
t.isExpression(expression) && getConstantName(expression, t);
|
|
272
|
+
const variableConstValue =
|
|
273
|
+
variableName && topLevelConstBindings.get(variableName);
|
|
256
274
|
if (variableConstValue === null || variableConstValue === undefined) {
|
|
257
275
|
currentCssParts.quasiCode.push({
|
|
258
276
|
insideCssValue: true,
|
|
259
277
|
code:
|
|
260
|
-
|
|
278
|
+
code +
|
|
261
279
|
// replace the expression with a css variable
|
|
262
280
|
`var(--🦬${hashedFile}${varIndex++})`,
|
|
263
281
|
});
|
|
282
|
+
removeCssUnit = true;
|
|
264
283
|
} else {
|
|
265
284
|
currentCssParts.quasiCode.push({
|
|
266
285
|
insideCssValue: true,
|
|
267
|
-
code:
|
|
286
|
+
code: code + String(variableConstValue),
|
|
268
287
|
});
|
|
269
288
|
}
|
|
270
289
|
} else {
|
|
@@ -273,7 +292,7 @@ module.exports = async function cssLoader(source) {
|
|
|
273
292
|
// empty quasis are also added to keep spacings
|
|
274
293
|
// e.g. `transition: color ${duration} ${easing};`
|
|
275
294
|
currentCssParts.quasiCode.push({
|
|
276
|
-
code
|
|
295
|
+
code,
|
|
277
296
|
insideCssValue: false,
|
|
278
297
|
});
|
|
279
298
|
}
|
|
@@ -285,10 +304,7 @@ module.exports = async function cssLoader(source) {
|
|
|
285
304
|
// const Bar = styled.div` ${MyStyledDiv} { color: blue }`
|
|
286
305
|
// "${MyStyledDiv} {" -> ".selector-0 {"
|
|
287
306
|
if (variableName && (isStyledLiteral || isStyledCall || isAttrsCall)) {
|
|
288
|
-
variableNameToStyledClassName.set(
|
|
289
|
-
variableName,
|
|
290
|
-
literalSelector
|
|
291
|
-
);
|
|
307
|
+
variableNameToStyledClassName.set(variableName, literalSelector);
|
|
292
308
|
}
|
|
293
309
|
},
|
|
294
310
|
});
|
|
@@ -310,7 +326,7 @@ const unEscapeCssCode = (code) => code.replace(/\\\\/gi, "\\");
|
|
|
310
326
|
/**
|
|
311
327
|
* Searches the closest parent TaggedTemplateExpression using a name from localNames
|
|
312
328
|
* Returns the location inside this parent
|
|
313
|
-
*
|
|
329
|
+
*
|
|
314
330
|
* @param {import("@babel/core").NodePath<import("@babel/types").TaggedTemplateExpression>} path
|
|
315
331
|
* @param {{ css?: string , styled?: string }} localNames
|
|
316
332
|
*/
|
|
@@ -325,7 +341,6 @@ const getClosestTemplateLiteralExpressionParentPath = (
|
|
|
325
341
|
let parent = path.parentPath;
|
|
326
342
|
const t = babel.types;
|
|
327
343
|
while (parent) {
|
|
328
|
-
|
|
329
344
|
if (t.isTaggedTemplateExpression(parent.node)) {
|
|
330
345
|
const tag = parent.node.tag;
|
|
331
346
|
const isCssLiteral =
|
|
@@ -353,16 +368,20 @@ const getClosestTemplateLiteralExpressionParentPath = (
|
|
|
353
368
|
/** @type {babel.types.Identifier} */ (tag.callee.property).name ===
|
|
354
369
|
"attrs";
|
|
355
370
|
if (isCssLiteral || isStyledLiteral || isStyledCall || isAttrsCall) {
|
|
356
|
-
if (
|
|
371
|
+
if (
|
|
372
|
+
!t.isTemplateLiteral(child.node) ||
|
|
373
|
+
!t.isExpression(grandChild.node)
|
|
374
|
+
) {
|
|
357
375
|
throw new Error("Broken AST");
|
|
358
376
|
}
|
|
359
377
|
const currentIndex = child.node.expressions.indexOf(grandChild.node);
|
|
360
|
-
return
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
378
|
+
return {
|
|
379
|
+
parent:
|
|
380
|
+
/** @type {import("@babel/core").NodePath<import("@babel/types").TaggedTemplateExpression>} */ (
|
|
381
|
+
parent
|
|
382
|
+
),
|
|
383
|
+
currentIndex,
|
|
384
|
+
};
|
|
366
385
|
}
|
|
367
386
|
}
|
|
368
387
|
if (!parent.parentPath) {
|
|
@@ -397,7 +416,8 @@ const mergeCssPartExpression = (cssPartExpression, level = 0) => {
|
|
|
397
416
|
}
|
|
398
417
|
}
|
|
399
418
|
// Try to keep the same indentation as the original code
|
|
400
|
-
const indent =
|
|
419
|
+
const indent =
|
|
420
|
+
quasiCode[0]?.code.match(/^\n( |\t)(\s*)/)?.[2] ?? " ".repeat(level);
|
|
401
421
|
const hasCss = Boolean(cssPart.trim());
|
|
402
422
|
css += !hasCss
|
|
403
423
|
? ""
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the css unit from a css string and checks if it is a valid CSS unit
|
|
3
|
+
*
|
|
4
|
+
* @param {string} cssUnit
|
|
5
|
+
* @param {babel.types.Expression} expression
|
|
6
|
+
* @param {Set<string>} runtimeInternalHelpers
|
|
7
|
+
* @param {import("@babel/types")} t
|
|
8
|
+
*/
|
|
9
|
+
const appendCssUnitToExpressionValue = (
|
|
10
|
+
cssUnit,
|
|
11
|
+
expression,
|
|
12
|
+
runtimeInternalHelpers,
|
|
13
|
+
t
|
|
14
|
+
) => {
|
|
15
|
+
if (expression.type === "ArrowFunctionExpression") {
|
|
16
|
+
if (expression.body.type !== "BlockStatement") {
|
|
17
|
+
const newBody = t.binaryExpression(
|
|
18
|
+
"+",
|
|
19
|
+
t.parenthesizedExpression(expression.body),
|
|
20
|
+
t.stringLiteral(cssUnit)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const newArrowFunction = t.arrowFunctionExpression(
|
|
24
|
+
expression.params,
|
|
25
|
+
newBody
|
|
26
|
+
);
|
|
27
|
+
return newArrowFunction;
|
|
28
|
+
}
|
|
29
|
+
} else if (
|
|
30
|
+
expression.type === "NumericLiteral" ||
|
|
31
|
+
expression.type === "BinaryExpression" ||
|
|
32
|
+
expression.type === "Identifier"
|
|
33
|
+
) {
|
|
34
|
+
const cssUnitLiteral = t.stringLiteral(cssUnit);
|
|
35
|
+
const binaryExpression = t.binaryExpression(
|
|
36
|
+
"+",
|
|
37
|
+
expression,
|
|
38
|
+
cssUnitLiteral
|
|
39
|
+
);
|
|
40
|
+
return binaryExpression;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const callExpression = t.callExpression(t.identifier("__yak_unitPostFix"), [
|
|
44
|
+
expression,
|
|
45
|
+
t.stringLiteral(cssUnit),
|
|
46
|
+
]);
|
|
47
|
+
runtimeInternalHelpers.add("__yak_unitPostFix");
|
|
48
|
+
return callExpression;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
module.exports = appendCssUnitToExpressionValue;
|
package/loaders/tsloader.cjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/// @ts-check
|
|
2
2
|
const babel = require("@babel/core");
|
|
3
3
|
const getYakImports = require("./lib/getYakImports.cjs");
|
|
4
|
-
const InvalidPositionError =
|
|
4
|
+
const InvalidPositionError =
|
|
5
|
+
require("./babel-yak-plugin.cjs").InvalidPositionError;
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Loader for typescript files that use yak, it replaces the css template literal with a call to the 'styled' function
|
|
@@ -53,7 +54,7 @@ module.exports = async function tsloader(source) {
|
|
|
53
54
|
{ isTSX: this.resourcePath.endsWith(".tsx") },
|
|
54
55
|
],
|
|
55
56
|
[
|
|
56
|
-
require
|
|
57
|
+
require("./babel-yak-plugin.cjs"),
|
|
57
58
|
{
|
|
58
59
|
replaces,
|
|
59
60
|
rootContext,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-yak",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./dist/",
|
|
6
6
|
"exports": {
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"import": "./dist/static/index.js",
|
|
13
13
|
"require": "./dist/static/index.cjs"
|
|
14
14
|
},
|
|
15
|
+
"./runtime-internals": {
|
|
16
|
+
"import": "./dist/runtime-internals/index.js",
|
|
17
|
+
"require": "./dist/runtime-internals/index.cjs"
|
|
18
|
+
},
|
|
15
19
|
"./withYak": {
|
|
16
20
|
"require": "./withYak/index.cjs"
|
|
17
21
|
},
|
|
@@ -35,6 +39,7 @@
|
|
|
35
39
|
"build": "pnpm run --filter . \"/^build:/\"",
|
|
36
40
|
"build:runtime": "tsup runtime/index.ts --target es2022 --clean --external react --external next-yak/context --format cjs,esm --minify --sourcemap --out-dir dist",
|
|
37
41
|
"build:runtime:types": "tsup runtime/index.ts --target es2022 --clean --external react --dts-only --format cjs,esm --minify --sourcemap --out-dir dist",
|
|
42
|
+
"build:runtimeInternals": "tsup runtime/internals/index.ts --target es2022 --clean --external react --external next-yak/runtime-internals --format cjs,esm --minify --sourcemap --out-dir dist/runtime-internals",
|
|
38
43
|
"build:static": "tsup static/index.ts --target es2022 --clean --external react --external next-yak/context --format cjs,esm --minify --sourcemap --out-dir dist/static",
|
|
39
44
|
"build:static:types": "tsup static/index.ts --target es2022 --clean --external react --dts-only --format cjs,esm --minify --sourcemap --out-dir dist/static",
|
|
40
45
|
"build:baseContext": "tsup runtime/context/baseContext.tsx --target es2022 --external react --dts --format cjs,esm --sourcemap --out-dir dist/context/",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { unitPostFix as __yak_unitPostFix } from "./unitPostFix.js";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Takes a function and a css unit and returns the result of the function concatenated with the unit
|
|
3
|
+
*
|
|
4
|
+
* @usage
|
|
5
|
+
*
|
|
6
|
+
* ```tsx
|
|
7
|
+
* import { styled, atoms } from "next-yak";
|
|
8
|
+
*
|
|
9
|
+
* const Button = styled.button<{ $primary?: boolean }>`
|
|
10
|
+
* ${atoms("text-teal-600", "text-base", "rounded-md")}
|
|
11
|
+
* ${props => props.$primary && atoms("shadow-md")}
|
|
12
|
+
* `;
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export const unitPostFix = (fn: any, unit: string) =>
|
|
16
|
+
typeof fn === "function" ? (...args: any[]) => fn(...args) + unit : fn + unit;
|