next-yak 0.0.35 → 0.0.39

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.
Files changed (45) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/loaders/cssloader.cjs +649 -0
  6. package/dist/loaders/cssloader.cjs.map +1 -0
  7. package/dist/loaders/cssloader.d.cts +3 -0
  8. package/dist/loaders/cssloader.d.ts +3 -0
  9. package/dist/loaders/cssloader.js +616 -0
  10. package/dist/loaders/cssloader.js.map +1 -0
  11. package/dist/loaders/tsloader.cjs +844 -0
  12. package/dist/loaders/tsloader.cjs.map +1 -0
  13. package/dist/loaders/tsloader.d.cts +6 -0
  14. package/dist/loaders/tsloader.d.ts +6 -0
  15. package/dist/loaders/tsloader.js +820 -0
  16. package/dist/loaders/tsloader.js.map +1 -0
  17. package/{withYak → dist/withYak}/index.cjs +14 -7
  18. package/dist/withYak/index.cjs.map +1 -0
  19. package/{withYak → dist/withYak}/index.d.cts +2 -2
  20. package/dist/withYak/index.d.ts +37 -0
  21. package/dist/withYak/index.js +68 -0
  22. package/dist/withYak/index.js.map +1 -0
  23. package/loaders/__tests__/classifier.test.ts +99 -93
  24. package/loaders/__tests__/cssloader.test.ts +1 -1
  25. package/loaders/__tests__/getCssName.test.ts +1 -1
  26. package/loaders/__tests__/tsloader.test.ts +1 -1
  27. package/loaders/{babel-yak-plugin.cjs → babel-yak-plugin.ts} +69 -68
  28. package/loaders/{cssloader.cjs → cssloader.ts} +73 -97
  29. package/loaders/lib/{appendCssUnitToExpressionValue.cjs → appendCssUnitToExpressionValue.ts} +7 -10
  30. package/loaders/lib/{getConstantValues.cjs → getConstantValues.ts} +10 -17
  31. package/loaders/lib/{getCssName.cjs → getCssName.ts} +19 -31
  32. package/loaders/lib/{getStyledComponentName.cjs → getStyledComponentName.ts} +7 -10
  33. package/loaders/lib/{getYakImports.cjs → getYakImports.ts} +4 -10
  34. package/loaders/lib/{hash.cjs → hash.ts} +3 -5
  35. package/loaders/lib/{localIdent.cjs → localIdent.ts} +5 -7
  36. package/loaders/lib/{quasiClassifier.cjs → quasiClassifier.ts} +7 -16
  37. package/loaders/lib/{replaceQuasiExpressionTokens.cjs → replaceQuasiExpressionTokens.ts} +27 -26
  38. package/loaders/lib/{stripCssComments.cjs → stripCssComments.ts} +3 -9
  39. package/loaders/{tsloader.cjs → tsloader.ts} +11 -15
  40. package/package.json +12 -21
  41. package/runtime/__tests__/attrs.test.tsx +4 -14
  42. package/runtime/__tests__/styled.test.tsx +25 -6
  43. package/runtime/styled.tsx +5 -5
  44. package/withYak/index.ts +43 -34
  45. package/withYak/index.cjs.map +0 -1
@@ -1,21 +1,18 @@
1
- // @ts-check
2
-
3
- /** @typedef {import("@babel/types")} babel */
1
+ import type { NodePath, types as babelTypes } from "@babel/core";
4
2
 
5
3
  /**
6
4
  * Extracts the conditions from a path
7
- * @param {babel.NodePath<babel.types.TaggedTemplateExpression>} path
8
5
  */
9
- function extractConditions(path) {
10
- /** @type {string[]} */
11
- const conditions = [];
6
+ function extractConditions(
7
+ path: NodePath<babelTypes.TaggedTemplateExpression>
8
+ ) {
9
+ const conditions: string[] = [];
12
10
  const visitedNodes = new Set();
13
- /**
14
- * @param {babel.types.Node} node
15
- * @param {babel.types.Node} previousNode
16
- * @param {boolean} isNegated
17
- */
18
- const getConditions = (node, previousNode, isNegated = false) => {
11
+ const getConditions = (
12
+ node: babelTypes.Node,
13
+ previousNode: babelTypes.Node,
14
+ isNegated = false
15
+ ) => {
19
16
  if (visitedNodes.has(node)) return;
20
17
  visitedNodes.add(node);
21
18
  // Support for && and || operators e.g. disabled && "disabled"
@@ -58,10 +55,8 @@ function extractConditions(path) {
58
55
  );
59
56
  }
60
57
  };
61
- /** @type {babel.NodePath | null} */
62
- let currentPath = path;
63
- /** @type {babel.NodePath} */
64
- let previousPath = path;
58
+ let currentPath: NodePath | null = path;
59
+ let previousPath: NodePath = path;
65
60
  while (currentPath) {
66
61
  getConditions(currentPath.node, previousPath.node);
67
62
  previousPath = currentPath;
@@ -77,11 +72,10 @@ function extractConditions(path) {
77
72
  * Try to get the name of a css component from a literal expression
78
73
  *
79
74
  * e.g. const mixin = css`...` -> "mixin"
80
- *
81
- * @param {babel.NodePath<babel.types.TaggedTemplateExpression>} taggedTemplateExpressionPath
82
- * @returns {string | null}
83
75
  */
84
- const getStyledComponentName = (taggedTemplateExpressionPath) => {
76
+ const getStyledComponentName = (
77
+ taggedTemplateExpressionPath: NodePath<babelTypes.TaggedTemplateExpression>
78
+ ) => {
85
79
  const variableDeclaratorPath = taggedTemplateExpressionPath.findParent(
86
80
  (path) => path.isVariableDeclarator()
87
81
  );
@@ -100,11 +94,8 @@ const getStyledComponentName = (taggedTemplateExpressionPath) => {
100
94
  *
101
95
  * e.g. props.disabled -> "propsDisabled"
102
96
  * e.g. props.user.disabled -> "propsUserDisabled
103
- *
104
- * @param {babel.types.MemberExpression} node
105
- * @returns {string}
106
97
  */
107
- function getMemberExpressionName(node) {
98
+ function getMemberExpressionName(node: babelTypes.MemberExpression): string {
108
99
  if (
109
100
  !node.object ||
110
101
  !node.property ||
@@ -134,11 +125,10 @@ function getMemberExpressionName(node) {
134
125
  * Try to get the name of a css literal
135
126
  *
136
127
  * e.g. ({$disabled}) => $disabled && css`...` -> "is_$disabled"
137
- *
138
- * @param {babel.NodePath<babel.types.TaggedTemplateExpression>} literal
139
- * @returns {string}
140
128
  */
141
- function getCssName(literal) {
129
+ export default function getCssName(
130
+ literal: NodePath<babelTypes.TaggedTemplateExpression>
131
+ ) {
142
132
  const conditions = extractConditions(literal);
143
133
  if (conditions.length === 0) {
144
134
  const mixinName = getStyledComponentName(literal);
@@ -146,5 +136,3 @@ function getCssName(literal) {
146
136
  }
147
137
  return conditions.join("_").replace(/\$/g, "");
148
138
  }
149
-
150
- module.exports = getCssName;
@@ -1,19 +1,16 @@
1
- // @ts-check
2
-
3
- /** @typedef {import("@babel/types")} babel */
1
+ import type { NodePath, types as babelTypes } from "@babel/core";
4
2
 
5
3
  /**
6
4
  * Try to get the name of a styled component from a call or member expression
7
5
  *
8
6
  * e.g. const MyButton = styled.div`...` -> "MyButton"
9
7
  * e.g. const FancyButton = styled(MyButton)`...` -> "FancyButton"
10
- *
11
- * @param {babel.NodePath<babel.types.TaggedTemplateExpression>} taggedTemplateExpressionPath
12
- * @returns {string}
13
8
  */
14
- const getStyledComponentName = (taggedTemplateExpressionPath) => {
9
+ const getStyledComponentName = (
10
+ taggedTemplateExpressionPath: NodePath<babelTypes.TaggedTemplateExpression>
11
+ ) => {
15
12
  const variableDeclaratorPath = taggedTemplateExpressionPath.findParent(
16
- (path) => path.isVariableDeclarator(),
13
+ (path) => path.isVariableDeclarator()
17
14
  );
18
15
  if (
19
16
  !variableDeclaratorPath ||
@@ -22,10 +19,10 @@ const getStyledComponentName = (taggedTemplateExpressionPath) => {
22
19
  ) {
23
20
  throw new Error(
24
21
  "Could not find variable declaration for styled component at " +
25
- taggedTemplateExpressionPath.node.loc,
22
+ taggedTemplateExpressionPath.node.loc
26
23
  );
27
24
  }
28
25
  return variableDeclaratorPath.node.id.name;
29
26
  };
30
27
 
31
- module.exports = getStyledComponentName;
28
+ export default getStyledComponentName;
@@ -1,17 +1,13 @@
1
- // @ts-check
2
1
  /**
3
2
  * Finds all imports in a given code string which import from a .yak file
4
3
  *
5
4
  * Uses regex to work with typescript and javascript
6
5
  * Does not support lazy imports
7
- *
8
- * @param {string} code
9
- * @returns { { imports: { localName: string, importedName: string }[], from: string }[] }
10
6
  */
11
- const getYakImports = (code) => {
7
+ const getYakImports = (code: string) => {
12
8
  const codeWithoutComments = code.replace(/\/\*[\s\S]*?\*\//g, "");
13
9
  const allImports = codeWithoutComments.matchAll(
14
- /(^|\n|;)\s*import\s+(?:(\w+(?:\s+as\s+\w+)?)\s*,?\s*)?(?:{([^}]*)})?\s+from\s+["']([^'"]+\.yak)["'](;|\n)/g,
10
+ /(^|\n|;)\s*import\s+(?:(\w+(?:\s+as\s+\w+)?)\s*,?\s*)?(?:{([^}]*)})?\s+from\s+["']([^'"]+\.yak)["'](;|\n)/g
15
11
  );
16
12
  return [...allImports].map(([, , defaultImport, namedImports, from]) => {
17
13
  // parse named imports to { localName: string, importedName: string }[]
@@ -33,10 +29,8 @@ const getYakImports = (code) => {
33
29
 
34
30
  /**
35
31
  * Parses a default import string
36
- * @param {string} defaultImport
37
- * @returns {{ localName: string, importedName: string }}
38
32
  */
39
- function parseDefaultImport(defaultImport) {
33
+ function parseDefaultImport(defaultImport: string) {
40
34
  const defaultImportArray = defaultImport.split(/\s+as\s+/);
41
35
  return {
42
36
  localName: defaultImportArray[1] ?? defaultImportArray[0],
@@ -44,4 +38,4 @@ function parseDefaultImport(defaultImport) {
44
38
  };
45
39
  }
46
40
 
47
- module.exports = getYakImports;
41
+ export default getYakImports;
@@ -6,10 +6,10 @@
6
6
  * @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
7
7
  * @see http://sites.google.com/site/murmurhash/
8
8
  *
9
- * @param {string} str ASCII only
10
- * @return {string} Base 36 encoded hash result
9
+ * @param str ASCII only
10
+ * @return Base 36 encoded hash result
11
11
  */
12
- function murmurhash2_32_gc(str) {
12
+ export default function murmurhash2_32_gc(str: string) {
13
13
  let l = str.length;
14
14
  let h = l;
15
15
  let i = 0;
@@ -56,5 +56,3 @@ function murmurhash2_32_gc(str) {
56
56
 
57
57
  return (h >>> 0).toString(36);
58
58
  }
59
-
60
- module.exports = murmurhash2_32_gc;
@@ -9,12 +9,12 @@
9
9
  * localIdent("myVariableName", 1, "keyframes") // "@keyframes myVariableName_1"
10
10
  * localIdent("myVariableName", 1, "animation") // "myVariableName_1"
11
11
  * ```
12
- *
13
- * @param {string} variableName
14
- * @param {number | null} i
15
- * @param {"selector" | "className" | "keyframes" | "animation"} kind
16
12
  */
17
- function localIdent(variableName, i, kind) {
13
+ export default function localIdent(
14
+ variableName: string,
15
+ i: number | null,
16
+ kind: "selector" | "className" | "keyframes" | "animation"
17
+ ) {
18
18
  switch (kind) {
19
19
  case "selector":
20
20
  return `.${variableName}${i === null ? "" : `_${i}`}`;
@@ -27,5 +27,3 @@ function localIdent(variableName, i, kind) {
27
27
  throw new Error("unknown kind");
28
28
  }
29
29
  }
30
-
31
- module.exports = localIdent;
@@ -1,5 +1,4 @@
1
- /// @ts-check
2
- const stripCssComments = require("./stripCssComments.cjs");
1
+ import stripCssComments from "./stripCssComments.js";
3
2
 
4
3
  /**
5
4
  * Checks a quasiValue and returns its type
@@ -7,18 +6,11 @@ const stripCssComments = require("./stripCssComments.cjs");
7
6
  * - empty: no expressions, no text
8
7
  * - unknownSelector: starts with a `{` e.g. `{ opacity: 0.5; }` or `,` e.g. `, bar { ... }`
9
8
  * - insideCssValue: does not end with a `{` or `}` or `;` e.g. `color: `
10
- *
11
- * @param {string} quasiValue
12
- * @param {string[]} currentNestingScopes - the current nesting scope
13
- *
14
- * @returns {{
15
- * empty: boolean,
16
- * unknownSelector: boolean,
17
- * insideCssValue: boolean,
18
- * currentNestingScopes: string[],
19
- * }}
20
9
  */
21
- module.exports = function quasiClassifier(quasiValue, currentNestingScopes) {
10
+ export default function quasiClassifier(
11
+ quasiValue: string,
12
+ currentNestingScopes: string[]
13
+ ) {
22
14
  // TODO - for better performance we could move the comment skipping logic
23
15
  // directly in the for loop below instead of calling stripCssComments
24
16
  const trimmedCssString = stripCssComments(quasiValue).trim();
@@ -30,8 +22,7 @@ module.exports = function quasiClassifier(quasiValue, currentNestingScopes) {
30
22
  currentNestingScopes,
31
23
  };
32
24
  }
33
- /** @type {'"' | "'" | false} */
34
- let isInsideString = false;
25
+ let isInsideString: '"' | "'" | false = false;
35
26
  let currentCharacter = "";
36
27
  let newNestingLevel = [...currentNestingScopes];
37
28
  let currentSelector = "";
@@ -87,4 +78,4 @@ module.exports = function quasiClassifier(quasiValue, currentNestingScopes) {
87
78
  currentCharacter !== ";",
88
79
  currentNestingScopes: newNestingLevel,
89
80
  };
90
- };
81
+ }
@@ -1,3 +1,5 @@
1
+ import type { NodePath, types as babelTypes } from "@babel/core";
2
+
1
3
  /**
2
4
  * Replace tokens with predefined values e.g.
3
5
  *
@@ -19,12 +21,12 @@
19
21
  * }
20
22
  * `
21
23
  * ```
22
- *
23
- * @param {import("@babel/types").TemplateLiteral} quasi
24
- * @param {(name: string) => unknown} replacer
25
- * @param {import("@babel/types")} t
26
24
  */
27
- module.exports = function replaceTokensInQuasiExpressions(quasi, replacer, t) {
25
+ export default function replaceTokensInQuasiExpressions(
26
+ quasi: babelTypes.TemplateLiteral,
27
+ replacer: (name: string) => unknown,
28
+ t: typeof babelTypes
29
+ ) {
28
30
  // Iterate over the expressions in reverse order
29
31
  // so removing items won't affect the index of the next item
30
32
  for (let i = quasi.expressions.length - 1; i >= 0; i--) {
@@ -36,23 +38,22 @@ module.exports = function replaceTokensInQuasiExpressions(quasi, replacer, t) {
36
38
  const replacement = parts && replacer(parts[0]);
37
39
  // if it is a nested value, find the value of the expression
38
40
  // e.g. x.y.z -> find the value of z
39
- const replacementValue = replacement && getReplacementValue(
40
- replacement,
41
- parts
42
- );
41
+ const replacementValue =
42
+ replacement && getReplacementValue(replacement, parts);
43
43
  if (replacementValue !== false && replacementValue !== null) {
44
44
  replaceExpressionAndMergeQuasis(quasi, i, replacementValue);
45
- }
45
+ }
46
46
  }
47
- };
47
+ }
48
48
 
49
49
  /**
50
50
  * Replace tokens with predefined values
51
- * @param {import("@babel/types").TemplateLiteral} quasi
52
- * @param {number} expressionIndex
53
- * @param {unknown} replacement
54
51
  */
55
- function replaceExpressionAndMergeQuasis(quasi, expressionIndex, replacement) {
52
+ function replaceExpressionAndMergeQuasis(
53
+ quasi: babelTypes.TemplateLiteral,
54
+ expressionIndex: number,
55
+ replacement: unknown
56
+ ) {
56
57
  const stringReplacement =
57
58
  typeof replacement === "string"
58
59
  ? replacement
@@ -77,11 +78,11 @@ function replaceExpressionAndMergeQuasis(quasi, expressionIndex, replacement) {
77
78
  * - `x()` -> ["x"]
78
79
  * - `x.y()` -> ["x", "y"]
79
80
  * - (1 + 2) -> null
80
- *
81
- * @param {import("@babel/types").Expression | import("@babel/types").TSType} expression
82
- * @param {import("@babel/types")} t
83
81
  */
84
- function getExpressionParts(expression, t) {
82
+ function getExpressionParts(
83
+ expression: babelTypes.Expression | babelTypes.TSType,
84
+ t: typeof babelTypes
85
+ ) {
85
86
  let currentExpression = expression;
86
87
  /** @type {string[]} */
87
88
  const tokens = [];
@@ -93,7 +94,10 @@ function getExpressionParts(expression, t) {
93
94
  }
94
95
  // e.g. x.y
95
96
  if (t.isMemberExpression(currentExpression)) {
96
- if (currentExpression.computed === false && t.isIdentifier(currentExpression.property)) {
97
+ if (
98
+ currentExpression.computed === false &&
99
+ t.isIdentifier(currentExpression.property)
100
+ ) {
97
101
  tokens.unshift(currentExpression.property.name);
98
102
  } else if (t.isStringLiteral(currentExpression.property)) {
99
103
  tokens.unshift(currentExpression.property.value);
@@ -117,15 +121,12 @@ function getExpressionParts(expression, t) {
117
121
 
118
122
  /**
119
123
  * Get the value of the replacement
120
- *
124
+ *
121
125
  * e.g. for `replacement.x.y[0]` and `replacement = { x: { y: [42] } }`
122
126
  * parts = ["replacement", "x", "y", 0]
123
127
  * --> 42
124
- *
125
- * @param {any} replacement
126
- * @param {string[]} parts
127
128
  */
128
- function getReplacementValue(replacement, parts) {
129
+ function getReplacementValue(replacement: any, parts: string[]) {
129
130
  let currentReplacement = replacement;
130
131
  for (let i = 1; i < parts.length; i++) {
131
132
  const part = parts[i];
@@ -135,4 +136,4 @@ function getReplacementValue(replacement, parts) {
135
136
  currentReplacement = currentReplacement[part];
136
137
  }
137
138
  return currentReplacement;
138
- }
139
+ }
@@ -1,12 +1,6 @@
1
- /// @ts-check
2
1
  // from https://github.com/sindresorhus/strip-css-comments/tree/main
3
- /**
4
- *
5
- * @param {string} cssString
6
- */
7
- module.exports = function stripCssComments(cssString) {
8
- /** @type {string | false} */
9
- let isInsideString = false;
2
+ export default function stripCssComments(cssString: string) {
3
+ let isInsideString: string | false = false;
10
4
  let currentCharacter = "";
11
5
  let comment = "";
12
6
  let returnValue = "";
@@ -55,4 +49,4 @@ module.exports = function stripCssComments(cssString) {
55
49
  returnValue += currentCharacter;
56
50
  }
57
51
  return returnValue;
58
- };
52
+ }
@@ -1,16 +1,14 @@
1
- /// @ts-check
2
- const babel = require("@babel/core");
3
- const getYakImports = require("./lib/getYakImports.cjs");
4
- const InvalidPositionError =
5
- require("./babel-yak-plugin.cjs").InvalidPositionError;
1
+ import babel, { BabelFileResult } from "@babel/core";
2
+ import getYakImports from "./lib/getYakImports.js";
3
+ import { InvalidPositionError } from "./babel-yak-plugin.js";
6
4
 
7
5
  /**
8
6
  * Loader for typescript files that use yak, it replaces the css template literal with a call to the 'styled' function
9
- * @param {string} source
10
- * @this {any}
11
- * @returns {Promise<string | void>}
12
7
  */
13
- module.exports = async function tsloader(source) {
8
+ export default async function tsloader(
9
+ this: any,
10
+ source: string
11
+ ): Promise<string | void> {
14
12
  // ignore files if they don't use yak
15
13
  if (!source.includes("next-yak")) {
16
14
  return source;
@@ -26,8 +24,7 @@ module.exports = async function tsloader(source) {
26
24
  // However .yak files inside .yak files are not be compiled
27
25
  // to avoid performance overhead
28
26
  const importedYakConstants = isYakFile ? [] : getYakImports(source);
29
- /** @type {Record<string, unknown>} */
30
- const replaces = {};
27
+ const replaces: Record<string, unknown> = {};
31
28
  await Promise.all(
32
29
  importedYakConstants.map(async ({ imports, from }) => {
33
30
  const constantValues = await this.importModule(from, {
@@ -39,8 +36,7 @@ module.exports = async function tsloader(source) {
39
36
  })
40
37
  );
41
38
 
42
- /** @type {babel.BabelFileResult | null} */
43
- let result = null;
39
+ let result: BabelFileResult | null = null;
44
40
  try {
45
41
  // Compile the typescript file with babel - this will:
46
42
  // - inject the import to the css-module (with .yak.module.css extension)
@@ -54,7 +50,7 @@ module.exports = async function tsloader(source) {
54
50
  { isTSX: this.resourcePath.endsWith(".tsx") },
55
51
  ],
56
52
  [
57
- require("./babel-yak-plugin.cjs"),
53
+ await import("./babel-yak-plugin.js").then((m) => m.default),
58
54
  {
59
55
  replaces,
60
56
  rootContext,
@@ -72,4 +68,4 @@ module.exports = async function tsloader(source) {
72
68
  return callback(new Error("babel transform failed"));
73
69
  }
74
70
  return callback(null, result.code, result.map);
75
- };
71
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-yak",
3
- "version": "0.0.35",
3
+ "version": "0.0.39",
4
4
  "type": "module",
5
5
  "types": "./dist/",
6
6
  "exports": {
@@ -17,7 +17,8 @@
17
17
  "require": "./dist/runtime-internals/index.cjs"
18
18
  },
19
19
  "./withYak": {
20
- "require": "./withYak/index.cjs"
20
+ "import": "./dist/withYak/index.js",
21
+ "require": "./dist/withYak/index.cjs"
21
22
  },
22
23
  "./context/baseContext": {
23
24
  "import": "./dist/context/baseContext.js",
@@ -34,23 +35,6 @@
34
35
  }
35
36
  }
36
37
  },
37
- "scripts": {
38
- "prepublishOnly": "npm run build && npm run test && npm run test:types:code && npm run test:types:test",
39
- "build": "pnpm run --filter . \"/^build:/\"",
40
- "build:runtime": "tsup runtime/index.ts --target es2022 --clean --external react --external next-yak/context --format cjs,esm --minify --sourcemap --out-dir dist",
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",
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",
44
- "build:static:types": "tsup static/index.ts --target es2022 --clean --external react --dts-only --format cjs,esm --minify --sourcemap --out-dir dist/static",
45
- "build:baseContext": "tsup runtime/context/baseContext.tsx --target es2022 --external react --dts --format cjs,esm --sourcemap --out-dir dist/context/",
46
- "build:context:client": "tsup runtime/context/index.tsx --target es2022 --external react --external next-yak/context/baseContext --dts --format cjs,esm --sourcemap --out-dir dist/context/",
47
- "build:context:server": "tsup runtime/context/index.server.tsx --target es2022 --external react --external next-yak/context/baseContext --external ./index.js --format cjs,esm --sourcemap --out-dir dist/context/",
48
- "build:withYak": "tsup withYak/index.ts --target es2022 --dts --format cjs --sourcemap --out-dir withYak --external ../loaders/tsloader.cjs --external ../loaders/cssloader.cjs",
49
- "test": "vitest run",
50
- "test:types:code": "tsc -p tsconfig.json",
51
- "test:types:test": "tsc -p ./runtime/__tests__/tsconfig.json",
52
- "test:watch": "vitest --watch"
53
- },
54
38
  "dependencies": {
55
39
  "@babel/core": "7.23.2",
56
40
  "@babel/plugin-syntax-typescript": "7.22.5",
@@ -79,5 +63,12 @@
79
63
  "loaders",
80
64
  "runtime",
81
65
  "withYak"
82
- ]
83
- }
66
+ ],
67
+ "scripts": {
68
+ "build": "tsup",
69
+ "test": "vitest run",
70
+ "test:types:code": "tsc -p tsconfig.json",
71
+ "test:types:test": "tsc -p ./runtime/__tests__/tsconfig.json",
72
+ "test:watch": "vitest --watch"
73
+ }
74
+ }
@@ -256,18 +256,6 @@ it("should work with data and aria attributes", () => {
256
256
  `);
257
257
  });
258
258
 
259
- // it("merge attrs", () => {
260
- // const Comp = styled.button
261
- // .attrs(() => ({
262
- // type: "button",
263
- // tabIndex: 0,
264
- // }))
265
- // .attrs(() => ({
266
- // type: "submit",
267
- // }))``;
268
- // expect(TestRenderer.create(<Comp />).toJSON()).toMatchInlineSnapshot();
269
- // });
270
-
271
259
  it("merge attrs when inheriting SC", () => {
272
260
  const Parent = styled.button.attrs(() => ({
273
261
  type: "button",
@@ -281,7 +269,7 @@ it("merge attrs when inheriting SC", () => {
281
269
  className=""
282
270
  style={{}}
283
271
  tabIndex={0}
284
- type="button"
272
+ type="submit"
285
273
  />
286
274
  `);
287
275
  });
@@ -531,6 +519,8 @@ it("should pass theme if theme is overwritten", () => {
531
519
  <pre
532
520
  className=""
533
521
  style={{}}
534
- />
522
+ >
523
+ {"color":"blue"}
524
+ </pre>
535
525
  `);
536
526
  });
@@ -95,13 +95,28 @@ it("should filter out properties starting with $ when passing to custom", () =>
95
95
  return null;
96
96
  };
97
97
  const StyledComponent = styled(Component)``;
98
- const { container } = render(
99
- <StyledComponent $forwardedProp="notForwarded" />,
100
- );
98
+ render(<StyledComponent $forwardedProp="notForwarded" />);
101
99
 
102
100
  expect(forwardedProps).toEqual({});
103
101
  });
104
102
 
103
+ it("should forward properties to the next yak component", () => {
104
+ const Component = styled.input.attrs(({ $text }) => ({
105
+ "aria-label": $text,
106
+ }))``;
107
+ const StyledComponent = styled(Component)``;
108
+ const { container } = render(<StyledComponent $text="hello world" />);
109
+
110
+ expect(container).toMatchInlineSnapshot(`
111
+ <div>
112
+ <input
113
+ aria-label="hello world"
114
+ class=""
115
+ />
116
+ </div>
117
+ `);
118
+ });
119
+
105
120
  it("should concatenate classNames", () => {
106
121
  const Component = styled.input("className1");
107
122
 
@@ -256,7 +271,7 @@ it("should remove theme if styled element", () => {
256
271
  `);
257
272
  });
258
273
 
259
- it("should not remove theme if theme is passed to element", () => {
274
+ it("should keep theme if theme is passed to element", () => {
260
275
  const ThemePrinter = ({ theme, ...props }: { theme?: unknown }) => (
261
276
  <pre {...props}>{JSON.stringify(theme)}</pre>
262
277
  );
@@ -272,7 +287,9 @@ it("should not remove theme if theme is passed to element", () => {
272
287
  <div>
273
288
  <pre
274
289
  class="test"
275
- />
290
+ >
291
+ {"anything":"test"}
292
+ </pre>
276
293
  </div>
277
294
  `);
278
295
  });
@@ -314,7 +331,9 @@ it("should not remove theme if theme is passed to wrapped element", () => {
314
331
  <div>
315
332
  <pre
316
333
  class="test-wrapper test"
317
- />
334
+ >
335
+ {"anything":"test"}
336
+ </pre>
318
337
  </div>
319
338
  `);
320
339
  });
@@ -22,7 +22,7 @@ const yakForwardRef: <TProps>(
22
22
  // warning: `__yak` is undefined during runtime
23
23
  __yak: true;
24
24
  } = (component) =>
25
- Object.assign(React.forwardRef(component), { component }) as any;
25
+ Object.assign(React.forwardRef(component), { yak: component }) as any;
26
26
 
27
27
  /**
28
28
  * All valid html tags
@@ -116,6 +116,8 @@ const yakStyled = <
116
116
  // prevents passing the theme prop to the DOM element of a styled component
117
117
  const { theme: themeAfterAttr, ...combinedPropsWithoutTheme } =
118
118
  combinedProps as { theme?: unknown };
119
+ const propsBeforeFiltering =
120
+ themeAfterAttr === theme ? combinedPropsWithoutTheme : combinedProps;
119
121
 
120
122
  const isYakComponent =
121
123
  typeof Component !== "string" && "yak" in Component;
@@ -123,10 +125,8 @@ const yakStyled = <
123
125
  // remove all props that start with a $ sign for string components e.g. "button" or "div"
124
126
  // so that they are not passed to the DOM element
125
127
  const filteredProps = !isYakComponent
126
- ? removePrefixedProperties(combinedPropsWithoutTheme)
127
- : themeAfterAttr === theme
128
- ? combinedPropsWithoutTheme
129
- : combinedProps;
128
+ ? removePrefixedProperties(propsBeforeFiltering)
129
+ : propsBeforeFiltering;
130
130
 
131
131
  // yak provides a className and style prop that needs to be merged with the
132
132
  // user provided className and style prop