diff --git a/docs/api/reactivity-core.md b/docs/api/reactivity-core.md index 02390b7..9585184 100644 --- a/docs/api/reactivity-core.md +++ b/docs/api/reactivity-core.md @@ -50,16 +50,16 @@ Creates a new source with the given value. count(count() + 1) -- 1 ``` -## watch() +## effect() Runs a callback on source update. - **Type** ```lua - function watch(source: () -> ()): Unwatch + function effect(source: () -> ()): Uneffect - type Unwatch = () -> () + type Uneffect = () -> () ``` - **Details** @@ -70,7 +70,7 @@ Runs a callback on source update. Any time a source referenced in the callback is changed, the callback will be reran. - Also returns a function that when called, stops the watcher immediately. + Also returns a function that when called, stops the effecter immediately. ::: warning `source()` cannot yield. @@ -81,7 +81,7 @@ Runs a callback on source update. ```lua local state = source(1) - watch(function() + effect(function() print(state()) end) diff --git a/docs/api/reactivity-flow.md b/docs/api/reactivity-flow.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/api/reactivity-utility.md b/docs/api/reactivity-utility.md index 82b9fd5..35559ee 100644 --- a/docs/api/reactivity-utility.md +++ b/docs/api/reactivity-utility.md @@ -15,7 +15,7 @@ Runs a callback anytime a reactive scope is re-ran. ```lua local data = source(1) - watch(function() + effect(function() local label = create "TextLabel" { Text = data() } cleanup(function() diff --git a/docs/api/strict-mode.md b/docs/api/strict-mode.md index c0f1e7e..54c30fc 100644 --- a/docs/api/strict-mode.md +++ b/docs/api/strict-mode.md @@ -12,14 +12,14 @@ and identifying improper usage. Currently, strict mode will: 1. Run derived sources twice a source updates. -2. Run watchers twice when a source updates. +2. Run effecters twice when a source updates. 3. Throw an error if yields occur where they are not allowed. 4. Checks for `indexes()` and `values()` returning primitive values. 5. Checks for duplicate nested properties at same depth. 6. Better error reporting and stack traces. 7. Checks for multiple `cleanup()` calls in the same function scope. -By rerunning sources and watchers, any side-effects are made more apparent. +By rerunning sources and effecters, any side-effects are made more apparent. This also helps ensure that cleanups are being handled correctly. Accidental yielding within reactive scopes can break Vide's reactive graph, diff --git a/docs/tut/crash-course/8-actions.md b/docs/tut/crash-course/10-actions.md similarity index 100% rename from docs/tut/crash-course/8-actions.md rename to docs/tut/crash-course/10-actions.md diff --git a/docs/tut/crash-course/2-creation.md b/docs/tut/crash-course/2-creation.md index 2a12819..c0ca3c4 100644 --- a/docs/tut/crash-course/2-creation.md +++ b/docs/tut/crash-course/2-creation.md @@ -3,7 +3,7 @@ Instances are created using [`create()`](../../api/creation.md#create). ```lua -local vide = require(path_to_vide) +local vide = require(vide) local create = vide.create ``` diff --git a/docs/tut/crash-course/3-components.md b/docs/tut/crash-course/3-components.md index 0009cf0..42f3fb1 100644 --- a/docs/tut/crash-course/3-components.md +++ b/docs/tut/crash-course/3-components.md @@ -5,7 +5,10 @@ Components are custom-made reusable pieces of UI made from other pieces of UI. By using components you can make your application more modular and better organized. -```lua [Button.lua] +```lua [Button.luau] +local vide = require(vide) +local create = vide.create + local function Button(props: { Position: UDim2, Text: string, @@ -24,7 +27,10 @@ end return Button ``` -```lua [App.lua] +```lua [App.luau] +local vide = require(vide) +local create = vide.create + local Button = require(Button) local function App() @@ -34,7 +40,7 @@ local function App() Text = "click me!", Activated = function() - print "clickeD" + print "clicked" end } } @@ -43,27 +49,17 @@ end root(App).Parent = game.StarterGui ``` -Above is a simple example of a button component with its background color set to -a dark grey and with a fixed size. +Above is a simple example of a button component with a set color and size, +being reused across files. A single parameter `props` is used to pass properties to the component. -Creating instances of this button component is as simple as doing the below: - -```lua -local button = Button { - Position = UDim2.new(), - Text = "Click me!", - - Activated = function() - print "clicked" - end -} -``` Components allow you to *encapsulate* behavior. You can only modify the component in ways that you allow in the component. This also promotes code reusability. Anytime you want a new button all you do is call `Button {}` instead of creating and setting every property each time. +When changing the button in future, any changes to the button file will be +reflected anywhere the button is used throughout your app. This can be extended to much more complicated UI. diff --git a/docs/tut/crash-course/4-source.md b/docs/tut/crash-course/4-source.md index 20ff4f1..c1213dc 100644 --- a/docs/tut/crash-course/4-source.md +++ b/docs/tut/crash-course/4-source.md @@ -9,7 +9,6 @@ A source in Vide can be created using ```lua local source = vide.source - local count = source(0) ``` @@ -24,7 +23,10 @@ count(count() + 1) -- increment source by 1 Below is an example of a stateful counter component. -```lua +```lua [Counter.luau] +local vide = require(vide) +local source = vide.source + local function Counter(props: { Position: UDim2 }) local count = source(0) @@ -54,22 +56,3 @@ This allows you as the programmer to not need to manually update GUI as the stat of your program changes. You just define how the data maps to UI, and Vide's reactive system will surgically update any properties depending on sources that are changed. - -Since sources are just functions, you can also pass external sources to -components like so: - -```lua -local function Text(p: { - Text: () -> string -}) - return create "TextLabel" { - Text = p.Text - } -end - -local text = source "hi" - -Text { - Text = text -} -``` diff --git a/docs/tut/crash-course/5-effect.md b/docs/tut/crash-course/5-effect.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/tut/crash-course/5-derived-source.md b/docs/tut/crash-course/6-derived-source.md similarity index 97% rename from docs/tut/crash-course/5-derived-source.md rename to docs/tut/crash-course/6-derived-source.md index a8b5b05..673d078 100644 --- a/docs/tut/crash-course/5-derived-source.md +++ b/docs/tut/crash-course/6-derived-source.md @@ -63,7 +63,7 @@ callback when deriving or binding sources. If a source is in a function but is never referenced the first time it runs, Vide will not know to rerun the function if that source changes. -An example to watch out for is when using sources within branches: +An example to effect out for is when using sources within branches: ```lua local condition = source(true) diff --git a/docs/tut/crash-course/6-table-source.md b/docs/tut/crash-course/7-control-flow.md similarity index 100% rename from docs/tut/crash-course/6-table-source.md rename to docs/tut/crash-course/7-control-flow.md diff --git a/docs/tut/crash-course/8-cleanup.md b/docs/tut/crash-course/8-cleanup.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/tut/crash-course/7-nested-properties.md b/docs/tut/crash-course/9-property-nesting.md similarity index 100% rename from docs/tut/crash-course/7-nested-properties.md rename to docs/tut/crash-course/9-property-nesting.md diff --git a/src/changed.luau b/src/changed.luau new file mode 100644 index 0000000..5d439c6 --- /dev/null +++ b/src/changed.luau @@ -0,0 +1,18 @@ +if not game then script = require "test/relative-string" end + +local action = require(script.Parent.action)() +local cleanup = require(script.Parent.cleanup) + +local function changed(property: string, callback: (T) -> ()) + return action(function(instance) + local con = instance:GetPropertyChangedSignal(property):Connect(function() + callback((instance :: any)[property]) + end) + + cleanup(function() + con:Disconnect() + end) + end) +end + +return changed diff --git a/src/watch.luau b/src/effect.luau similarity index 70% rename from src/watch.luau rename to src/effect.luau index c5ee5df..12488c4 100644 --- a/src/watch.luau +++ b/src/effect.luau @@ -8,9 +8,9 @@ local open_scope = graph.open_scope local close_scope = graph.close_scope local set_owner = graph.set_owner -local function watch(effect: (T) -> T, initial_value: T) +local function effect(effect: (T) -> T, initial_value: T) local owner = get_scope() - if not owner then throw("cannot watch in non-reactive scope") end + if not owner then throw("cannot effect in non-reactive scope") end assert(owner) local node = create_node(initial_value) @@ -24,4 +24,4 @@ local function watch(effect: (T) -> T, initial_value: T) close_scope() end -return watch :: ((effect: (T) -> T, initial_value: T) -> ()) & ((effect: () -> ()) -> ()) +return effect :: ((effect: (T) -> T, initial_value: T) -> ()) & ((effect: () -> ()) -> ()) diff --git a/src/graph.luau b/src/graph.luau index 6015e40..6f63dd7 100644 --- a/src/graph.luau +++ b/src/graph.luau @@ -41,7 +41,7 @@ local check_for_yield: (fn: (T...) -> unknown, T...) -> () do if not ok then if err == "attempt to yield across metamethod/C-call boundary" or err == "thread is not yieldable" then - throw(EVALUATION_ERR .. "cannot yield when deriving node in watcher") + throw(EVALUATION_ERR .. "cannot yield when deriving node in effecter") else throw(EVALUATION_ERR .. err) end diff --git a/src/init.luau b/src/init.luau index 5d9c5d1..bcacd64 100644 --- a/src/init.luau +++ b/src/init.luau @@ -9,7 +9,7 @@ local root = require(script.root) local create = require(script.create) local apply = require(script.apply) local source = require(script.source) -local watch = require(script.watch) +local effect = require(script.effect) local cleanup = require(script.cleanup) local untrack = require(script.untrack) local derive = require(script.derive) @@ -52,7 +52,7 @@ local vide = { root = root, create = create, source = source, - watch = watch, + effect = effect, derive = derive, indexes = indexes, values = values, diff --git a/test/spring-test.luau b/test/spring-test.luau index f2f19f3..21f2d18 100644 --- a/test/spring-test.luau +++ b/test/spring-test.luau @@ -37,12 +37,12 @@ local function main() local source = vide.source local spring = vide.spring - local watch = vide.watch + local effect = vide.effect local value = source(MAX) local sprung = spring(value, 1, 0.3) - watch(function() + effect(function() local v = sprung() local fv = math.floor(v) local reset = "\27[H\27[2J" -- ANSI clear terminal diff --git a/test/tests.luau b/test/tests.luau index 9c7fbe9..a47b139 100644 --- a/test/tests.luau +++ b/test/tests.luau @@ -261,7 +261,7 @@ end) TEST("source()", wrap_root(function() local source = vide.source - local watch = vide.watch + local effect = vide.effect do CASE "create source" local src = source(1) @@ -278,7 +278,7 @@ TEST("source()", wrap_root(function() local src = source(1) local count = 0 - watch(function() + effect(function() src() count += 1 end) @@ -294,7 +294,7 @@ TEST("source()", wrap_root(function() local src = source {} local count = 0 - watch(function() + effect(function() src() count += 1 end) @@ -311,7 +311,7 @@ TEST("source()", wrap_root(function() local src = source(a) local count = 0 - watch(function() + effect(function() src() count += 1 end) @@ -330,7 +330,7 @@ TEST("derive()", wrap_root(function() local root = vide.root local source = vide.source local derive = vide.derive - local watch = vide.watch + local effect = vide.effect local cleanup = vide.cleanup do CASE "derive new value on source change" @@ -371,7 +371,7 @@ TEST("derive()", wrap_root(function() local count = 0 - watch(function() + effect(function() is_even() count += 1 end) @@ -399,7 +399,7 @@ TEST("derive()", wrap_root(function() local count = 0 - watch(function() c() count += 1 end) + effect(function() c() count += 1 end) b(true) CHECK(c() == "b") @@ -455,16 +455,16 @@ TEST("derive()", wrap_root(function() end end)) -TEST("watch()", wrap_root(function() +TEST("effect()", wrap_root(function() local source = vide.source - local watch = vide.watch + local effect = vide.effect do CASE "rerun on source change" local a = source(1) local b = source(1) local count = 0 - watch(function() + effect(function() a() b() count += 1 @@ -481,7 +481,7 @@ end)) TEST("cleanup()", wrap_root(function() local root = vide.root local source = vide.source - local watch = vide.watch + local effect = vide.effect local cleanup = vide.cleanup do CASE "root cleanup" @@ -503,23 +503,23 @@ TEST("cleanup()", wrap_root(function() do CASE "cleanup on rerun" local state = source(1) - local watched = 0 + local effected = 0 local cleaned = 0 - watch(function() + effect(function() state() - watched += 1 + effected += 1 cleanup(function() cleaned += 1 end) end) - CHECK(watched == 1) + CHECK(effected == 1) CHECK(cleaned == 0) state(2) - CHECK(watched == 2) + CHECK(effected == 2) CHECK(cleaned == 1) end @@ -528,7 +528,7 @@ TEST("cleanup()", wrap_root(function() local queue = {} - watch(function() + effect(function() state() cleanup(function() table.insert(queue, 1) end) cleanup(function() table.insert(queue, 2) end) @@ -1001,7 +1001,7 @@ TEST("spring()", wrap_root(function() local create = vide.create local source = vide.source local spring = vide.spring - local watch = vide.watch + local effect = vide.effect do CASE "update source (on next step)" local value = source(10) @@ -1082,7 +1082,7 @@ TEST("spring()", wrap_root(function() CHECK(output() == input()) -- check spring is at target local count = -1 - watch(function() + effect(function() output() count += 1 end) @@ -1102,7 +1102,7 @@ TEST("untrack()", wrap_root(function() local root = vide.root local source = vide.source local derive = vide.derive - local watch = vide.watch + local effect = vide.effect local cleanup = vide.cleanup local untrack = vide.untrack @@ -1112,7 +1112,7 @@ TEST("untrack()", wrap_root(function() local count = 0 - watch(function() + effect(function() count += 1 untrack(a) b() @@ -1138,7 +1138,7 @@ TEST("untrack()", wrap_root(function() local count = 0 - watch(function() + effect(function() count += 1 untrack(d) c() @@ -1275,7 +1275,7 @@ end) -- local create = vide.create -- local source = vide.source -- local derive = vide.derive --- local watch = vide.watch +-- local effect = vide.effect -- local indexes, values = vide.indexes, vide.values -- local cleanup = vide.cleanup @@ -1292,11 +1292,11 @@ end) -- -- CHECK(not ok) -- -- end --- -- do CASE "error on watcher callback yield" +-- -- do CASE "error on effecter callback yield" -- -- local state = source(1) -- -- local ok = pcall(function() --- -- local _derived = watch(function() +-- -- local _derived = effect(function() -- -- coroutine.yield() -- -- state() -- -- end) @@ -1319,11 +1319,11 @@ end) -- CHECK(runcount == 4) -- end --- do CASE "run watcher callback twice" +-- do CASE "run effecter callback twice" -- local state = source(1) -- local runcount = 0 --- watch(function() +-- effect(function() -- runcount += 1 -- state() -- end)