Add source to show() callback

This commit is contained in:
aaron 2025-01-04 00:40:51 +00:00
parent 58a31a1b32
commit c796e48173
3 changed files with 84 additions and 17 deletions

View file

@ -16,6 +16,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
effects to set children.
- `spring()` returns a second value, a setter to set position, velocity and
impulse.
- `show()` now receives a source to its callback returning the current value
of the condition.
### Changed

View file

@ -1,16 +1,28 @@
local switch = require "./switch"
local derive = require "./derive"
local untrack = require "./untrack"
local function show<T>(source: () -> any, component: () -> T, fallback: (() -> T)?): () -> T?
local function truthy()
local function show<T, U>(source: () -> T?, component: (() -> T) -> U, fallback: (() -> U)?): () -> U?
local truthy = derive(function()
return not not source()
end)
-- seemingly redundant derivation to extend the reactive graph so that
-- the propogation of the source's update is delayed, giving time for
-- the show() scope to be destroyed before potential effects registered
-- by the component can run when they should not run
-- todo: are there cases this method does not cover?
local derived = derive(function()
return source()
end)
return derive(function()
return
if truthy() then untrack(function() return component(derived :: () -> T) end)
elseif fallback then untrack(fallback)
else nil
end)
end
return switch(truthy) {
[true] = component,
[false] = fallback,
}
end
return show ::
(<T>(source: () -> any, component: () -> T) -> () -> T?) &
(<T, U>(source: () -> any, component: () -> T, fallback: () -> U) -> () -> (T | U)?)
return show :: (
( <T, U>(source: () -> T?, component: (() -> T) -> U) -> () -> U? )
)

View file

@ -1073,20 +1073,73 @@ TEST("show()", wrap_root(function()
local show = vide.show
local root = vide.root
do CASE "main"
-- uses switch() internally, more extensive testing of scoping not needed
local value = source("truey" :: unknown)
do CASE "show component"
local input = source(true)
local function one() return 1 end
local output = show(input, one)
CHECK(output() == 1)
input(false)
CHECK(output() == nil)
end
do CASE "fallback component"
local input = source(true)
local function one() return 1 end
local function two() return 2 end
local output = show(value, one, two)
local output = show(input, one, two)
CHECK(output() == 1)
value(nil)
input(false)
CHECK(output() == 2)
end
do CASE "alt"
do CASE "updating truth to truthy does not rerun"
local input = source(1)
local count = 0
local function component()
count += 1
return 1
end
local output = show(input, component)
CHECK(count == 1)
CHECK(output() == 1)
input(2)
CHECK(count == 1)
end
do CASE "updating source passed to component"
local input = source(1 :: number?)
local count = 0
show(input :: () -> number?, function(value: () -> number)
vide.cleanup(function() print "destroyed" end)
effect(function()
local v = value()
count += 1
CHECK(v == count)
if v ~= count then error(count) end
end)
return true
end)
input(2)
CHECK(count == 2)
input(3)
CHECK(count == 3)
input(nil)
CHECK(count == 3)
end
do CASE "alt" -- todo: move test
local visible = vide.source(true)
local count = vide.source(0)