Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 2.x #222

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,27 @@
[Preview (Video)](https://github.com/jantimon/next-yak/assets/4113649/f5a220fc-2a0f-46be-a8e7-c855f7faa337
)

## Compatibility

| next-yak version | Next.js version | swc_core version |
|------------------|-----------------|------------------|
| 3.x | 15.x | 3.0.2 |
| 2.x | 14.x | 0.279.0 |

Make sure to use a compatible version when installing:


## Installation

```bash
npm install next-yak
```
# For Next.js 15.x
npm install next-yak@3

or
# For Next.js 14.x
npm install next-yak@2

```bash
yarn add next-yak
# For Next.js 13.x
npm install next-yak@1
```

## Getting Started
Expand Down
9 changes: 9 additions & 0 deletions packages/next-yak/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@

### Patch Changes

- 6806558: Allow keyframe values to reference typed constants
- ea831c6: Fix typings of selectors within mixin
- Updated dependencies [f24770d]
- [email protected]

## 2.4.1

### Patch Changes

- Improve hashing of css variables ([email protected])

## 2.3.0
Expand Down
21 changes: 16 additions & 5 deletions packages/next-yak/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,27 @@
[Preview (Video)](https://github.com/jantimon/next-yak/assets/4113649/f5a220fc-2a0f-46be-a8e7-c855f7faa337
)

## Compatibility

| next-yak version | Next.js version | swc_core version |
|------------------|-----------------|------------------|
| 3.x | 15.x | 3.0.2 |
| 2.x | 14.x | 0.279.0 |

Make sure to use a compatible version when installing:


## Installation

```bash
npm install next-yak
```
# For Next.js 15.x
npm install next-yak@3

or
# For Next.js 14.x
npm install next-yak@2

```bash
yarn add next-yak
# For Next.js 13.x
npm install next-yak@1
```

## Getting Started
Expand Down
4 changes: 2 additions & 2 deletions packages/next-yak/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-yak",
"version": "2.4.0",
"version": "2.4.1",
"type": "module",
"types": "./dist/",
"license": "MIT",
Expand Down Expand Up @@ -78,7 +78,7 @@
"dependencies": {
"@babel/core": "7.23.2",
"@babel/plugin-syntax-typescript": "7.22.5",
"yak-swc": "0.8.0"
"yak-swc": "0.8.1"
},
"devDependencies": {
"@types/babel__core": "^7.1.14",
Expand Down
33 changes: 33 additions & 0 deletions packages/next-yak/runtime/__tests__/typeTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,36 @@ const GenericComponentWorks = () => {
);
};
};

const KeyframesWithConstants = () => {
const constString = "rotate(360deg)";
const constNumber = 360;

const rotate = keyframes`
from {
transform: rotate(${constNumber}deg);
}
to {
transform: ${constString};
}
`;
};

const SelectorMixinsShouldNotAlterType = () => {
const Button = styled.button<{ $primary?: boolean }>``;

const Mixin = css`
${Button} {
color: red;
}
`;

const X = styled.div`
${Button} {
color: blue;
}
${Mixin};
`;

<X />;
};
4 changes: 2 additions & 2 deletions packages/next-yak/runtime/cssLiteral.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type CSSFunction = <TProps = {}>(
...values: CSSInterpolation<TProps & { theme: YakTheme }>[]
) => ComponentStyles<TProps>;

type PropsToClassNameFn = (props: unknown) =>
export type PropsToClassNameFn = (props: unknown) =>
| {
className?: string;
style?: Record<string, string>;
Expand All @@ -61,7 +61,7 @@ type PropsToClassNameFn = (props: unknown) =>
export function css(styles: TemplateStringsArray, ...values: []): StaticCSSProp;
export function css<TProps = {}>(
styles: TemplateStringsArray,
...values: CSSInterpolation<TProps & { theme: YakTheme }>[]
...values: CSSInterpolation<NoInfer<TProps> & { theme: YakTheme }>[]
): ComponentStyles<TProps>;
export function css<TProps>(
...args: Array<any>
Expand Down
4 changes: 2 additions & 2 deletions packages/next-yak/runtime/keyframes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
* `;
* ```
*/
export const keyframes = (
export const keyframes = <T extends (string | number | bigint)[] = never>(
styles: TemplateStringsArray,
...dynamic: never[]
...dynamic: T
): string => {
// during compilation all args of keyframe are compiled
// to a string which references the animation name
Expand Down
66 changes: 9 additions & 57 deletions packages/next-yak/runtime/mocks/cssLiteral.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,6 @@
import { CSSProperties } from "react";
import type { YakTheme } from "../index.d.ts";
import { yakComponentSymbol } from "../cssLiteral.js";
import type { css as cssInternal, PropsToClassNameFn } from "../cssLiteral.js";

type ComponentStyles<TProps> = (props: TProps) => {
className: string;
style?: {
[key: string]: string;
};
};

export type StaticCSSProp = {
className: string;
style?: CSSProperties;
};

export type CSSInterpolation<TProps> =
| string
| number
| undefined
| null
| false
| ComponentStyles<TProps>
| StaticCSSProp
| {
// type only identifier to allow targeting components
// e.g. styled.svg`${Button}:hover & { fill: red; }`
[yakComponentSymbol]: any;
}
| ((props: TProps) => CSSInterpolation<TProps>);

type CSSStyles<TProps = {}> = {
style: { [key: string]: string | ((props: TProps) => string) };
};

type CSSFunction = <TProps = {}>(
styles: TemplateStringsArray,
...values: CSSInterpolation<TProps & { theme: YakTheme }>[]
) => ComponentStyles<TProps>;

type PropsToClassNameFn = (props: unknown) =>
| {
className?: string;
style?: Record<string, string>;
}
| PropsToClassNameFn;
export type { StaticCSSProp, CSSInterpolation } from "../cssLiteral.js";

/**
* Allows to use CSS styles in a styled or css block
Expand All @@ -57,17 +14,12 @@ type PropsToClassNameFn = (props: unknown) =>
* `;
* ```
*/
export function css(styles: TemplateStringsArray, ...values: []): StaticCSSProp;
export function css<TProps = {}>(
export const css: typeof cssInternal = (
styles: TemplateStringsArray,
...values: CSSInterpolation<TProps & { theme: YakTheme }>[]
): ComponentStyles<TProps>;
export function css<TProps>(
styles: TemplateStringsArray,
...args: CSSInterpolation<TProps & { theme: YakTheme }>[]
): StaticCSSProp | ComponentStyles<TProps> {
...args: unknown[]
) => {
const dynamicCssFunctions: PropsToClassNameFn[] = [];
for (const arg of args as Array<string | CSSFunction | CSSStyles<any>>) {
for (const arg of args as Array<string | Function | object>) {
// Dynamic CSS e.g.
// css`${props => props.active && css`color: red;`}`
// compiled -> css((props: { active: boolean }) => props.active && css("yak31e4"))
Expand All @@ -81,7 +33,7 @@ export function css<TProps>(
style: undefined,
};
}
return (<T>(props: T) => {
return ((props: unknown) => {
for (let i = 0; i < dynamicCssFunctions.length; i++) {
// run the dynamic expressions and ignore the return value
// the execution is important to ensure that the user code is executed
Expand All @@ -92,8 +44,8 @@ export function css<TProps>(
className: "",
style: undefined,
};
}) as ComponentStyles<TProps>;
}
}) as any;
};

function executeDynamicExpressionRecursively(
props: unknown,
Expand Down
7 changes: 3 additions & 4 deletions packages/next-yak/runtime/mocks/keyframes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { keyframes as keyframesInternal } from "../keyframes.js";

/**
* Allows to use CSS keyframe animations in a styled or css block
*
Expand All @@ -20,10 +22,7 @@
* `;
* ```
*/
export const keyframes = (
styles: TemplateStringsArray,
...dynamic: never[]
): string => {
export const keyframes: typeof keyframesInternal = (styles, ...dynamic) => {
// the keyframes function is a no-op in the mock
// as it has no dynamic runtime behavior but only css
return "";
Expand Down
2 changes: 1 addition & 1 deletion packages/next-yak/runtime/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ const yakStyled = <
CSSInterpolation<T & NoInfer<TCSSProps> & { theme: YakTheme }>
>
) => {
const getRuntimeStyles = css(styles, ...values);
const getRuntimeStyles = css(styles, ...(values as any));
const yak = (props: Substitute<TCSSProps & T, TAttrsIn>, ref: unknown) => {
// if the css component does not require arguments
// it can be called without arguments and we skip calling useTheme()
Expand Down
6 changes: 6 additions & 0 deletions packages/yak-swc/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# yak-swc

## 0.8.1

### Patch Changes

- f24770d: Better error message for wrong usage of dynamic properties in nested template

## 0.8.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/yak-swc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "yak-swc",
"version": "0.8.0",
"version": "0.8.1",
"description": "next-yak rust based swc plugin to compile styled components at build time",
"homepage": "https://yak.js.org/",
"repository": {
Expand Down
23 changes: 20 additions & 3 deletions packages/yak-swc/yak_swc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,9 @@ where
});
}
}
// A property with a dynamic value
// e.g. styled.button`${({$color}) => css`color: ${$color}`};`
else {
// A property with a dynamic value in the top scope
// e.g. styled.button`color: ${myColor};`
else if is_top_level {
HANDLER.with(|handler| {
handler
.struct_span_err(
Expand All @@ -353,6 +353,23 @@ where
)
.emit();
});
// A property with a dynamic value
// e.g. styled.button`${({$color}) => css`color: ${$color}`};`
} else {
HANDLER.with(|handler| {
handler
.struct_span_err(
expr.span(),
&format!(
"The shorthand access to the variable \"{var}\" is not allowed in a nested expression.
To be able to use the property turn it into a CSS variable by wrapping it in a function:

${{() => {var}}};\n",
var=scoped_name.id.0
),
)
.emit();
});
}
}
// Handle inline css literals
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { styled, css } from "next-yak";

// example taken from https://github.com/jantimon/next-yak/issues/208

const spacing = "20px";

const ContainerFluid = styled.div`
position: relative;
margin: 0 auto;
padding-top: ${spacing};
max-width: 100%;

${({ $isApp, $pageHeaderHeight }) =>
$isApp ? css`
margin-top: unset;
` : css`
margin-top: ${$pageHeaderHeight}px;
`};

margin-top: ${({ $pageHeaderHeight }) => $pageHeaderHeight}px;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
x The shorthand access to the variable "$pageHeaderHeight" is not allowed in a nested expression.
| To be able to use the property turn it into a CSS variable by wrapping it in a function:
|
| ${() => $pageHeaderHeight};
|
,-[input.js:17:1]
16 | ` : css`
17 | margin-top: ${$pageHeaderHeight}px;
: ^^^^^^^^^^^^^^^^^
18 | `};
`----
Loading