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/>
|
<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()
|
## source()
|
||||||
|
|
||||||
Creates a new source with the given value.
|
Creates a new source with the given value.
|
||||||
|
|
@ -14,10 +34,10 @@ Creates a new source with the given value.
|
||||||
|
|
||||||
- **Details**
|
- **Details**
|
||||||
|
|
||||||
Calling the returned source with no arguments will return its stored value,
|
Calling the returned source with no argument will return its stored value,
|
||||||
calling with arguments will set a new 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.
|
to that source to be tracked and anything depending on it to update.
|
||||||
|
|
||||||
- **Example**
|
- **Example**
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## cleanup()
|
## cleanup()
|
||||||
|
|
||||||
Runs a callback anytime a function scope is re-ran.
|
Runs a callback anytime a reactive scope is re-ran.
|
||||||
|
|
||||||
- **Type**
|
- **Type**
|
||||||
|
|
||||||
|
|
@ -10,19 +10,6 @@ Runs a callback anytime a function scope is re-ran.
|
||||||
function cleanup(callback: () -> ())
|
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**
|
- **Example**
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|
@ -53,7 +40,7 @@ Runs a callback anytime a function scope is re-ran.
|
||||||
|
|
||||||
## untrack()
|
## 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**
|
- **Type**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
This is a brief tutorial designed to give you a quick run through the usage of
|
This is a brief tutorial designed to give you a quick run through the usage of
|
||||||
Vide.
|
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?
|
## Why Vide?
|
||||||
|
|
||||||
|
|
@ -21,5 +21,6 @@ Some of the main focuses behind Vide's design choices:
|
||||||
- Being completely typecheckable.
|
- Being completely typecheckable.
|
||||||
- Flexibility, particularly with integrating other libraries and allowing users
|
- Flexibility, particularly with integrating other libraries and allowing users
|
||||||
to use their own patterns.
|
to use their own patterns.
|
||||||
- A powerful reactive system that does not interfere with the lifetime of
|
- Independence from instance lifetimes.
|
||||||
instances.
|
- 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
|
-- finally set parent if any
|
||||||
if parent then
|
if parent then
|
||||||
if type(parent) == "function" then
|
if type(parent) == "function" then
|
||||||
bind.parent(instance, parent :: () -> ())
|
bind.parent(instance, parent :: () -> Instance)
|
||||||
else
|
else
|
||||||
instance.Parent = parent :: Instance
|
instance.Parent = parent :: Instance
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ function create_binding<T>(updater: (T) -> T, binding_data: T)
|
||||||
binding.effect = updater
|
binding.effect = updater
|
||||||
|
|
||||||
local owner = get_scope()
|
local owner = get_scope()
|
||||||
|
if not owner then throw("cannot bind property in non-reactive scope") end
|
||||||
assert(owner)
|
assert(owner)
|
||||||
|
|
||||||
set_owner(binding, owner)
|
set_owner(binding, owner)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
if not game then script = require "test/relative-string" end
|
if not game then script = require "test/relative-string" end
|
||||||
|
|
||||||
local flags = require(script.Parent.flags)
|
|
||||||
local throw = require(script.Parent.throw)
|
local throw = require(script.Parent.throw)
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
local get_scope = graph.get_scope
|
local get_scope = graph.get_scope
|
||||||
local add_cleanup = graph.add_cleanup
|
local add_cleanup = graph.add_cleanup
|
||||||
|
|
||||||
local function cleanup(fn: () -> ())
|
local function cleanup(fn: () -> ())
|
||||||
local node = get_scope()
|
local scope = get_scope()
|
||||||
if node == nil then throw("cannot call cleanup() in a non-reactive scope") end
|
if not scope then throw("cannot cleanup in a non-reactive scope") end
|
||||||
add_cleanup(node, fn)
|
assert(scope)
|
||||||
|
|
||||||
|
add_cleanup(scope, fn)
|
||||||
end
|
end
|
||||||
|
|
||||||
return cleanup
|
return cleanup
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
if not game then script = require "test/relative-string" end
|
if not game then script = require "test/relative-string" end
|
||||||
|
|
||||||
|
local throw = require(script.Parent.throw)
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
local create_node = graph.create_node
|
local create_node = graph.create_node
|
||||||
local set_owner = graph.set_owner
|
local set_owner = graph.set_owner
|
||||||
|
|
@ -8,8 +9,10 @@ local get_scope = graph.get_scope
|
||||||
local open_scope = graph.open_scope
|
local open_scope = graph.open_scope
|
||||||
local close_scope = graph.close_scope
|
local close_scope = graph.close_scope
|
||||||
|
|
||||||
|
|
||||||
local function derive<T>(fn: () -> T): () -> T
|
local function derive<T>(fn: () -> T): () -> T
|
||||||
local owner = get_scope()
|
local owner = get_scope()
|
||||||
|
if not owner then throw("cannot derive in non-reactive scope") end
|
||||||
assert(owner)
|
assert(owner)
|
||||||
|
|
||||||
local node = create_node((false :: any) :: T)
|
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 throw = require(script.Parent.throw)
|
||||||
local flags = require(script.Parent.flags)
|
local flags = require(script.Parent.flags)
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
type Scope = graph.Scope
|
type Node<T> = graph.Node<T>
|
||||||
type StartNode<T> = graph.StartNode<T>
|
type StartNode<T> = graph.StartNode<T>
|
||||||
local create_node = graph.create_node
|
local create_node = graph.create_node
|
||||||
local create_start_node = graph.create_start_node
|
local create_start_node = graph.create_start_node
|
||||||
|
|
@ -28,9 +28,12 @@ local function check_primitives(t: {})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- todo: verify destruction of subscopes when owner scope is destroyed
|
||||||
|
|
||||||
-- todo: optimize output array
|
-- todo: optimize output array
|
||||||
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
||||||
local owner = get_scope()
|
local owner = get_scope()
|
||||||
|
if not owner then throw("cannot derive in non-reactive scope") end
|
||||||
assert(owner)
|
assert(owner)
|
||||||
|
|
||||||
local input_cache = {} :: Map<K, VI>
|
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 input_nodes = {} :: Map<K, StartNode<VI>>
|
||||||
local remove_queue = {} :: { K }
|
local remove_queue = {} :: { K }
|
||||||
|
|
||||||
local scopes = {} :: Map<K, Scope>
|
local scopes = {} :: Map<K, Node<unknown>>
|
||||||
|
|
||||||
local function update_children(data)
|
local function update_children(data)
|
||||||
-- queue removed values
|
-- 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 ~= v then
|
||||||
if cv == nil then
|
if cv == nil then
|
||||||
local scope = create_node(false)
|
local scope = create_node(false)
|
||||||
scopes[i] = scope
|
scopes[i] = scope :: Node<any>
|
||||||
|
|
||||||
set_owner(scope, owner)
|
set_owner(scope, owner)
|
||||||
open_scope(scope)
|
open_scope(scope)
|
||||||
|
|
@ -122,6 +125,7 @@ end
|
||||||
-- todo: optimize output array
|
-- todo: optimize output array
|
||||||
local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () -> K) -> VO): () -> { VO }
|
local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () -> K) -> VO): () -> { VO }
|
||||||
local owner = get_scope()
|
local owner = get_scope()
|
||||||
|
if not owner then throw("cannot derive in non-reactive scope") end
|
||||||
assert(owner)
|
assert(owner)
|
||||||
|
|
||||||
local cur_input_cache_up = {} :: Map<VI, K>
|
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 output_cache = {} :: Map<VI, VO>
|
||||||
local input_nodes = {} :: Map<VI, StartNode<K>>
|
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 function update_children(data: Map<K, VI>)
|
||||||
local cur_input_cache, new_input_cache = cur_input_cache_up, new_input_cache_up
|
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
|
if cv == nil then
|
||||||
local scope = create_node(false)
|
local scope = create_node(false)
|
||||||
scopes[v] = scope
|
scopes[v] = scope :: Node<any>
|
||||||
|
|
||||||
set_owner(scope, owner)
|
set_owner(scope, owner)
|
||||||
open_scope(scope)
|
open_scope(scope)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ local destroy = graph.destroy
|
||||||
local refs = {}
|
local refs = {}
|
||||||
|
|
||||||
local function root<T>(fn: () -> T): (T, () -> ())
|
local function root<T>(fn: () -> T): (T, () -> ())
|
||||||
--assert(not get_scope())
|
|
||||||
local node = create_node(false)
|
local node = create_node(false)
|
||||||
|
|
||||||
open_scope(node)
|
open_scope(node)
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@ setmetatable(springs, { __mode = "v" })
|
||||||
|
|
||||||
local function spring<T>(source: () -> T, period: number?, damping_ratio: number?): () -> T
|
local function spring<T>(source: () -> T, period: number?, damping_ratio: number?): () -> T
|
||||||
local owner = get_scope()
|
local owner = get_scope()
|
||||||
|
if not owner then throw("cannot derive in non-reactive scope") end
|
||||||
assert(owner)
|
assert(owner)
|
||||||
|
|
||||||
local updater = create_node(false)
|
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.x1_123, data.x1_456 = type_to_vec6[typeof(v)](v)
|
||||||
data.source_value = v
|
data.source_value = v
|
||||||
springs[data] = output -- todo: investigate why insertion is not O(1) at ~20k springs
|
springs[data] = output -- todo: investigate why insertion is not O(1) at ~20k springs
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
if not game then script = require "test/relative-string" end
|
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)
|
local graph = require(script.Parent.graph)
|
||||||
type Node<T> = graph.Node<T>
|
type Node<T> = graph.Node<T>
|
||||||
local create_node = graph.create_node
|
|
||||||
local get_scope = graph.get_scope
|
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 function untrack<T>(source: () -> T): T
|
||||||
local scope = get_scope()
|
local scope = get_scope()
|
||||||
|
if not scope then throw("cannot untrack in non-reactive scope") end
|
||||||
assert(scope)
|
assert(scope)
|
||||||
|
|
||||||
local effect = scope.effect
|
local effect = scope.effect
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
if not game then script = require "test/relative-string" end
|
if not game then script = require "test/relative-string" end
|
||||||
|
|
||||||
|
local throw = require(script.Parent.throw)
|
||||||
local graph = require(script.Parent.graph)
|
local graph = require(script.Parent.graph)
|
||||||
local create_node = graph.create_node
|
local create_node = graph.create_node
|
||||||
local get_scope = graph.get_scope
|
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 function watch<T>(effect: (T) -> T, initial_value: T)
|
||||||
local owner = get_scope()
|
local owner = get_scope()
|
||||||
|
if not owner then throw("cannot watch in non-reactive scope") end
|
||||||
assert(owner)
|
assert(owner)
|
||||||
|
|
||||||
local node = create_node(false)
|
local node = create_node(initial_value)
|
||||||
node.effect = effect
|
node.effect = effect
|
||||||
|
|
||||||
set_owner(node, owner)
|
set_owner(node, owner)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
local testkit = require("test/testkit")
|
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 mock = require "test/mock"
|
||||||
local Instance, Signal = mock.Instance, mock.Signal
|
local Instance, Signal = mock.Instance, mock.Signal
|
||||||
|
|
@ -29,7 +29,7 @@ local function wrap_root(fn: () -> ())
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local NIL = NIL
|
local NIL = nil
|
||||||
|
|
||||||
TEST("graph", function()
|
TEST("graph", function()
|
||||||
local create_node = graph.create_node
|
local create_node = graph.create_node
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue