Skip to content
Merged
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ install: ## Install project dependencies
npm install
npm install --prefix demo/melange


.PHONY: pin
pin: ## pin
opam pin add server-reason-react.0.4.1 "https://github.com/ml-in-barcelona/server-reason-react.git#56bbe2c3d9bcfad46ce491e110bc963899d33c51" -y
Expand Down
19 changes: 19 additions & 0 deletions packages/website/app/[[...mdxPath]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { generateStaticParamsFor, importPage } from "nextra/pages";

export const generateStaticParams = generateStaticParamsFor("mdxPath");

type PageProps = Readonly<{
params: Promise<{ mdxPath?: string[] }>;
}>;

export async function generateMetadata({ params }: PageProps) {
const { mdxPath } = await params;
const { metadata } = await importPage(mdxPath);
return metadata;
}

export default async function Page({ params }: PageProps) {
const { mdxPath } = await params;
const { default: MDXContent } = await importPage(mdxPath);
return <MDXContent params={params} />;
}
61 changes: 61 additions & 0 deletions packages/website/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import type { Metadata } from "next";
import type { FC, ReactNode } from "react";
import { getPageMap } from "nextra/page-map";
import { Layout } from "../src/index";
import "../src/css/fonts.css";
import "../src/css/global.css";

export const metadata: Metadata = {
title: {
absolute: "styled-ppx",
template: "%s | styled-ppx",
},
description: "Typed styled components in ReScript, Melange and OCaml",
};

const RootLayout: FC<{ children: ReactNode }> = async ({ children }) => {
const pageMap = await getPageMap();
return (
<html lang="en" suppressHydrationWarning>
<head>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicon/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicon/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicon/favicon-16x16.png"
/>
<link rel="manifest" href="/favicon/site.webmanifest" />
<link
rel="mask-icon"
href="/favicon/safari-pinned-tab.svg"
color="#000000"
/>
<link
href="https://fonts.googleapis.com/css2?family=Archivo&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Archivo+Black&display=swap"
rel="stylesheet"
/>
<script async src="https://cdn.splitbee.io/sb.js" />
</head>
<body>
<Layout pageMap={pageMap}>{children}</Layout>
</body>
</html>
);
};

export default RootLayout;
36 changes: 36 additions & 0 deletions packages/website/content/_meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export default {
"index": {
"title": "Introduction",
"theme": {
"breadcrumb": false,
"toc": false
}
},
"getting-started": "Getting Started",
"editor-support": "Editor Support",
"reference": "API Reference",
"about": {
"title": "About",
"theme": {
"breadcrumb": false
}
},
"css-support": {
"title": "CSS Support",
"theme": {
"breadcrumb": false
}
},
"faq": {
"title": "FAQ",
"theme": {
"breadcrumb": false
}
},
"releases": {
"title": "Releases",
"theme": {
"breadcrumb": false
}
}
}
49 changes: 49 additions & 0 deletions packages/website/content/about.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: About
---

import { Re, Res } from "../src/components/language-content";

# About

Author and maintainer: [David Sancho](https://sancho.dev)

<br />

# Motivation

There are a few reasons why this project exists and why it came to live.

### There was a need
In my experience, writing React with a CSS-in-JS library is one of the best combos for writing scalable design systems, UI libraries and applications. When I discovered Reason back in the day (around 2018), it wasn't possible to bind to styled-components or emotion. Even [a](https://reasonml.chat/t/idiomatic-way-to-bind-to-styled-components/886) [f](https://reasonml.chat/t/styled-components-possible/554)[e](https://reasonml.chat/t/styling-solutions-reasonreact-as-of-aug-18/958)[w](https://reasonml.chat/t/options-and-best-practices-for-styling-in-reasonreact/261) [p](https://twitter.com/lyovson/status/1233397294311100417)[e](https://discord.gg/byjdYFH)[o](https://discord.gg/byjdYFH)[p](https://discord.gg/byjdYFH)[l](https://discord.gg/byjdYFH)[e](https://forum.rescript-lang.org/t/how-to-create-bindings-for-emotion-styled/2995) were asking for it.

During that time, there were a few efforts to bring type-safety to CSS with [bs-css](https://github.com/giraud/bs-css) and [bs-emotion](https://github.com/ahrefs/bs-emotion). Even though I liked that approach, it had a few drawbacks:
- The need for learning a new DSL on top of CSS was tedious. Very fancy for simple properties, but almost impossible for more complex ones (a classic example `width: calc(100% - 20px){:styled-ppx-css}` became `CSS.width(calc(min, percent(100.), px(20))){:rescript}` `CSS.width(calc(min, percent(100.), px(20)));{:reason}`). In real world usage I would end up using `CSS.unsafe`.
- The runtime was huge. The bundle-size of bs-css starts with 64kb and goes up considerably with the usage, even with the dead code elimination made by the compiler.
- The fact of having a runtime involved to only write safe CSS doesn't seem like a nice trade-off.

### It's possible and a good solution
Embedding CSS inside Reason/OCaml seemed like a bad idea at first, mostly since most CSS-in-JS solutions that use native CSS relied on a JavaScript feature that isn't available in Reason: [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).

After discovering what a ppx was (*"a mechanism to embed other languages inside Reason"*), and it could mimic the template literals, I jumped straight into hacking a prototype that became this project.

Embedding languages inside others isn't a new concept and has been happening for a long time. In fact, the most common case of an embedded language is usually CSS inside HTML.
Using CSS enables all sorts of integrations: Editors, DevTools, prototyping tools, Github Copilot, etc. Even for designers that don't want to understand or care about <Res>ReScript</Res><Re>Reason</Re>.

### It can be more powerful than the JavaScript equivalents
Enabling type-safety in CSS is a nice to have, rather than a hard requirement, but nevertheless useful. styled-ppx brings an entire CSS compiler and type-chcker. This enables features from SASS (like supporting future CSS version features) with features from emotion to inline your styles and code together.
Features that aren't implemented but are on the horizon are mostly related in extracting the CSS from the runtime and making your styles static at runtime and have zero run-time.

To know more about how it works or what are the benefits I recommend you watch [my talk at ReasonSTHLM Meetup](https://www.youtube.com/watch?v=ekHCBZiCviM).

## Credits

Here's a list of people that helped me and I couldn't have made styled-ppx without them:

- [Javier Chávarri](https://github.com/jchavarri): for the introduction to Reason. Teaching me all his knowledge about OCaml, AST, ppx rewriters and the help of bootstrapping the project.
- [Alessandro Strada](https://github.com/astrada): this project started with inspiration from [bs-css-ppx](https://github.com/astrada/ppx_bs_css).
- [Eduardo Rafael](https://github.com/EduardoRFS/): to teach me how to write a compiler and a type-checker. His initial implementation of the CSS Value definition and the parser combinator.
- [Rizo](https://github.com/rizo): for the help with the API design, discussions and great conversations about styling and CSS.
- [Max Lantas](https://github.com/mnxn): for implementing the VSCode extension.
- [Egor Chemohonenko](https://github.com/ixzzd): for implementing the vim plugin.
- This project builds on a long line of earlier work by clever folks in the JavaScript community from around the world. People from [styled-components](https://github.com/styled-components/styled-components), [emotion](https://github.com/emotion-js/emotion), [compiledcssinjs](https://github.com/atlassian-labs/compiled), [linaria](https://github.com/callstack/linaria), and many more.
86 changes: 86 additions & 0 deletions packages/website/content/css-support.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
title: CSS Support
---

# CSS Support

The **styled-ppx** CSS parser supports [CSS Syntax Module Level 3](https://www.w3.org/TR/css-syntax-3/) almost completely. We ensure that most CSS supported is used day to day and available in most major browsers.

There are a few levels of support in **styled-ppx**:
- **Parser support**: The parser understands CSS3.
- **Code generation support**: Can transform the CSS into CSS bindings.
- **Interpolation support**: We can interpolate values from outside of CSS creating type-safe holes.

## Detailed view of the parsing support

✅: Fully supported
🟠: Partially supported
🔴: Not supported

If you want to know which properties are supported, you can check our test here: https://github.com/davesnx/styled-ppx/blob/main/packages/ppx/test/css-support.

---
| **CSS Feature** | **Link** | **Supported** |
|-------------------------------------------------------------- |------------------------------------------- |--------------- |
| Compositing and Blending Level 1 | https://www.w3.org/TR/compositing-1 | ✅ |
| CSS Backgrounds and Borders Module Level 3 | https://www.w3.org/TR/css-backgrounds-3 | 🟠 |
| CSS Box Sizing Module Level 3 | https://www.w3.org/TR/css-box-3 | 🟠 |
| CSS Cascading and Inheritance Level 3 | https://www.w3.org/TR/css-cascade-3 | ✅ |
| CSS Cascading and Inheritance Level 4 | https://www.w3.org/TR/css-cascade-4 | 🔴 |
| CSS Color Module Level 3 | https://www.w3.org/TR/css-color-3 | ✅ |
| CSS Color Module Level 4 | https://www.w3.org/TR/css-color-4 | 🟠 |
| CSS Color Adjustment Module Level 1 | https://www.w3.org/TR/css-color-adjust-1 | 🔴 |
| CSS Conditional Rules Level 3 | https://www.w3.org/TR/css-conditional-3 | 🔴 |
| CSS Containment Module Level 1 | https://www.w3.org/TR/css-contain-1 | ✅ |
| CSS Containment Module Level 2 | https://www.w3.org/TR/css-contain-2 | 🔴 |
| CSS Counter Styles Level 3 | https://www.w3.org/TR/css-counter-styles-3 | 🔴 |
| CSS Display Module Level 3 | https://www.w3.org/TR/css-display-3 | 🟠 |
| CSS Easing Functions Level 1 | https://www.w3.org/TR/css-easing-1 | ✅ |
| CSS Flexible Box Layout Module Level 1 | https://www.w3.org/TR/css-flexbox-1 | ✅ |
| CSS Fonts Module Level 3 | https://www.w3.org/TR/css-fonts-3 | 🟠 |
| CSS Fonts Module Level 4 | https://www.w3.org/TR/css-fonts-4 | 🟠 |
| CSS Grid Layout Module Level 1 | https://www.w3.org/TR/css-grid-1 | 🟠 |
| CSS Grid Layout Module Level 2 | https://www.w3.org/TR/css-grid-2 | 🔴 |
| CSS Images Module Level 3 | https://www.w3.org/TR/css-images-3 | 🔴 |
| CSS Images Module Level 4 | https://www.w3.org/TR/css-images-4 | 🔴 |
| CSS Lists and Counters Module Level 3 | https://www.w3.org/TR/css-lists-3 | 🔴 |
| CSS Logical Properties and Values Level 1 | https://www.w3.org/TR/css-logical-1 | 🟠 |
| CSS Multi-column Layout Module Level 1 | https://www.w3.org/TR/css-multicol-1 | 🟠 |
| CSS Positioned Layout Module Level 3 | https://www.w3.org/TR/css-position-3 | ✅ |
| CSS Box Sizing Module Level 3 | https://www.w3.org/TR/css-sizing-3 | ✅ |
| CSS Box Sizing Module Level 4 | https://www.w3.org/TR/css-sizing-4 | 🟠 |
| CSS Style Attributes | https://www.w3.org/TR/css-style-attr | ✅ |
| CSS Transforms Module Level 1 | https://www.w3.org/TR/css-transforms-1 | 🟠 |
| CSS Transforms Module Level 2 | https://www.w3.org/TR/css-transforms-2 | ✅ |
| CSS Basic User Interface Module Level 3 | https://www.w3.org/TR/css-ui-3 | ✅ |
| CSS Values and Units 3 | https://www.w3.org/TR/css-values-3 | 🟠 |
| CSS Custom Properties for Cascading Variables Module Level 1 | https://www.w3.org/TR/css-variables-1 | 🔴 |
| CSS Will Change Module Level 1 | https://www.w3.org/TR/css-will-change-1 | ✅ |
| CSS Writing Modes Level 3 | https://www.w3.org/TR/css-writing-modes-3 | ✅ |
| Media Queries Level 3 | https://www.w3.org/TR/css3-mediaqueries | 🟠 |
| CSS Namespaces Module Level 3 | https://www.w3.org/TR/css-namespaces-3 | 🟠 |
| Selectors Level 3 | https://www.w3.org/TR/selectors-3 | ✅ |
| Selectors Level 4 | https://www.w3.org/TR/selectors-4 | 🟠 |
| CSS Box Alignment Module Level 3 | https://www.w3.org/TR/css-align-3 | ✅ |
| CSS Animations Level 1 | https://www.w3.org/TR/css-animations-1 | ✅ |
| CSS Fragmentation Module Level 3 | https://www.w3.org/TR/css-break-3 | ✅ |
| CSS Font Loading Module Level 3 | https://www.w3.org/TR/css-font-loading-3 | 🔴 |
| CSS Masking Module Level 1 | https://www.w3.org/TR/css-masking-1 | 🟠 |
| CSS Scroll Snap Module Level 1 | https://www.w3.org/TR/css-scroll-snap-1 | 🟠 |
| CSS Scrollbars Styling Module Level 1 | https://www.w3.org/TR/css-scrollbars-1 | 🔴 |
| CSS Shapes Module Level 1 | https://www.w3.org/TR/css-shapes-1 | 🔴 |
| CSS Speech Module | https://www.w3.org/TR/css-speech-1 | 🔴 |
| CSS Text Module Level 3 | https://www.w3.org/TR/css-text-3 | 🟠 |
| CSS Text Decoration Module Level 3 | https://www.w3.org/TR/css-text-decor-3 | ✅ |
| CSS Transitions | https://www.w3.org/TR/css-transitions-1 | ✅ |
| CSS Writing Modes Level 4 | https://www.w3.org/TR/css-writing-modes-4 | ✅ |
| Filter Effects Module Level 1 | https://www.w3.org/TR/filter-effects-1 | 🟠 |
| Media Queries Level 4 | https://www.w3.org/TR/mediaqueries-4 | 🟠 |

<small>This table has been generated manually and it might be outdated.</small>

All references are found in [w3.org](https://www.w3.org)
- [(CSS 1.0) Cascading Style Sheets Level 1](https://www.w3.org/TR/CSS1/) ✅
- [(CSS 2.1) Cascading Style Sheets Level 2 Revision 1 Specification](https://www.w3.org/TR/CSS21/) ✅
- [(CSS 2.2) Cascading Style Sheets Level 2 Revision 2 Specification](https://www.w3.org/TR/CSS22/) ✅
- [(CSS 3.0) CSS Syntax Module Level 3](https://www.w3.org/TR/css-syntax-3/) ✅
34 changes: 34 additions & 0 deletions packages/website/content/editor-support.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
title: Editor Support
---

import { Re, Res } from "../src/components/language-content";

# Editor Support

One of the downsides of embedding a language (CSS) into another language (<Res>ReScript</Res><Re>Reason</Re>) is the limited editor support. Because of that, we provide an editor extension that brings syntax highlighting for the CSS inside the styled-ppx notation.

## VSCode Extension

Install the **[VSCode Extension](https://marketplace.visualstudio.com/items?itemName=davesnx.vscode-styled-ppx)** via the marketplace or via the command line:

```bash
ext install davesnx.vscode-styled-ppx
```

## Vim Plugin

Install the vim plugin with VimPlug, Vundle or Pathogen:

### with VimPlug
Add `Plug 'ahrefs/vim-styled-ppx'` to your `~/.vimrc` and run PlugInstall.

### with Vundle
Add `Plugin 'ahrefs/vim-styled-ppx'` to your `~/.vimrc` and run PluginInstall.

### with Pathogen
```bash
$ git clone https://github.com/ahrefs/vim-styled-ppx ~/.vim/bundle/vim-log-highlighting
```

> If you are interested on another editor, please [file an issue](https://github.com/davesnx/styled-ppx/issues/new).
14 changes: 14 additions & 0 deletions packages/website/content/faq.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: Frequently asked questions
---

# Frequently asked questions

## Does it support ReScript, Reason and OCaml syntax?

Yes, all are supported. Since the ppx transformation operates on the AST and all of those languages share the majority of the AST, it's possible to support all of them. Note that, ReScript has been challenging since they are exploring new patterns of the language and are diverging from the OCaml AST.

You can use the language selector in the sidebar to switch between the different syntaxes. All snippets on this page are written in Reason and ReScript.

As well, our [VSCode extension](https://marketplace.visualstudio.com/items?itemName=davesnx.vscode-styled-ppx) supports ReScript, Reason, and OCaml syntaxes.

5 changes: 5 additions & 0 deletions packages/website/content/getting-started/_meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
"rescript": "ReScript",
"melange": "Melange",
"native": "Native"
}
Loading
Loading