allow fragments in implicit effects for children (#29)

* fix fragments in effects

* add test case

* more descriptive test
This commit is contained in:
alicesaidhi 2024-08-20 13:40:29 +02:00 committed by GitHub
parent 72e5fbb6fe
commit b85419088c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 49 additions and 3 deletions

View file

@ -11,6 +11,7 @@ local graph = require(script.Parent.graph)
type Node<T> = graph.Node<T> type Node<T> = graph.Node<T>
type Array<V> = { V } type Array<V> = { V }
type ArrayOrV<V> = {ArrayOrV<V>} | V
type Map<K, V> = { [K]: V } type Map<K, V> = { [K]: V }
local free_caches: { local free_caches: {
@ -124,7 +125,7 @@ local function apply<T>(instance: T & Instance, properties: { [unknown]: unknown
end end
elseif type(property) == "number" then elseif type(property) == "number" then
if type(value) == "function" then if type(value) == "function" then
bind.children(instance, value :: () -> Instance | Array<Instance>) -- bind children bind.children(instance, value :: () -> ArrayOrV<Instance>) -- bind children
elseif type(value) == "table" then elseif type(value) == "table" then
if is_action(value) then if is_action(value) then
table.insert(actions[(value :: any).priority], (value :: any).callback :: () -> ()) -- add action to buffer table.insert(actions[(value :: any).priority], (value :: any).callback :: () -> ()) -- add action to buffer

View file

@ -38,6 +38,7 @@ type ChildrenBinding = {
children: () -> Instance | { Instance } children: () -> Instance | { Instance }
} }
type ArrayOrV<V> = V | { V }
local function update_children_effect(p: ChildrenBinding) local function update_children_effect(p: ChildrenBinding)
local cur_children_set: { [Instance]: true } = p.cur_children_set -- cache of all children parented before update local cur_children_set: { [Instance]: true } = p.cur_children_set -- cache of all children parented before update
local new_child_set: { [Instance]: true } = p.new_children_set -- cache of all children parented after update local new_child_set: { [Instance]: true } = p.new_children_set -- cache of all children parented after update
@ -48,8 +49,14 @@ local function update_children_effect(p: ChildrenBinding)
new_children = { new_children } new_children = { new_children }
end end
if new_children then local function process_child(child: ArrayOrV<Instance>)
for _, child in next, new_children :: { Instance } do if type(child) == "table" then
for _, child in next, child do
process_child(child)
end
else
if new_child_set[child] then return end -- stops redundant reparenting
new_child_set[child] = true -- record child set from this update new_child_set[child] = true -- record child set from this update
if not cur_children_set[child] then if not cur_children_set[child] then
child.Parent = p.instance -- if child wasn't already parented then parent it child.Parent = p.instance -- if child wasn't already parented then parent it
@ -59,6 +66,8 @@ local function update_children_effect(p: ChildrenBinding)
end end
end end
process_child(new_children)
for child in next, cur_children_set do for child in next, cur_children_set do
child.Parent = nil -- unparent all children that weren't in the new children set child.Parent = nil -- unparent all children that weren't in the new children set
end end

View file

@ -945,6 +945,42 @@ TEST("create()", wrap_root(function()
CHECK((f2 :: any).a == 2) CHECK((f2 :: any).a == 2)
end end
do CASE "nested children effect"
local a = create "Frame" { Name = "a" }
local b = create "Frame" { Name = "b" }
local c = create "Frame" { Name = "c" }
local d = create "Frame" { Name = "d" }
local e = create "Frame" { Name = "e" }
local children = source {
a,
{ b, c, { d } },
{ { e } }
}
local obj = create "Frame" {
children
}
CHECK(obj:FindFirstChild("a"))
CHECK(obj:FindFirstChild("b"))
CHECK(obj:FindFirstChild("c"))
CHECK(obj:FindFirstChild("d"))
CHECK(obj:FindFirstChild("e"))
children {
b,
{ c, a },
{ { d } }
}
CHECK(obj:FindFirstChild("a"))
CHECK(obj:FindFirstChild("b"))
CHECK(obj:FindFirstChild("c"))
CHECK(obj:FindFirstChild("d"))
CHECK(not obj:FindFirstChild("e"))
end
do CASE "garbage collection test" do CASE "garbage collection test"
local wref local wref