Skip to content

Commit

Permalink
Nested CSS Expressions (#44)
Browse files Browse the repository at this point in the history
Co-authored-by: Jan Nicklas <[email protected]>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 16, 2024
1 parent a7613d4 commit fe9dc90
Show file tree
Hide file tree
Showing 10 changed files with 1,015 additions and 506 deletions.
2 changes: 1 addition & 1 deletion packages/example/app/HighContrastToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const Button = styled.button<{ $primary?: boolean }>`
`
: css`
color: #009688;
`};
`}
background: #fff;
border: 1px solid currentColor;
font-size: 17px;
Expand Down
12 changes: 9 additions & 3 deletions packages/example/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ const headline = css<{ $primary?: boolean }>`
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
`};
`}
${queries.sm} {
font-size: 1.5rem;
${({ $primary }) =>
$primary &&
css`
font-size: 1.7rem;
`}
}
&:before,
Expand All @@ -50,14 +55,15 @@ const Headline = styled.h1<{ $primary?: boolean }>`
`;

const Button = styled.button<{ $primary?: boolean }>`
display: block;
${({ theme }) =>
theme.highContrast
? css`
color: ${colors.dark};
`
: css`
color: #009688;
`};
`}
background: #fff;
border: 1px solid currentColor;
font-size: 17px;
Expand Down Expand Up @@ -109,7 +115,7 @@ export default function Home() {
return (
<YakThemeProvider>
<main className={styles.main}>
<Headline>Hello world</Headline>
<Headline $primary>Hello world</Headline>
<Button>Ghost</Button>
<Button $primary>Primary Ghost</Button>
<FancyButton $primary title="fancy">
Expand Down
172 changes: 147 additions & 25 deletions packages/next-yak/README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,49 @@
# next-yak

yet another CSS-in-JS library
![Yak At Work as Frontend Dev](https://github.com/jantimon/next-yak/assets/4113649/2dcaf443-7205-4ef3-ba44-fbbe3ef2807d)

a CSS-in-JS with the power of "dynamic at the speed and reliability of static" 🙃
[![npm version](https://badge.fury.io/js/next-yak.svg)](https://www.npmjs.com/package/next-yak)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jantimon/next-yak/blob/main/LICENSE)

the initial version of next-yak will only work for next.js
**next-yak** is a CSS-in-JS solution tailored for [Next.js](https://nextjs.org/) that seamlessly combines the expressive power of styled-components syntax with efficient build-time extraction of CSS using Next.js's built-in CSS configuration.

![Yak At Work as Frontend Dev](https://github.com/jantimon/next-yak/assets/4113649/2dcaf443-7205-4ef3-ba44-fbbe3ef2807d)

## Features

## Example
- **NextJs Compatibility**: Works smoothly with both React Server and Client Components
- **Build-time CSS**: Reduces load time by handling CSS during the build phase, using Next.js built-in CSS Modules features
- **Lightweight Runtime**: Operates with minimal impact, simply changing CSS classes without modifying the CSSOM
- **Standard CSS Syntax**: Write styles in familiar, easy-to-use CSS
- **Integrates with Atomic CSS**: Easily combines with atomic CSS frameworks like Tailwind CSS for more design options

Try it on [stackblitz](https://stackblitz.com/edit/stackblitz-starters-dfykqy?file=app%2Fpage.tsx)
<video width="630" height="300" src="https://github.com/jantimon/next-yak/assets/4113649/cfacb70e-1b42-4a41-9706-f5e4da1fe8cd" alt="Code example"></video>

```tsx
import { styled, css } from "next-yak";

const Title = styled.h1<{ x: number; children: React.ReactNode }>`
display: block;
${({ $x }) => $x % 2 === 0 && css`color: red`}
position: relative;
top: ${({ $x }) => `${$x * 100}px`};
`;
## Installation

const App = () => (
<Title $x={3}>
Hello World
</Title>
);
```bash
npm install next-yak
```

## Installation
or

```bash
npm install next-yak
yarn add next-yak
```

## Getting Started

Try it on [stackblitz](https://stackblitz.com/edit/stackblitz-starters-dfykqy?file=app%2Fpage.tsx)

### Locally

1. Install **next-yak** in your Next.js project.

2. Add next-yak to your `next.config.js`:

```js
// next.config.js
const { withYak } = require("next-yak");
const { withYak } = require("next-yak/withYak");

const nextConfig = {
// your next.js config
Expand All @@ -47,6 +52,109 @@ const nextConfig = {
module.exports = withYak(nextConfig);
```

3. Ready to go:

```jsx
// pages/index.js
import { styled } from 'next-yak';

const StyledDiv = styled.div`
color: #333;
padding: 16px;
background-color: #f0f0f0;
`;

function HomePage() {
return <StyledDiv>Hello, next-yak!</StyledDiv>;
}

export default HomePage;
```

## More Examples

### Dynamic Styles

Dynamic Styles will only toggle the css class during runtime:

```jsx
import { styled, css } from 'next-yak';

const ToggleButton = styled.button`
${props => props.$active
? css`background-color: green`
: css`background-color: lime`
};
color: white;
padding: 10px 20px;
`;
```

<video width="630" height="300" src="https://github.com/jantimon/next-yak/assets/4113649/9065d0a0-f839-4d91-b05e-b3e72c7c2bb0" alt="Dynamic Styles example"></video>

### Dynamic Properties

Dynamic Properties use custom properties ([aka css variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)) under the hood to extract the CSS at built time but modify properties at runtime:

```jsx
import { styled } from 'next-yak';

const ProgressBar = styled.div`
width: ${props => `${props.$percent}%`};
height: 20px;
background-color: #3498db;
transition: width 0.3s ease-in-out;
`;

const ProgressBarContainer = styled.div`
border: 1px solid #ccc;
`;

const ExampleComponent = () => {
const progress = 75; // You can dynamically set this value

return (
<ProgressBarContainer>
<ProgressBar $percent={progress} />
</ProgressBarContainer>
);
};
```

<video width="630" height="300" src="https://github.com/jantimon/next-yak/assets/4113649/11e9aca7-f5c8-416b-bb67-67e180be81e8" alt="Dynamic Styles example"></video>

### Targeting Components

In next-yak, you can target other components directly using CSS selectors as long as they are **in the same file**:

```jsx
import { styled, keyframes } from 'next-yak';

const flip = keyframes`
from { transform: rotateY(0deg); }
to { transform: rotateY(360deg); }
`;

const Glow = styled.div`
/* Add your Glow component styles here */
`;

const Text = styled.span`
display: inline-block;
${Glow}:hover & {
animation: 1.5s ${flip} ease-out;
}
`;

const ExampleComponent = () => {
return (
<Glow>
<Text>This text will flip on hover.</Text>
</Glow>
);
};
```

## Nesting

`next-yak` supports nesting out of the box.
Expand Down Expand Up @@ -127,7 +235,7 @@ const Button = styled.button`

## Todos:

This is a proof of concept. There are a lot of things that need to be done before this can be used in production:
next-yak is currently in the development phase, with several todos that must be completed before it is ready for production:

- [ ] improve js parsing - right now it not reusing babel..
- [ ] better sourcemaps
Expand All @@ -150,6 +258,20 @@ This is a proof of concept. There are a lot of things that need to be done befor

</details>

## Prior art
## Acknowledgments

Special thanks to the contributors and the inspiring projects that influenced next-yak:

- Styled-Components 💅: For pioneering the styled syntax and redefining styling in the React ecosystem.
- Linaria: For its innovative approach to zero-runtime CSS in JS and efficient styling solutions.
- Emotion: For pushing the boundaries of CSS-in-JS and providing a high-performance styling experience.
- Vanilla Extract: For its focus on type-safe, zero-runtime CSS and contributing to the evolution of styling techniques.
- Tailwind CSS: For its exceptional atomic CSS approach, enabling efficient and customizable styling solutions.

## License

**next-yak** is licensed under the [MIT License](link/to/LICENSE).

---

This POC is heavily inspried by [styled-components](https://styled-components.com/), [emotion](https://emotion.sh/docs/introduction) and [linaria](https://github.com/callstack/linaria).
Feel free to reach out with any questions, issues, or suggestions!
Loading

0 comments on commit fe9dc90

Please sign in to comment.