/*****************
* lib *
*****************/
#let mylib(fill: none, body) = {
body
}
#let lib-component-func(content) = {
// this box's fill will changed by mylib input
box()[#content]
}
/*****************
* User *
*****************/
// case1: draw a red box
#show: mylib.with(fill: red)
#lib-component-func("hello")
// case2: draw a green box
#show: mylib.with(fill: green)
#lib-component-func("world")
The basic idea here is that everything in the function is definite (for the same input the function should generate the same result). So there are 2 ways to achieve this:
- Use a context block (The function generates the same context content, the color is determined after it is inserted into the document according to the “context”)
- (Recommended) Let users customize the function by themselves (The function accepts a
color
parameter and the user can set it easily)
Context solution
If you wrap it with a context block:
#let global-color = state("my-box-color", blue.lighten(40%))
#let set-color(c) = global-color.update(c)
#let smart-box(cont) = context {
box(cont, fill: global-color.get())
}
And make sure to add the global-color.update
content into the document in your main show
function to make sure the state updates correctly.
.with
solution
Using context immoderately would cause disasters, for example, if you would like to modify the smart-box
above, you may find that the type of its return value has been content
, which is hard to customize further.
I would like to define a function like this:
#let stupid-box(cont, fill: blue.lighten(40%)) = box(cont, fill: fill)
And in the main file add the following code:
#import "somewhere/lib.typ": stupid-box
#let my-box = stupid-box.with(fill: red)
which is much more simple and steerable.
Conclusion
state
and context
allow you to make it work like a “global variable”, but this usually get into a mess when the global context become more and more complicated. Using the recommended way would make sure users know what they are getting from the function.