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.
@@ -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,2 @@
1
+ var n=(t,o)=>typeof t=="function"?(...i)=>t(...i)+o:t+o;export{n as __yak_unitPostFix};
2
+ //# sourceMappingURL=index.js.map
@@ -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(path) {
134
- this.topLevelConstBindings = getConstantValues(path, t);
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} */ (expression)
400
+ /** @type {babel.types.Expression} */ (transformedExpression)
373
401
  )
374
402
  );
375
- } else {
403
+ }
404
+ // handle mixins
405
+ else {
376
406
  wasInsideCssValue = false;
377
407
  if (expression) {
378
408
  if (quasiTypes[i].currentNestingScopes.length > 0) {
@@ -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 ? getCssName(path)
208
- : null
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 ? literalSelector : `&:where(${literalSelector})`,
220
+ selector: !parentLocation
221
+ ? literalSelector
222
+ : `&:where(${literalSelector})`,
221
223
  hasParent: Boolean(parentLocation),
222
224
  };
223
- const parentCssParts = parentLocation && cssParts.get(parentLocation.parent);
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(currentCssParts);
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 = t.isExpression(expression) && getConstantName(expression, t);
255
- const variableConstValue = variableName && topLevelConstBindings.get(variableName);
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
- unEscapeCssCode(quasi.value.raw) +
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: unEscapeCssCode(quasi.value.raw) + String(variableConstValue),
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: unEscapeCssCode(quasi.value.raw),
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 (!t.isTemplateLiteral(child.node) || !t.isExpression(grandChild.node)) {
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
- { parent:
362
- /** @type {import("@babel/core").NodePath<import("@babel/types").TaggedTemplateExpression>} */(parent),
363
- currentIndex
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 = quasiCode[0]?.code.match(/^\n( |\t)(\s*)/)?.[2] ?? " ".repeat(level);
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;
@@ -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 = require("./babel-yak-plugin.cjs").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.resolve("./babel-yak-plugin.cjs"),
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.30",
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;