mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
This commit is contained in:
parent
52ea2e4690
commit
5b61a9df10
13 changed files with 57 additions and 39 deletions
|
|
@ -2,6 +2,26 @@
|
|||
|
||||
<br/>
|
||||
|
||||
## root()
|
||||
|
||||
Creates and runs a function in a new reactive scope.
|
||||
|
||||
- **Type**
|
||||
|
||||
```lua
|
||||
function root<T>(fn: () -> T): (T, () -> ())
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
Creates a new root reactive scope, where creation and derivations of sources
|
||||
can be tracked and properly disposed of.
|
||||
|
||||
Returns the result of the given function.
|
||||
|
||||
Also returns a function to destroy the root, which will run any cleanups
|
||||
and allow derived sources created to garbage collect.
|
||||
|
||||
## source()
|
||||
|
||||
Creates a new source with the given value.
|
||||
|
|
@ -14,10 +34,10 @@ Creates a new source with the given value.
|
|||
|
||||
- **Details**
|
||||
|
||||
Calling the returned source with no arguments will return its stored value,
|
||||
calling with arguments will set a new value.
|
||||
Calling the returned source with no argument will return its stored value,
|
||||
calling with an argument will set a new value.
|
||||
|
||||
Reading from the source from within any reactive scope will cause changes
|
||||
Reading from the source from within a reactive scope will cause changes
|
||||
to that source to be tracked and anything depending on it to update.
|
||||
|
||||
- **Example**
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## cleanup()
|
||||
|
||||
Runs a callback anytime a function scope is re-ran.
|
||||
Runs a callback anytime a reactive scope is re-ran.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
@ -10,19 +10,6 @@ Runs a callback anytime a function scope is re-ran.
|
|||
function cleanup(callback: () -> ())
|
||||
```
|
||||
|
||||
- **Details**
|
||||
|
||||
The primary purpose of this function is to provide a means of cleaning up
|
||||
side effects caused by source updates and `watch()` updates.
|
||||
|
||||
The stack is inspected to find the function that calls `cleanup()`. The
|
||||
callback passed is called anytime the caller is re-ran, and when the caller
|
||||
finally garbage collects.
|
||||
|
||||
::: warning
|
||||
Only one `cleanup()` call is allowed per function scope.
|
||||
:::
|
||||
|
||||
- **Example**
|
||||
|
||||
```lua
|
||||
|
|
@ -53,7 +40,7 @@ Runs a callback anytime a function scope is re-ran.
|
|||
|
||||
## untrack()
|
||||
|
||||
Gets the value of a source without reactively tracking it.
|
||||
Runs a given function where any sources read will not track its reactive scope.
|
||||
|
||||
- **Type**
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
This is a brief tutorial designed to give you a quick run through the usage of
|
||||
Vide.
|
||||
|
||||
Vide is largely inspired by other UI libraries such as Solid and Fusion.
|
||||
Vide is heavily inspired by [Solid](https://www.solidjs.com/).
|
||||
|
||||
## Why Vide?
|
||||
|
||||
|
|
@ -21,5 +21,6 @@ Some of the main focuses behind Vide's design choices:
|
|||
- Being completely typecheckable.
|
||||
- Flexibility, particularly with integrating other libraries and allowing users
|
||||
to use their own patterns.
|
||||
- A powerful reactive system that does not interfere with the lifetime of
|
||||
instances.
|
||||
- Independence from instance lifetimes.
|
||||
- A powerful reactive system that can surgically update properties as a result
|
||||
of state changes.
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ local function apply<T>(instance: T & Instance, properties: { [unknown]: unknown
|
|||
-- finally set parent if any
|
||||
if parent then
|
||||
if type(parent) == "function" then
|
||||
bind.parent(instance, parent :: () -> ())
|
||||
bind.parent(instance, parent :: () -> Instance)
|
||||
else
|
||||
instance.Parent = parent :: Instance
|
||||
end
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ function create_binding<T>(updater: (T) -> T, binding_data: T)
|
|||
binding.effect = updater
|
||||
|
||||
local owner = get_scope()
|
||||
if not owner then throw("cannot bind property in non-reactive scope") end
|
||||
assert(owner)
|
||||
|
||||
set_owner(binding, owner)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
if not game then script = require "test/relative-string" end
|
||||
|
||||
local flags = require(script.Parent.flags)
|
||||
local throw = require(script.Parent.throw)
|
||||
local graph = require(script.Parent.graph)
|
||||
local get_scope = graph.get_scope
|
||||
local add_cleanup = graph.add_cleanup
|
||||
|
||||
local function cleanup(fn: () -> ())
|
||||
local node = get_scope()
|
||||
if node == nil then throw("cannot call cleanup() in a non-reactive scope") end
|
||||
add_cleanup(node, fn)
|
||||
local scope = get_scope()
|
||||
if not scope then throw("cannot cleanup in a non-reactive scope") end
|
||||
assert(scope)
|
||||
|
||||
add_cleanup(scope, fn)
|
||||
end
|
||||
|
||||
return cleanup
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
if not game then script = require "test/relative-string" end
|
||||
|
||||
local throw = require(script.Parent.throw)
|
||||
local graph = require(script.Parent.graph)
|
||||
local create_node = graph.create_node
|
||||
local set_owner = graph.set_owner
|
||||
|
|
@ -8,8 +9,10 @@ local get_scope = graph.get_scope
|
|||
local open_scope = graph.open_scope
|
||||
local close_scope = graph.close_scope
|
||||
|
||||
|
||||
local function derive<T>(fn: () -> T): () -> T
|
||||
local owner = get_scope()
|
||||
if not owner then throw("cannot derive in non-reactive scope") end
|
||||
assert(owner)
|
||||
|
||||
local node = create_node((false :: any) :: T)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ if not game then script = require "test/relative-string" end
|
|||
local throw = require(script.Parent.throw)
|
||||
local flags = require(script.Parent.flags)
|
||||
local graph = require(script.Parent.graph)
|
||||
type Scope = graph.Scope
|
||||
type Node<T> = graph.Node<T>
|
||||
type StartNode<T> = graph.StartNode<T>
|
||||
local create_node = graph.create_node
|
||||
local create_start_node = graph.create_start_node
|
||||
|
|
@ -28,9 +28,12 @@ local function check_primitives(t: {})
|
|||
end
|
||||
end
|
||||
|
||||
-- todo: verify destruction of subscopes when owner scope is destroyed
|
||||
|
||||
-- todo: optimize output array
|
||||
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
||||
local owner = get_scope()
|
||||
if not owner then throw("cannot derive in non-reactive scope") end
|
||||
assert(owner)
|
||||
|
||||
local input_cache = {} :: Map<K, VI>
|
||||
|
|
@ -38,7 +41,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
|||
local input_nodes = {} :: Map<K, StartNode<VI>>
|
||||
local remove_queue = {} :: { K }
|
||||
|
||||
local scopes = {} :: Map<K, Scope>
|
||||
local scopes = {} :: Map<K, Node<unknown>>
|
||||
|
||||
local function update_children(data)
|
||||
-- queue removed values
|
||||
|
|
@ -69,7 +72,7 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
|||
if cv ~= v then
|
||||
if cv == nil then
|
||||
local scope = create_node(false)
|
||||
scopes[i] = scope
|
||||
scopes[i] = scope :: Node<any>
|
||||
|
||||
set_owner(scope, owner)
|
||||
open_scope(scope)
|
||||
|
|
@ -122,6 +125,7 @@ end
|
|||
-- todo: optimize output array
|
||||
local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () -> K) -> VO): () -> { VO }
|
||||
local owner = get_scope()
|
||||
if not owner then throw("cannot derive in non-reactive scope") end
|
||||
assert(owner)
|
||||
|
||||
local cur_input_cache_up = {} :: Map<VI, K>
|
||||
|
|
@ -130,7 +134,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
|||
local output_cache = {} :: Map<VI, VO>
|
||||
local input_nodes = {} :: Map<VI, StartNode<K>>
|
||||
|
||||
local scopes = {} :: Map<VI, Scope>
|
||||
local scopes = {} :: Map<VI, Node<unknown>>
|
||||
|
||||
local function update_children(data: Map<K, VI>)
|
||||
local cur_input_cache, new_input_cache = cur_input_cache_up, new_input_cache_up
|
||||
|
|
@ -155,7 +159,7 @@ local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () ->
|
|||
|
||||
if cv == nil then
|
||||
local scope = create_node(false)
|
||||
scopes[v] = scope
|
||||
scopes[v] = scope :: Node<any>
|
||||
|
||||
set_owner(scope, owner)
|
||||
open_scope(scope)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ local destroy = graph.destroy
|
|||
local refs = {}
|
||||
|
||||
local function root<T>(fn: () -> T): (T, () -> ())
|
||||
--assert(not get_scope())
|
||||
local node = create_node(false)
|
||||
|
||||
open_scope(node)
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@ setmetatable(springs, { __mode = "v" })
|
|||
|
||||
local function spring<T>(source: () -> T, period: number?, damping_ratio: number?): () -> T
|
||||
local owner = get_scope()
|
||||
if not owner then throw("cannot derive in non-reactive scope") end
|
||||
assert(owner)
|
||||
|
||||
local updater = create_node(false)
|
||||
|
|
@ -199,6 +200,7 @@ local function spring<T>(source: () -> T, period: number?, damping_ratio: number
|
|||
data.x1_123, data.x1_456 = type_to_vec6[typeof(v)](v)
|
||||
data.source_value = v
|
||||
springs[data] = output -- todo: investigate why insertion is not O(1) at ~20k springs
|
||||
return false
|
||||
end
|
||||
|
||||
return function()
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
if not game then script = require "test/relative-string" end
|
||||
|
||||
local create = require(script.Parent.create)
|
||||
local throw = require(script.Parent.throw)
|
||||
local graph = require(script.Parent.graph)
|
||||
type Node<T> = graph.Node<T>
|
||||
local create_node = graph.create_node
|
||||
local get_scope = graph.get_scope
|
||||
local open_scope = graph.open_scope
|
||||
local close_scope = graph.close_scope
|
||||
|
||||
local function untrack<T>(source: () -> T): T
|
||||
local scope = get_scope()
|
||||
if not scope then throw("cannot untrack in non-reactive scope") end
|
||||
assert(scope)
|
||||
|
||||
local effect = scope.effect
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
if not game then script = require "test/relative-string" end
|
||||
|
||||
local throw = require(script.Parent.throw)
|
||||
local graph = require(script.Parent.graph)
|
||||
local create_node = graph.create_node
|
||||
local get_scope = graph.get_scope
|
||||
|
|
@ -9,9 +10,10 @@ local set_owner = graph.set_owner
|
|||
|
||||
local function watch<T>(effect: (T) -> T, initial_value: T)
|
||||
local owner = get_scope()
|
||||
if not owner then throw("cannot watch in non-reactive scope") end
|
||||
assert(owner)
|
||||
|
||||
local node = create_node(false)
|
||||
local node = create_node(initial_value)
|
||||
node.effect = effect
|
||||
|
||||
set_owner(node, owner)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
local testkit = require("test/testkit")
|
||||
local TEST, CASE, CHECK, FINISH, SKIP = testkit.test()
|
||||
local TEST, CASE, CHECK, FINISH = testkit.test()
|
||||
|
||||
local mock = require "test/mock"
|
||||
local Instance, Signal = mock.Instance, mock.Signal
|
||||
|
|
@ -29,7 +29,7 @@ local function wrap_root(fn: () -> ())
|
|||
end
|
||||
end
|
||||
|
||||
local NIL = NIL
|
||||
local NIL = nil
|
||||
|
||||
TEST("graph", function()
|
||||
local create_node = graph.create_node
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue