Skip to content

Commit 12d86f1

Browse files
committed
Use indirection to properly resolve current stylesheet
1 parent 2ba464c commit 12d86f1

File tree

12 files changed

+99
-110
lines changed

12 files changed

+99
-110
lines changed

e2e/server_components/src/server_components.gleam

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ import sketch/lustre/experimental as sketch_lustre
2323
// MAIN ------------------------------------------------------------------------
2424

2525
pub fn main() {
26-
let assert Ok(stylesheet) = sketch.stylesheet(sketch.Persistent)
27-
let assert Ok(_) =
28-
stylesheet
29-
|> sketch.global(host_class())
30-
|> sketch_lustre.setup
3126
let assert Ok(_) =
3227
fn(request: Request(Connection)) -> Response(ResponseData) {
3328
// In order to get started with server components, we'll need to handle at
@@ -159,7 +154,12 @@ type CounterSocketInit =
159154
#(CounterSocket, Option(Selector(CounterSocketMessage)))
160155

161156
fn init_counter_socket(_) -> CounterSocketInit {
162-
let counter = shared_view.app()
157+
let assert Ok(stylesheet) = sketch.stylesheet(sketch.Persistent)
158+
let assert Ok(_) =
159+
stylesheet
160+
|> sketch.global(host_class())
161+
|> sketch_lustre.setup
162+
let counter = shared_view.app(stylesheet)
163163
// Rather than calling `lustre.start` as we do in the client, we construct the
164164
// Lustre runtime by calling `lustre.start_server_component`. This is the same
165165
// `Runtime` type we get from `lustre.start` but this function doesn't need a

e2e/shared_view/src/shared_view.gleam

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import gleam/int
33
import lustre
44
import lustre/attribute as a
55
import lustre/event as e
6+
import sketch
67
import sketch/lustre/experimental as sketch_lustre
78
import sketch/lustre/experimental/element/html as h
89
import styles
@@ -16,17 +17,17 @@ pub type Msg {
1617
}
1718

1819
/// Defines the standard app, used everywhere in Lustre applications.
19-
pub fn app() {
20+
pub fn app(stylesheet: sketch.StyleSheet) {
2021
use model <- lustre.simple(init, update)
21-
use <- sketch_lustre.render(in: [sketch_lustre.node()])
22+
use <- sketch_lustre.render(stylesheet:, in: [sketch_lustre.node()])
2223
view(model)
2324
}
2425

2526
/// Function used specifically in SSR, in order to send the correct HTML
2627
/// before hydrating it. It can also be an example of HTML server-side
2728
/// generation, Sketch improved.
28-
pub fn ssr(model: Model) {
29-
use <- sketch_lustre.render([sketch_lustre.node()])
29+
pub fn ssr(model: Model, stylesheet: sketch.StyleSheet) {
30+
use <- sketch_lustre.render(stylesheet:, in: [sketch_lustre.node()])
3031
h.html([], [
3132
h.head([], [
3233
h.link([a.rel("stylesheet"), a.href(styles.fonts)]),

e2e/ssr/src/ssr.gleam

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ pub fn main() {
1111
let assert Ok(stylesheet) = sketch.stylesheet(sketch.Persistent)
1212
let assert Ok(_) = sketch_lustre.setup(stylesheet)
1313
let assert Ok(_) =
14-
fn(_) { greet() }
14+
fn(_) { greet(stylesheet) }
1515
|> mist.new()
1616
|> mist.port(1234)
1717
|> mist.start_http()
1818
process.sleep_forever()
1919
}
2020

21-
fn greet() -> Response(ResponseData) {
22-
shared_view.ssr(0)
21+
fn greet(stylesheet: sketch.StyleSheet) -> Response(ResponseData) {
22+
shared_view.ssr(0, stylesheet)
2323
|> element.to_document_string()
2424
|> bytes_tree.from_string()
2525
|> mist.Bytes()

e2e/web_application/src/web_application.gleam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ import sketch/lustre/experimental as sketch_lustre
66
pub fn main() {
77
let assert Ok(stylesheet) = sketch.stylesheet(sketch.Persistent)
88
let assert Ok(_) = sketch_lustre.setup(stylesheet)
9-
shared_view.app()
9+
shared_view.app(stylesheet)
1010
|> lustre.start("#app", Nil)
1111
}

sketch/src/sketch.ffi.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
let id = 0
2+
export function uniqueId() {
3+
return id++
4+
}

sketch/src/sketch.gleam

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@target(erlang)
22
import gleam/result
3-
import sketch/css.{type AtRule, type Class, type Global}
3+
import sketch/css.{type AtRule, type Class}
44
import sketch/error
55
@target(erlang)
66
import sketch/internals/cache/actor
@@ -10,12 +10,12 @@ import sketch/internals/cache/cache
1010
@target(javascript)
1111
/// Manages the styles. Can be instanciated with [`stylesheet`](#stylesheet).
1212
pub opaque type StyleSheet {
13-
StyleSheet(cache: cache.Cache, is_persistent: Bool)
13+
StyleSheet(cache: cache.Cache, id: Int, is_persistent: Bool)
1414
}
1515

1616
@target(erlang)
1717
pub opaque type StyleSheet {
18-
StyleSheet(cache: actor.Cache)
18+
StyleSheet(cache: actor.Cache, id: Int)
1919
}
2020

2121
@target(javascript)
@@ -41,62 +41,35 @@ pub fn class_name(class: Class, stylesheet: StyleSheet) -> #(StyleSheet, String)
4141
@target(erlang)
4242
pub fn class_name(class: Class, stylesheet: StyleSheet) -> #(StyleSheet, String) {
4343
let #(cache, class_name) = actor.class_name(class, stylesheet.cache)
44-
#(StyleSheet(cache:), class_name)
44+
#(StyleSheet(..stylesheet, cache:), class_name)
4545
}
4646

4747
@target(javascript)
4848
/// Pushes an `@rule` in the StyleSheet, to get it bundled in the outputted CSS.
4949
/// It returns the StyleSheet with the rule added.
50-
@deprecated("Use `at_rule_` instead. `at_rule` will be replaced in the next version.")
5150
pub fn at_rule(rule: AtRule, stylesheet: StyleSheet) -> StyleSheet {
5251
let cache = cache.at_rule(rule, stylesheet.cache)
5352
StyleSheet(..stylesheet, cache:)
5453
}
5554

5655
@target(erlang)
57-
@deprecated("Use `at_rule_` instead. `at_rule` will be replaced in the next version.")
5856
pub fn at_rule(rule: AtRule, stylesheet: StyleSheet) -> StyleSheet {
5957
let cache = actor.at_rule(rule, stylesheet.cache)
60-
StyleSheet(cache:)
58+
StyleSheet(..stylesheet, cache:)
6159
}
6260

6361
@target(javascript)
6462
/// Pushes an `@rule` in the StyleSheet, to get it bundled in the outputted CSS.
6563
/// It returns the StyleSheet with the rule added.
66-
pub fn at_rule_(stylesheet: StyleSheet, rule: AtRule) -> StyleSheet {
67-
let cache = cache.at_rule(rule, stylesheet.cache)
68-
StyleSheet(..stylesheet, cache:)
69-
}
70-
71-
@target(erlang)
72-
pub fn at_rule_(stylesheet: StyleSheet, rule: AtRule) -> StyleSheet {
73-
let cache = actor.at_rule(rule, stylesheet.cache)
74-
StyleSheet(cache:)
75-
}
76-
77-
@target(javascript)
78-
/// Injects a `Global` class in the StyleSheet. Use it to apply some style on
79-
/// `body` for example.
80-
///
81-
/// ```gleam
82-
/// let assert Ok(stylesheet) = sketch.stylesheet(sketch.Persistent)
83-
/// stylesheet
84-
/// |> sketch.global({
85-
/// css.global("body", [
86-
/// css.margin(px(0)),
87-
/// css.backkground("red"),
88-
/// ])
89-
/// })
90-
/// ```
91-
pub fn global(stylesheet: StyleSheet, global: Global) -> StyleSheet {
64+
pub fn global(stylesheet: StyleSheet, global: css.Global) -> StyleSheet {
9265
let #(cache, _) = cache.class_name(global.class, stylesheet.cache)
9366
StyleSheet(..stylesheet, cache:)
9467
}
9568

9669
@target(erlang)
97-
pub fn global(stylesheet: StyleSheet, global: Global) -> StyleSheet {
70+
pub fn global(stylesheet: StyleSheet, global: css.Global) -> StyleSheet {
9871
let #(cache, _) = actor.class_name(global.class, stylesheet.cache)
99-
StyleSheet(cache:)
72+
StyleSheet(..stylesheet, cache:)
10073
}
10174

10275
/// Strategy for the StyleSheet. Two strategies are available as of now: ephemeral
@@ -118,19 +91,25 @@ pub type Strategy {
11891
pub fn stylesheet(
11992
strategy strategy: Strategy,
12093
) -> Result(StyleSheet, error.SketchError) {
94+
let id = unique_id()
12195
Ok(case strategy {
122-
Ephemeral -> StyleSheet(cache: cache.new(), is_persistent: False)
123-
Persistent -> StyleSheet(cache: cache.new(), is_persistent: True)
96+
Ephemeral -> StyleSheet(cache: cache.new(), id:, is_persistent: False)
97+
Persistent -> StyleSheet(cache: cache.new(), id:, is_persistent: True)
12498
})
12599
}
126100

127101
@target(erlang)
128102
pub fn stylesheet(
129103
strategy strategy: Strategy,
130104
) -> Result(StyleSheet, error.SketchError) {
131-
case strategy {
105+
let id = unique_id()
106+
use cache <- result.map(case strategy {
132107
Ephemeral -> Ok(actor.ephemeral())
133108
Persistent -> actor.persistent()
134-
}
135-
|> result.map(StyleSheet)
109+
})
110+
StyleSheet(cache:, id:)
136111
}
112+
113+
@external(erlang, "erlang", "unique_integer")
114+
@external(javascript, "./sketch.ffi.mjs", "uniqueId")
115+
fn unique_id() -> Int

sketch_lustre_experimental/src/sketch/lustre/experimental.gleam

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,11 @@ pub fn setup(stylesheet: sketch.StyleSheet) -> Result(sketch.StyleSheet, Nil) {
6161
/// }
6262
/// ```
6363
pub fn render(
64+
stylesheet stylesheet: sketch.StyleSheet,
6465
in outputs: List(Container),
6566
after view: fn() -> el.Element(msg),
6667
) -> el.Element(msg) {
68+
let assert Ok(_) = global.set_current_stylesheet(stylesheet)
6769
let new_view = view()
6870
case global.get_stylesheet() {
6971
Error(_) -> new_view

sketch_lustre_experimental/src/sketch/lustre/experimental/element.gleam

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@ pub fn element(
3232
attributes attributes: List(Attribute(msg)),
3333
children children: List(el.Element(msg)),
3434
) {
35-
let attributes = case class_name(class) {
36-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
37-
Error(_) -> attributes
38-
}
35+
let class_name = class_name(class)
36+
let attributes = [attribute.class(class_name), ..attributes]
3937
el.element(tag, attributes, children)
4038
}
4139

@@ -56,10 +54,8 @@ pub fn namespaced(
5654
attributes attributes: List(Attribute(msg)),
5755
children children: List(el.Element(msg)),
5856
) {
59-
let attributes = case class_name(class) {
60-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
61-
Error(_) -> attributes
62-
}
57+
let class_name = class_name(class)
58+
let attributes = [attribute.class(class_name), ..attributes]
6359
el.namespaced(tag, namespace, attributes, children)
6460
}
6561

@@ -77,16 +73,13 @@ const error_msg = "Stylesheet is not initialized in your application. Please, in
7773

7874
/// Generate a class name from a `Class`, using the `StyleSheet` injected
7975
/// in the environment.
80-
pub fn class_name(class: css.Class) -> Result(String, Nil) {
76+
pub fn class_name(class: css.Class) -> String {
8177
case global.get_stylesheet() {
82-
Error(_) -> {
83-
io.println(error_msg)
84-
Error(Nil)
85-
}
78+
Error(_) -> panic as error_msg
8679
Ok(stylesheet) -> {
8780
let #(stylesheet, class_name) = sketch.class_name(class, stylesheet)
8881
let _ = global.set_stylesheet(stylesheet)
89-
Ok(class_name)
82+
class_name
9083
}
9184
}
9285
}

sketch_lustre_experimental/src/sketch/lustre/experimental/element/keyed.gleam

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,8 @@ pub fn element(
1414
attributes: List(Attribute(msg)),
1515
children: List(#(String, Element(msg))),
1616
) -> Element(msg) {
17-
let attributes = case class_name(class) {
18-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
19-
Error(_) -> attributes
20-
}
17+
let class_name = class_name(class)
18+
let attributes = [attribute.class(class_name), ..attributes]
2119
keyed.element(tag, attributes, children)
2220
}
2321

@@ -38,10 +36,8 @@ pub fn namespaced(
3836
attributes: List(Attribute(msg)),
3937
children: List(#(String, Element(msg))),
4038
) -> Element(msg) {
41-
let attributes = case class_name(class) {
42-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
43-
Error(_) -> attributes
44-
}
39+
let class_name = class_name(class)
40+
let attributes = [attribute.class(class_name), ..attributes]
4541
keyed.namespaced(namespace, tag, attributes, children)
4642
}
4743

@@ -64,10 +60,8 @@ pub fn ul(
6460
attributes: List(Attribute(msg)),
6561
children: List(#(String, Element(msg))),
6662
) -> Element(msg) {
67-
let attributes = case class_name(class) {
68-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
69-
Error(_) -> attributes
70-
}
63+
let class_name = class_name(class)
64+
let attributes = [attribute.class(class_name), ..attributes]
7165
keyed.element("ul", attributes, children)
7266
}
7367

@@ -85,10 +79,8 @@ pub fn ol(
8579
attributes: List(Attribute(msg)),
8680
children: List(#(String, Element(msg))),
8781
) -> Element(msg) {
88-
let attributes = case class_name(class) {
89-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
90-
Error(_) -> attributes
91-
}
82+
let class_name = class_name(class)
83+
let attributes = [attribute.class(class_name), ..attributes]
9284
keyed.element("ol", attributes, children)
9385
}
9486

@@ -106,10 +98,8 @@ pub fn div(
10698
attributes: List(Attribute(msg)),
10799
children: List(#(String, Element(msg))),
108100
) -> Element(msg) {
109-
let attributes = case class_name(class) {
110-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
111-
Error(_) -> attributes
112-
}
101+
let class_name = class_name(class)
102+
let attributes = [attribute.class(class_name), ..attributes]
113103
keyed.element("div", attributes, children)
114104
}
115105

@@ -127,10 +117,8 @@ pub fn tbody(
127117
attributes: List(Attribute(msg)),
128118
children: List(#(String, Element(msg))),
129119
) -> Element(msg) {
130-
let attributes = case class_name(class) {
131-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
132-
Error(_) -> attributes
133-
}
120+
let class_name = class_name(class)
121+
let attributes = [attribute.class(class_name), ..attributes]
134122
keyed.element("tbody", attributes, children)
135123
}
136124

@@ -148,10 +136,8 @@ pub fn dl(
148136
attributes: List(Attribute(msg)),
149137
children: List(#(String, Element(msg))),
150138
) -> Element(msg) {
151-
let attributes = case class_name(class) {
152-
Ok(class_name) -> [attribute.class(class_name), ..attributes]
153-
Error(_) -> attributes
154-
}
139+
let class_name = class_name(class)
140+
let attributes = [attribute.class(class_name), ..attributes]
155141
keyed.element("dl", attributes, children)
156142
}
157143

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
import * as gleam from '../../../../gleam.mjs'
22

3-
let _stylesheet = null
3+
let currentStylesheet = null
4+
const stylesheets = {}
45

56
export function setStyleSheet(stylesheet) {
6-
_stylesheet = stylesheet
7+
stylesheets[stylesheet.id] = stylesheet
8+
return new gleam.Ok(stylesheet)
9+
}
10+
11+
export function setCurrentStylesheet(stylesheet) {
12+
currentStylesheet = stylesheet.id
713
return new gleam.Ok(stylesheet)
814
}
915

1016
export function getStyleSheet() {
11-
if (!_stylesheet) return new gleam.Error()
12-
return new gleam.Ok(_stylesheet)
17+
const stylesheet = stylesheets[currentStylesheet]
18+
if (!stylesheet) return new gleam.Error()
19+
return new gleam.Ok(stylesheet)
1320
}

0 commit comments

Comments
 (0)