mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Add mermaid diagrams to docs
This commit is contained in:
parent
3c45defeac
commit
e9742e88fd
4 changed files with 131 additions and 18 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
import { defineConfig } from "vitepress"
|
//import { defineConfig } from "vitepress"
|
||||||
|
import { withMermaid } from "vitepress-plugin-mermaid";
|
||||||
|
|
||||||
// https://vitepress.dev/reference/site-config
|
// https://vitepress.dev/reference/site-config
|
||||||
export default defineConfig({
|
export default withMermaid({
|
||||||
title: "Vide",
|
title: "Vide",
|
||||||
titleTemplate: ":title - A reactive UI library for Luau",
|
titleTemplate: ":title - A reactive UI library for Luau",
|
||||||
description: "A reactive UI library for Luau.",
|
description: "A reactive UI library for Luau.",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vitepress": "^1.0.0-rc.4"
|
"vitepress": "^1.0.0-rc.4",
|
||||||
|
"vitepress-plugin-mermaid": "^2.0.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,54 @@
|
||||||
# Reactive Scoping
|
# Reactive Scoping
|
||||||
|
|
||||||
This is a brief document designed to give the user more insight into how Vide's
|
This is a brief document designed to give the user more insight into how Vide's
|
||||||
reactive graph works.
|
reactive system works.
|
||||||
|
|
||||||
|
Vide's reactivity can be pictured as a graph, where each source, derived source,
|
||||||
|
and effect is a node on that graph. For example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
|
||||||
|
root(function()
|
||||||
|
local forename = source "quan"
|
||||||
|
local surname = source "xi"
|
||||||
|
|
||||||
|
local name = derive(function()
|
||||||
|
return forename() .. " " .. surname()
|
||||||
|
end)
|
||||||
|
|
||||||
|
effect(function()
|
||||||
|
print("new name: " .. name())
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
Each time you create and derive sources, a new node representing that source is
|
Each time you create and derive sources, a new node representing that source is
|
||||||
created and added to the reactive graph. Each node stores a value and a
|
created and added to the reactive graph. Each node stores a value and a
|
||||||
side-effect function. Each node also keeps track of its parents and children,
|
side-effect function. Each node also keeps track of its parents and children,
|
||||||
as well as any cleanups registered.
|
as well as any cleanups registered.
|
||||||
|
|
||||||
|
This code will produce a graph that looks like so:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{init: {
|
||||||
|
"theme": "base",
|
||||||
|
"themeVariables": {
|
||||||
|
"primaryColor": "#1B1B1F",
|
||||||
|
"primaryTextColor": "#fff",
|
||||||
|
"primaryBorderColor": "#1B1B1F",
|
||||||
|
"lineColor": "#79B8FF",
|
||||||
|
"tertiaryColor": "#161618",
|
||||||
|
"tertiaryBorderColor": "#161618"
|
||||||
|
}
|
||||||
|
}}%%
|
||||||
|
|
||||||
|
flowchart
|
||||||
|
subgraph root
|
||||||
|
forename & surname --> name
|
||||||
|
name --> effect
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
Any time a node is updated, Vide will traverse and update that node's children,
|
Any time a node is updated, Vide will traverse and update that node's children,
|
||||||
its children's children, etc, until all nodes descending from that node has been
|
its children's children, etc, until all nodes descending from that node has been
|
||||||
updated. Traversal will stop at a node if that node's cached value does not
|
updated. Traversal will stop at a node if that node's cached value does not
|
||||||
|
|
@ -30,32 +71,85 @@ the root node which will track any node created or derived inside its scope, or
|
||||||
any cleanups registered. Without it, nodes could be garbage collected without a
|
any cleanups registered. Without it, nodes could be garbage collected without a
|
||||||
chance to run pending cleanups which can cause memory leakage.
|
chance to run pending cleanups which can cause memory leakage.
|
||||||
|
|
||||||
|
Nodes created by `source()` can actually exist outside of root nodes, since
|
||||||
|
they do not have direct side-effects or cleanups, they do not have to be
|
||||||
|
explicitly destroyed.
|
||||||
|
|
||||||
Control flow functions in Vide are special, as they can dynamically create and
|
Control flow functions in Vide are special, as they can dynamically create and
|
||||||
destroy new root scopes.
|
destroy new root scopes.
|
||||||
|
|
||||||
It is the combination of the above which allows us to write components like so:
|
It is the combination of the above which allows us to write components like so:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local function Counter()
|
local function Counter(props: { text: string })
|
||||||
local count = source(0)
|
local count = source(0)
|
||||||
|
|
||||||
local connection = stepped:Connect(function() count(count() + 1) end)
|
local connection = stepped:Connect(function() count(count() + 1) end)
|
||||||
|
|
||||||
cleanup(function() connection:Disconnect() end)
|
cleanup(function() connection:Disconnect() end)
|
||||||
effect(function() print(count()) end)
|
|
||||||
|
|
||||||
return create "TextLabel" { Text = count }
|
return create "TextLabel" {
|
||||||
|
Text = function()
|
||||||
|
return props.text() .. ": " .. count()
|
||||||
|
end
|
||||||
|
}
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
Vide doesn't recognise this as a "component", that is a user abstraction. Vide
|
Vide doesn't recognise this as a "component", that is a user abstraction. Vide
|
||||||
just sees this as a function that creates nodes in the reactive graph.
|
just sees this as a function that creates nodes in the reactive graph.
|
||||||
|
|
||||||
Whenever the reactive scope that calls this function is destroyed, like by a
|
```lua
|
||||||
control flow function, the registered cleanup will be called, and the effect
|
root(function()
|
||||||
(which is just a node on the reactive graph) is destroyed. The returned instance
|
local counters = { "A", "B" }
|
||||||
and the bound `count` source is just considered to be a side-effect, and with
|
|
||||||
the reactive scope from which the side-effects stem from destroyed, the instance
|
|
||||||
can be garbage collected - everything is nicely cleaned up.
|
|
||||||
|
|
||||||
> todo: add graphics
|
indexes(counters, function(name)
|
||||||
|
return Counter { text = name }
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
This code produces a graph like so:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{init: {
|
||||||
|
"theme": "base",
|
||||||
|
"themeVariables": {
|
||||||
|
"primaryColor": "#1B1B1F",
|
||||||
|
"primaryTextColor": "#fff",
|
||||||
|
"primaryBorderColor": "#1B1B1F",
|
||||||
|
"lineColor": "#79B8FF",
|
||||||
|
"tertiaryColor": "#161618",
|
||||||
|
"tertiaryBorderColor": "#161618"
|
||||||
|
}
|
||||||
|
}}%%
|
||||||
|
|
||||||
|
flowchart LR
|
||||||
|
subgraph root
|
||||||
|
counters --> indexes
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph root1[subroot 1]
|
||||||
|
n1[name] --> p1[prop binding]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph root2[subroot 2]
|
||||||
|
n2[name] --> p2[prop binding]
|
||||||
|
end
|
||||||
|
|
||||||
|
indexes .-> root1 & root2
|
||||||
|
```
|
||||||
|
|
||||||
|
This shows how the `indexes()` control flow function creates and manages new
|
||||||
|
root scopes. The function creates an effect seen as `indexes` in the graph,
|
||||||
|
which manages the new roots `subroot 1` and `subroot 2`, as well as the sources
|
||||||
|
`name` for which one exists for each index value in the input table.
|
||||||
|
|
||||||
|
When the input table changes, `indexes()` can automatically destroy and create
|
||||||
|
subroots based on the changed indexes. Destroyed nodes run any cleanups made, in
|
||||||
|
this case it is the cleanups to disconnect the counters connection. The same
|
||||||
|
applies to all other control flow functions.
|
||||||
|
|
||||||
|
Whenever the root reactive scope is destroyed, all its children, `counters` and
|
||||||
|
`indexes` will be destroyed too, which means that `indexes` children, the
|
||||||
|
subroots, will also be destroyed. Everything is nicely cleaned up.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Effect
|
# Effects
|
||||||
|
|
||||||
Effects are functions that are ran in response to source updates. They are
|
Effects are functions that are ran in response to source updates. They are
|
||||||
called effects because they cause *side-effects* when reacting to source updates.
|
called effects because they cause *side-effects* when reacting to source updates.
|
||||||
|
|
@ -20,9 +20,9 @@ count(1)
|
||||||
-- "count: 1" printed
|
-- "count: 1" printed
|
||||||
```
|
```
|
||||||
|
|
||||||
The callback given to `effect()` is ran in a *reactive-scope*. Any source read
|
The callback given to `effect()` is ran in a *reactive scope*. Any source read
|
||||||
from inside a reactive scope will be tracked, so that if any of those sources
|
from inside a reactive scope will be tracked, so that if any of those sources
|
||||||
update, the effect will be re-ran too.
|
update, the effect will be reran too.
|
||||||
|
|
||||||
The callback is first ran immediately inside the `effect()` call to initially
|
The callback is first ran immediately inside the `effect()` call to initially
|
||||||
figure out what sources are being used.
|
figure out what sources are being used.
|
||||||
|
|
@ -56,9 +56,26 @@ All observable changes to the user are considered to be side-effects of pure
|
||||||
computations.
|
computations.
|
||||||
|
|
||||||
Sources, derived sources, and effects form what is called a *reactive graph*.
|
Sources, derived sources, and effects form what is called a *reactive graph*.
|
||||||
In the above example a graph `count -> doubled -> effect` is formed. Anywhere
|
In the above example, the following graph is formed. Anywhere
|
||||||
an update occures, everything further down the graph is updated.
|
an update occures, everything further down the graph is updated.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{init: {
|
||||||
|
"theme": "base",
|
||||||
|
"themeVariables": {
|
||||||
|
"primaryColor": "#1B1B1F",
|
||||||
|
"primaryTextColor": "#fff",
|
||||||
|
"primaryBorderColor": "#1B1B1F",
|
||||||
|
"lineColor": "#79B8FF",
|
||||||
|
"tertiaryColor": "#161618",
|
||||||
|
"tertiaryBorderColor": "#161618"
|
||||||
|
}
|
||||||
|
}}%%
|
||||||
|
|
||||||
|
flowchart LR
|
||||||
|
count --> doubled --> effect
|
||||||
|
```
|
||||||
|
|
||||||
You should not update other sources using an effect. Improper usage can lead to
|
You should not update other sources using an effect. Improper usage can lead to
|
||||||
a cyclic loop in the graph, causing an infinite loop when it tries to update.
|
a cyclic loop in the graph, causing an infinite loop when it tries to update.
|
||||||
Sources should be derived instead.
|
Sources should be derived instead.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue