-
-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
52 changed files
with
1,578 additions
and
10,644 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,4 @@ | ||
node_modules | ||
lib | ||
docs/.vitepress/cache | ||
docs/.vitepress/dist | ||
.DS_Store | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,262 @@ | ||
# 💧 MistCSS | ||
# MistCSS | ||
|
||
[![Node.js CI](https://github.com/typicode/mistcss/actions/workflows/node.js.yml/badge.svg)](https://github.com/typicode/mistcss/actions/workflows/node.js.yml) | ||
> Simplicity is the ultimate sophistication | ||
> Create components with 50% less code | ||
MistCSS lets you create reusable visual components without JavaScript or TypeScript (_think about it for a second... no JS/TS needed_). | ||
|
||
MistCSS is a new, better and faster way to write visual components. ~~CSS-in-JS~~? Nope! JS-from-CSS 👍 | ||
Leverage native HTML and CSS, get type safety and auto completion. Just clean and efficient styling. | ||
|
||
All major frameworks are supported. | ||
<img width="1116" alt="Screenshot 2024-11-01 at 03 47 44" src="https://github.com/user-attachments/assets/74aea071-be00-4d03-b43a-e46d6282e4b5"> | ||
|
||
## 1. Write your component in CSS only | ||
_What you see above is standard HTML ([data-attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*)) and CSS ([nested CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_nesting/Using_CSS_nesting)). MistCSS simply creates a `d.ts` file based on your CSS._ | ||
|
||
`./src/Button.mist.css` | ||
## Features | ||
|
||
- 🥶 Below zero-runtime, it's zero JavaScript. Smaller bundles and faster code. | ||
- 💎 What you write is what you get. No transformations, easy debugging. | ||
- 🎒 Standards-based, reusable styles across frameworks, compatible with Tailwind or any CSS framework | ||
- ⚡️ Instantly productive, no learning curve, simple onboarding. | ||
- 💖 Back to basics with a modern twist: access the full power of HTML and CSS, enhanced with type safety and code completion (without the complexity). | ||
|
||
## Usage | ||
|
||
Traditional approaches require wrapping your markup/styles in JavaScript functions (`Button.tsx` → `<button/>`, `Input.tsx` → `<input/>`, ...), defining props with TypeScript types, and writing logic to manage class names. | ||
|
||
With MistCSS, styling is straightforward and minimal. Here’s how it looks: | ||
|
||
`mist.css` | ||
|
||
```css | ||
@scope (button.custom-button) { | ||
:scope { | ||
background: black; | ||
button { | ||
border-radius: 1rem; | ||
padding: 1rem; | ||
background: lightgray; | ||
|
||
&[data-variant='primary'] { | ||
background-color: black; | ||
color: white; | ||
} | ||
|
||
&[data-variant='secondary'] { | ||
background-color: grey; | ||
color: white; | ||
} | ||
} | ||
``` | ||
|
||
/* 👇 Define component's props directly in your CSS */ | ||
&[data-variant='primary'] { | ||
background: blue; | ||
} | ||
`Page.tsx` | ||
|
||
&[data-variant='secondary'] { | ||
background: gray; | ||
} | ||
```jsx | ||
<> | ||
<button data-variant="primary">Save</button> | ||
<button data-variant="tertiary">Save</button> {/* TS error, tertiary isn't valid */} | ||
</> | ||
``` | ||
|
||
Output | ||
|
||
```jsx | ||
<button data-variant="primary">Save</button> {/* Same as in Page.tsx */} | ||
``` | ||
|
||
_This example demonstrates enums, but MistCSS also supports boolean and string props. For more details, see the FAQ._ | ||
|
||
## How does it work? | ||
|
||
MistCSS parses your `mist.css` file and generates `mist.d.ts` for type safety. | ||
|
||
For instance, here’s the generated `mist.d.ts` for our button component: | ||
|
||
```typescript | ||
interface Mist_button extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLButtonElement>, HTMLButtonElement> { | ||
'data-variant'?: 'primary' | 'secondary' | ||
} | ||
|
||
declare namespace JSX { | ||
interface IntrinsicElements { | ||
button: Mist_button // ← <button/> is extended at JSX level to allow 'primary' and 'secondary' values | ||
} | ||
} | ||
``` | ||
|
||
## 2. Run MistCSS codegen | ||
That’s it! Simple yet powerful, built entirely on browser standards and TypeScript/JSX. | ||
|
||
## Install | ||
|
||
```sh | ||
npm install mistcss --save-dev | ||
``` | ||
|
||
`postcss.config.js` | ||
|
||
```js | ||
module.exports = { | ||
plugins: { | ||
mistcss: {}, | ||
}, | ||
} | ||
``` | ||
|
||
`layout.tsx` | ||
|
||
```shell | ||
mistcss ./src --target=react --watch | ||
# It will create ./src/Button.mist.tsx | ||
```ts | ||
import './mist.css' | ||
``` | ||
|
||
## 3. Get a type-safe component without writing TypeScript | ||
## FAQ | ||
|
||
### Can I use CSS frameworks like Tailwind or Open Props? | ||
|
||
Absolutely, MistCSS is pure HTML and CSS, generating only `mist.d.ts`, so there are no limitations. You can integrate any CSS framework seamlessly. Here are a few examples to get you started: | ||
|
||
#### Tailwind v3 ([@apply](https://tailwindcss.com/docs/functions-and-directives#apply)) | ||
|
||
```css | ||
button { | ||
@apply bg-blue-500 text-white; | ||
/* ... */ | ||
} | ||
``` | ||
|
||
#### Tailwind v3 ([theme](https://tailwindcss.com/docs/functions-and-directives#theme)) | ||
|
||
```css | ||
button { | ||
background: theme(colors.blue.500); | ||
/* ... */ | ||
} | ||
``` | ||
|
||
#### Tailwind v4 | ||
|
||
Tailwind v4 will support CSS variables natively (see [blog post](https://tailwindcss.com/blog/tailwindcss-v4-alpha | ||
)). | ||
|
||
`./src/App.tsx` | ||
#### Tailwind (inline style) | ||
|
||
To override some styles, you can use `className` | ||
|
||
```jsx | ||
<button data-variant="primary" className="p-12"> | ||
Save | ||
</button> | ||
``` | ||
|
||
#### Open Props | ||
|
||
```css | ||
button { | ||
background-color: var(--blue-6); | ||
/* ... */ | ||
} | ||
``` | ||
|
||
### Can I do X without JavaScript? | ||
|
||
CSS is more powerful than ever, before reaching for JS, explore if native CSS features can accomplish what you need. | ||
|
||
### How to write enum, boolean, string props and conditions? | ||
|
||
```css | ||
div[data-component='section'] | ||
/* CSS variables */ | ||
--color: ...; | ||
|
||
/* Default styles */ | ||
background: var(--color, green); | ||
margin: ...; | ||
padding: ...; | ||
|
||
/* Enum props */ | ||
&[data-size="sm"] { ... } | ||
&[data-size="lg"] { ... } | ||
|
||
/* Boolean props */ | ||
&[data-is-active] { ... } | ||
|
||
/* Condition: size="lg" && is-active */ | ||
&[data-size="lg"]&[data-is-active] { ... } | ||
|
||
/* Condition: size="lg" && !is-active */ | ||
&[data-size="lg"]:not([data-is-active]) { ... } | ||
} | ||
``` | ||
|
||
```jsx | ||
<div | ||
data-component="section" | ||
data-size="foo" | ||
data-is-active | ||
style={{ '--color': 'red' }} | ||
/> | ||
``` | ||
|
||
### How to re-use the same tag | ||
|
||
If you want both basic links and button-styled links, here’s how you can do: | ||
|
||
```css | ||
a { /* ... */ } | ||
|
||
a[data-component='button'] { /* ... */ | ||
&[data-variant='primary'] { /* ... */ } | ||
} | ||
``` | ||
|
||
```jsx | ||
import { CustomButton } from './Button.mist' | ||
<> | ||
<a href="/home">Home</a> | ||
<a href="/home" data-component="button">Home</a> | ||
<a href="/home" data-component="button" data-variant="primary">Home</a> | ||
<a href="/home" data-variant="primary">Home</a> {/* TS error, `data-variant` is only valid with `data-component="button"` */} | ||
</> | ||
``` | ||
|
||
> [!NOTE] | ||
> `data-component` is just a naming convention. Feel free to use any attribute, like `data-style='button'` or `data-button`. It’s simply a way to differentiate between components using the same tag. | ||
|
||
### How to build complex components? | ||
|
||
export const App = () => ( | ||
<> | ||
<CustomButton variant="primary">Save</CustomButton> | ||
`mist.css` | ||
|
||
{/* TypeScript will catch the error */} | ||
<CustomButton variant="tertiary">Cancel</CustomButton> | ||
</> | ||
) | ||
```css | ||
article[data-component='card'] { /* ... */ } | ||
div[data-component='card-title'] { /* ... */ } | ||
div[data-component='card-content'] { /* ... */ } | ||
``` | ||
|
||
`Card.jsx` | ||
|
||
```jsx | ||
export function Card({ title, children }) { | ||
return ( | ||
<article data-component="card"> | ||
<div data-component="card-title">{title}</div> | ||
<div data-component="card-content">{children}</div> | ||
</article> | ||
) | ||
} | ||
``` | ||
|
||
MistCSS can generate ⚛️ **React**, 💚 **Vue**, 🚀 **Astro**, 🧠**Svelte** and 🔥 **Hono** components. You can use 🍃 **Tailwind CSS** to style them. | ||
> [!TIP] | ||
> To indicate that these styles aren't meant to be used outside of `Card`, you can name them `data-p-component` (`p` for `private`) or use another naming convention. | ||
## Documentation | ||
### How to define CSS variables | ||
|
||
```css | ||
:root { | ||
--primary-color: #007bff; | ||
--secondary-color: #6c757d; | ||
} | ||
|
||
button { | ||
background: var(--primary-color) | ||
/* ... */ | ||
``` | ||
|
||
https://typicode.github.io/mistcss | ||
See also your CSS framework/tooling documentation for ways to define them in JS if you prefer. | ||
|
||
## Supports | ||
### Origin of the project name? | ||
|
||
- [Next.js](https://nextjs.org/) | ||
- [Remix](https://remix.run/) | ||
- [React](https://react.dev/) | ||
- [Vue](https://vuejs.org) | ||
- [Svelte](https://svelte.dev/) | ||
- [Astro](https://astro.build/) | ||
- [Hono](https://hono.dev/) | ||
- [Tailwind CSS](https://tailwindcss.com/) | ||
Mist is inspired by atomized water 💧 often seen near waterfalls. A nod to the _Cascading_ in CSS 🌊. |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.