diff --git a/README.md b/README.md index fade679..3775f84 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,18 @@ ![example code](./docs/assets/example-screenshot.png) -**Castella** is a Web Component-based CSS in JS library for React. - ```sh npm install @castella/runtime @castella/macro ``` +Browser requirements: support for [Custom Elements](https://caniuse.com/custom-elementsv1) ("Customized built-in elements" support is not required). + +## Overview + +**Castella** is a Web Components-based CSS in JS library for React. With the help of Web Components, Castella provides the best developer experience of writing styling components. + +See also: [Castella's Design Goals](./docs/design-goals.md). + ## How Castella Works? Castella creates a React component from given CSS string and HTML fragment. The generated component puts these CSS and HTML into its shadow DOM. @@ -18,6 +24,8 @@ Castella is implemented as a [Babel macro](https://github.com/kentcdodds/babel-p ## Usage +See also: [API Reference](./docs/api.md), [Server-Side Rendering](./docs/ssr.md) + To make Castella work, set up Babel macro (see below). Import `castella`, `css`, `html` and `slot` from `@castella/macro`. The `castella` function receives a CSS string which is created by `css` and an HTML object which is created by `html`. In order to let your component receive children, place `${slot()}` in your HTML string. @@ -124,7 +132,10 @@ If you are using create-react-app, babel-plugin-macros is already there. ## Example -This repository contains the `example/` directory where you can see some usage of Castella and also compare Castella with [styled-components](https://styled-components.com/) and [linaria](https://github.com/callstack/linaria). +This repository contains two examples. + +- `example/basic`: Shows basic usage of Castella. You can also compare Castella with [styled-components](https://styled-components.com/) and [linaria](https://github.com/callstack/linaria). +- `example/nextjs`: Shows usage of Castella with Next.js. ## Contributing diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..ee6e93d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,3 @@ +- [Castella's Design Goals](./design-goals.md) +- [API Reference](./api.md) +- [Server-Side Rendering](./ssr.md) \ No newline at end of file diff --git a/docs/design-goals.md b/docs/design-goals.md new file mode 100644 index 0000000..e0d6b15 --- /dev/null +++ b/docs/design-goals.md @@ -0,0 +1,108 @@ +# Castella's Design Goals + +Castella is a skosh opinionated as a CSS-in-JS library. This document explains why Castella is designed like this. + +## Couple Styles and Markups. + +As seen in [the example](../README.md), Castella's API forces you to tightly couple CSS (styles) and HTML (markups). This is in contrast to existing CSS-in-JS libraries (and also CSS Modules) that is className-oriented; any CSS results in a class name that is to be attached to arbitrary one element. + +Styles tend to be dispersed to multiple elements even if those styles have a single purpose. For example, Flexbox layout requires the parent to have `display: flex` and also often requires the child to have something like `flex: auto 1 0`. Scattered styles are hard to maintain, so we want to gather single-purposed styles to one place. + +Styles also depend on underlying markups. For example, an element with `display: flex` lays out its direct children. This is making it inadvisable to edit CSS without looking at underlying markups, or vice versa. + +For these reasons, we want to collect all CSS and HTML for one styling purpose at one place. This is what Castella enables you. + +The example below defines a component named `TwoColumn`, whose purpose is a two-column layout. Of notable is that this definition contains all the styles and markup structured needed for that purpose. + +```ts +export const TwoColumn = castella( + css` + display: flex; + + .aside { + flex: 100px 0 0; + } + .main { + flex: auto 1 0; + } + `, + html` +
${slot("aside")}
+
${slot("main")}
+ ` +); + +// Usage +Aside contents

} + main={

Main contents

} +/> + +// Rendered result + + #shadow-root (open) + +
+
+

Aside contents

+

Main contents

+
+``` + +The rendered element consists of three elements: `` with `display: flex`, `
` with `flex: 100px 0 0`, and `
` with `display: auto 1 0`, which are all we need for the desired layout. Contents given from outside are put into corresponding ``s. + +As you can see, the `TwoColumn` component includes just enough amount of CSS and HTML for one purpose. This is how Castella helps you define maintainable styling components. + +## Decouple Styles and Logics. + +One of our design principles is that we should decouple styling components and logic components. Ideally, all styles should be described inside styling components and logic components should not be aware of any styles. Also, elements rendered by logic components should not play any role in styling; they should be purely for semantic purpose. + +By using Castella, you are nearly forced to follow this style. For example, let's use above `TwoColumn` component in our app: + +```tsx +const App = () => { + return +

Navigation

+ + + } + main={ +
+

Welcome to our nice app!

+

Some contents

+
+ } + />; +} +``` + +Our `App` component focuses on semantical work. All the `
`s needed for styling is put inside the `TwoColumn` component. `App` could also include logics like `useState` as needed. If you need more styles, more styling components could be made and used. + +## Best Experience of Writing Styles. + +One of the key features of CSS-in-JS libraries is encapsulation of styles. While typical CSS-in-JS realizes this by generating unique class names, Castella makes use of Shadow DOM. (*Note: Castella's `styled` API is still based on class names.*) This enables the best CSS writing experience. + +In Castella components, you are free to use arbitrary class names (as in `TwoColumn` above). You do not have to consider class name conflicts, as your styles and markups are put into the component's own Shadow DOM and does not interact with outside. This is the most natural way of writing styles and markups, while is backed by the web standard. + +## Be Future-Proof. + +Castella's API is desiened so that it works well with future Web APIs, including [Declarative Shadow DOM](https://web.dev/declarative-shadow-dom/), [Constructable Stylesheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) and so on. When these new features become ready for use, Castella users will be able to benefit from them with minimal effort. + +## Easy to Opt out. + +Castella is based on program transformation with [Babel Macro](https://github.com/kentcdodds/babel-plugin-macros). This means that Castella components are fully statically-analizable. In case you want to move from Castella to another CSS-in-JS method, your effort is minimized as you can automate conversion from Castella to the other. \ No newline at end of file