Skip to content

Commit

Permalink
Merge branch 'feat/4.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
ghivert committed Jan 12, 2025
2 parents 2745002 + 30819e8 commit e8ca108
Show file tree
Hide file tree
Showing 22 changed files with 285 additions and 127 deletions.
4 changes: 2 additions & 2 deletions sketch/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## v4.0.0 - Unreleased
## v4.0.0 - 2024-01-12

v4.0.0 marks a major release for Sketch! It bundles new improvements, new
features, and improve namespacing! Six months after the initial release of v3,
features, and improved namespacing! Six months after the initial release of v3,
v4 marks a new milestone as Sketch gains in maturity, usability and usage. More
and more people are using it, and as such, Sketch has to evolve in the right
path!
Expand Down
12 changes: 9 additions & 3 deletions sketch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ abstraction allows a greater flexibility, without adding too much burden, as
they're still all generated at runtime. Sketch favour explicitness and CSS
generation for every node instead of relying on cascading and inheritance.

## Examples

Want to see examples to jump directly on subject? Take a look at
[e2e folder on GitHub](https://github.com/ghivert/sketch/tree/main/e2e) to see
how it works!

## Sketch Lustre

### Setup
Expand Down Expand Up @@ -119,7 +125,7 @@ simple node, without any class linked on it.

```gleam
import sketch/css
import sketch/csssize.{px}
import sketch/css/length.{px}
import sketch/lustre/element
import sketch/lustre/element/html
Expand Down Expand Up @@ -209,7 +215,7 @@ time.
```gleam
import redraw/html as h
import sketch/css
import sketch/css/size.{px}
import sketch/css/length.{px}
import sketch/redraw/html
fn main_style() {
Expand Down Expand Up @@ -384,8 +390,8 @@ to call the proper functions, and Sketch will take care of the rest.

```gleam
import sketch/css
import sketch/css/length.{px}
import sketch/css/media
import sketch/css/size.{px}
fn my_class() {
css.class([
Expand Down
2 changes: 1 addition & 1 deletion sketch/gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ path = "sketch"
[dependencies]
gleam_erlang = ">= 0.25.0 and < 1.0.0"
gleam_otp = ">= 0.10.0 and < 1.0.0"
gleam_stdlib = ">= 0.34.0 and < 1.0.0"
gleam_stdlib = ">= 0.42.0 and < 1.0.0"

[dev-dependencies]
birdie = ">= 1.2.5 and < 2.0.0"
Expand Down
2 changes: 1 addition & 1 deletion sketch/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ packages = [
birdie = { version = ">= 1.2.5 and < 2.0.0" }
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
gleam_otp = { version = ">= 0.10.0 and < 1.0.0" }
gleam_stdlib = { version = ">= 0.34.0 and < 1.0.0" }
gleam_stdlib = { version = ">= 0.42.0 and < 1.0.0" }
startest = { version = ">= 0.6.0 and < 1.0.0" }
4 changes: 3 additions & 1 deletion sketch/src/sketch.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn render(cache: StyleSheet) -> String {
}

@target(javascript)
/// Convert a `Class` to its class name, to use it anywhere in your application.
/// Converts a `Class` to its class name, to use it anywhere in your application.
/// It always returns the StyleSheet, because the class can have been pushed
/// in the StyleSheet itself.
pub fn class_name(class: Class, stylesheet: StyleSheet) -> #(StyleSheet, String) {
Expand All @@ -45,6 +45,8 @@ pub fn class_name(class: Class, stylesheet: StyleSheet) -> #(StyleSheet, String)
}

@target(javascript)
/// Pushes an `@rule` in the StyleSheet, to get it bundled in the outputted CSS.
/// It returns the StyleSheet with the rule added.
pub fn at_rule(rule: AtRule, stylesheet: StyleSheet) -> StyleSheet {
let cache = cache.at_rule(rule, stylesheet.cache)
StyleSheet(..stylesheet, cache:)
Expand Down
20 changes: 10 additions & 10 deletions sketch/src/sketch/css.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub type Style =
pub type Class =
style.Class

/// Represents an at-rule.
/// Represents an [at-rule](https://developer.mozilla.org/docs/Web/CSS/At-rule).
pub type AtRule =
style.AtRule

Expand Down Expand Up @@ -137,15 +137,15 @@ pub fn all(value: String) -> Style {
/// ---
///
/// This property is a shorthand for the following CSS properties:
/// [`animation-delay`](https://developer.mozilla.org/docs/Web/CSS/animation-delay)
/// [`animation-direction`](https://developer.mozilla.org/docs/Web/CSS/animation-direction)
/// [`animation-duration`](https://developer.mozilla.org/docs/Web/CSS/animation-duration)
/// [`animation-fill-mode`](https://developer.mozilla.org/docs/Web/CSS/animation-fill-mode)
/// [`animation-iteration-count`](https://developer.mozilla.org/docs/Web/CSS/animation-iteration-count)
/// [`animation-name`](https://developer.mozilla.org/docs/Web/CSS/animation-name)
/// [`animation-play-state`](https://developer.mozilla.org/docs/Web/CSS/animation-play-state)
/// [`animation-timeline`](https://developer.mozilla.org/docs/Web/CSS/animation-timeline)
/// [`animation-timing-function`](https://developer.mozilla.org/docs/Web/CSS/animation-timing-function)
/// - [`animation-delay`](https://developer.mozilla.org/docs/Web/CSS/animation-delay)
/// - [`animation-direction`](https://developer.mozilla.org/docs/Web/CSS/animation-direction)
/// - [`animation-duration`](https://developer.mozilla.org/docs/Web/CSS/animation-duration)
/// - [`animation-fill-mode`](https://developer.mozilla.org/docs/Web/CSS/animation-fill-mode)
/// - [`animation-iteration-count`](https://developer.mozilla.org/docs/Web/CSS/animation-iteration-count)
/// - [`animation-name`](https://developer.mozilla.org/docs/Web/CSS/animation-name)
/// - [`animation-play-state`](https://developer.mozilla.org/docs/Web/CSS/animation-play-state)
/// - [`animation-timeline`](https://developer.mozilla.org/docs/Web/CSS/animation-timeline)
/// - [`animation-timing-function`](https://developer.mozilla.org/docs/Web/CSS/animation-timing-function)
///
/// ---
///
Expand Down
8 changes: 8 additions & 0 deletions sketch/src/sketch/css/font_face.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
//// The `@font-face` CSS at-rule specifies a custom font with which to display
//// text; the font can be loaded from either a remote server or a
//// locally-installed font on the user's own computer.
////
//// ---
////
//// [MDN Reference](https://developer.mozilla.org/docs/Web/CSS/@font-face)

import gleam/float

/// A `FontFace` is a part of a `@font-face` rule.
Expand Down
10 changes: 10 additions & 0 deletions sketch/src/sketch/css/keyframe.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//// The `@keyframes` CSS [at-rule](https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule)
//// controls the intermediate steps in a CSS animation sequence by defining
//// styles for keyframes (or waypoints) along the animation sequence. This
//// gives more control over the intermediate steps of the animation sequence
//// than [transitions](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_transitions).
////
//// ---
////
//// [MDN Reference](https://developer.mozilla.org/docs/Web/CSS/@keyframes)

import gleam/int
import sketch/internals/cache/cache as style

Expand Down
93 changes: 71 additions & 22 deletions sketch_css/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
Sketch CSS is a tool to generate CSS from Sketch Class definitions. Because pure
CSS generation is straightforward, `sketch_css` does not need a cache to
generate correct CSS files. Instead, `sketch_css` ships with a CLI tool, able to
read your Gleam styles files, and output corresponding your CSS automagically,
while providing an abstraction layer written in Gleam, to make sure you're using
the right classes! It's an other way to leverage Sketch core and enjoy the
styling in Gleam, while taking advantage of all the static CSS power!
read your Gleam styles files, and output corresponding CSS automagically, while
providing an abstraction layer written in Gleam, to make sure you're using the
right classes! It's an other way to leverage Sketch core and enjoy the styling
in Gleam, while taking advantage of all the static CSS power!

To run the generator, you have to use the command
`gleam run -m sketch/css generate` at the root of your project. By default,
Expand All @@ -25,16 +25,59 @@ in `src/sketch/styles`, matching your styles files, to use in your project!

### Options

Sketch CSS generation has strong defaults, but everything can be customised. Use
the CLI flags to configure what you need. CLI exposes 3 flags:
Sketch CSS generation has strong defaults, but everything can be customised. To
pass options to Sketch CSS, you have three ways:

- Pass them directly on the CLI. Every option has its equivalent exposed in the
CLI.
- Write them in a `sketch_css.toml` file, at root of your project, next
`gleam.toml`.
- Write them directly in `gleam.toml`, under `[sketch_css]` section.

Sketch CSS has 3 distinct options:

- `--dest`, accepting a folder, relative to current directory. It defaults to
`styles`
`styles`.
- `--src`, accepting a folder, relative to current directory. It defaults to
`src`.
- `--interface`, accepting a folder, relative to current directory. It defaults
to `src/sketch/styles`.

Write directly the folder, path resolution is done with current working
directory as root.

#### Examples

```sh
gleam run -m sketch_css generate --src="src" --dest="styles" --interface="src/sketch/styles"
```

```toml
# sketch_css.toml
src = "src"
dest = "styles"
interface = "src/sketch/styles"
```

```toml
# gleam.toml
name = "name"
version = "1.0.0"

[sketch_css]
src = "src"
dst = "styles"
interface = "src/sketch/styles"

[dependencies]
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
sketch = ">= 4.0.0 and < 5.0.0"
sketch_css = ">= 2.0.0 and < 3.0.0"

[dev-dependencies]
gleeunit = ">= 1.0.0 and < 2.0.0"
```

### A note on generation algorithm

Because a Sketch `Class` can be generated in multiple ways, and with variable,
Expand All @@ -44,43 +87,49 @@ generated with the variable taken into account! Sketch CSS being opinionated, it
generates the class, with a CSS variable, letting you update it, override it,
etc.

All `_` are also automatically transformed into `-`, because CSS classes are
most of the time used with dashes, so Sketch CSS follows that convention!
Sketch CSS also acts as a basic interpreter. It means you can write basic
constants or variables, and they will be taking into account. Be sure to write
classes like you would do in CSS yet: Sketch CSS does not execute your
functions!

### Example

```gleam
// src/main_styles.gleam
import sketch
import sketch/css
fn flexer() {
sketch.class([
sketch.display("flex"),
])
pub fn flexer() {
let display = "flex"
css.class([css.display(display)])
}
fn direction(flex_direction: String) {
css.flex_direction(flex_direction)
}
fn flexer_direction(flex_direction: String) {
sketch.class([
sketch.compose(flexer()),
sketch.flex_direction(flex_direction),
pub fn flexer_direction(flex_direction: String) {
css.class([
css.compose(flexer()),
direction(flex_direction),
])
}
```

```css
/* styles/main_styles.css */
.flexer {
.main_styles-flexer {
display: flex;
}

.flexer-direction {
.main_styles-flexer_direction {
display: flex;
flex-direction: var(--flex-direction);
}
```

```gleam
// src/sketch/styles/main_styles.gleam
pub const flexer = "flexer"
pub const flexer = "main_styles-flexer"
pub const flexer_direction = "flexer flexer-direction"
pub const flexer_direction = "main_styles-flexer_direction"
```
2 changes: 1 addition & 1 deletion sketch_css/gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ path = "sketch_css"
argv = ">= 1.0.2 and < 2.0.0"
glance = ">= 2.0.0 and < 3.0.0"
gleam_erlang = ">= 0.25.0 and < 1.0.0"
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
gleam_stdlib = ">= 0.42.0 and < 2.0.0"
glint = ">= 1.2.0 and < 2.0.0"
simplifile = ">= 2.0.1 and < 3.0.0"
sketch = {path = "../sketch"}
Expand Down
2 changes: 1 addition & 1 deletion sketch_css/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ argv = { version = ">= 1.0.2 and < 2.0.0" }
birdie = { version = ">= 1.2.5 and < 2.0.0" }
glance = { version = ">= 2.0.0 and < 3.0.0" }
gleam_erlang = { version = ">= 0.25.0 and < 1.0.0" }
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
gleam_stdlib = { version = ">= 0.42.0 and < 2.0.0" }
glint = { version = ">= 1.2.0 and < 2.0.0" }
pprint = { version = ">= 1.0.4 and < 2.0.0" }
simplifile = { version = ">= 2.0.1 and < 3.0.0" }
Expand Down
55 changes: 34 additions & 21 deletions sketch_lustre/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ import sketch
import sketch/lustre as sketch_lustre
pub fn main() {
// Initialise the cache. Two strategies can be used in browser, only one
// on server-side.
let assert Ok(cache) = sketch.cache(strategy: sketch.Ephemeral)
// Select the output of the generated stylesheet.
sketch_lustre.node()
// Add the sketch CSS generation "view middleware".
|> sketch_lustre.compose(view, cache)
// Give the new view function to lustre runtime!
|> lustre.simple(init, update, _)
// Initialise the cache. Two strategies can be used. Ephemeral caches are designed as throw-away caches.
let assert Ok(stylesheet) = sketch.stylesheet(strategy: sketch.Ephemeral)
// Generate the partial view function, compatible with Lustre's runtime.
lustre.simple(init, update, view(_, stylesheet))
// And voilà!
|> lustre.start("#app", Nil)
}
fn view(model, stylesheet) {
// Add the sketch CSS generation "view middleware".
use <- sketch_lustre.render(stylesheet, [sketch_lustre.node()])
// Run your actual view function.
my_view(model)
}
```

## Usage
Expand All @@ -54,21 +56,23 @@ Lustre, and will not add another class. This is helpful when you want to use a
simple node, without any class linked on it.

```gleam
import sketch
import sketch/css
import sketch/css/length.{px}
import sketch/lustre/element
import sketch/lustre/element/html
import sketch/size.{px}
fn main_style() {
sketch.class([
sketch.background("red"),
sketch.font_size(px(16)),
css.class([
css.background("red"),
css.font_size(px(16)),
])
}
fn view(model: Int) {
html.div(main_style(), [], [
html.div_([], [h.text(int.to_string(model))]),
html.div_([], [
html.text(int.to_string(model)),
]),
])
}
```
Expand All @@ -86,12 +90,21 @@ straightforward, by using `sketch/lustre/element.unstyled`. The opposite (going
from a Lustre element to a Sketch Lustre element) is also possible by using
`sketch/lustre/element.styled`!

### Sketch Lustre Experimental

Because sometimes you may want to avoid the `Element(msg)` overhead, you can try
the experimental Sketch Lustre runtime, `sketch_lustre_experimental`. That
runtime works in the same way, excepts it does not implements its own `Element`
type on top of Lustre's `Element`. Most of the time, you should not see any
differences. Keep in mind that it can bug though, as it's still experimental. If
you try to use it, please, report any bugs you can find.

### Usage with Shadow DOM

In browser, Sketch can work with a Shadow DOM, in order to hide the compiled
styles from the rest of the application. To do it, you can use
[`plinth`](https://github.com/CrowdHailer/plinth). This allows to create a
`ShadowRoot`, to use
[`sketch/options.shadow_root()`](https://hexdocs.pm/sketch/sketch/options.html#shadow_root).
In the same way you can initialize the cache to render in document or in a
`style` node, you can now use a Shadow Root to paint styles in your application!
styles from the rest of the application. With a proper shadow root (represented
as a `Dynamic` in Gleam), you can use
[`sketch/lustre.shadow()`](https://hexdocs.pm/sketch_lustre/sketch/lustre.html#shadow)
to render a stylesheet in the shadow root directly. In the same way you can
initialize the cache to render in document or in a `style` node, you can use a
shadow root to paint styles in your application!
Loading

0 comments on commit e8ca108

Please sign in to comment.