1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
--!strict
local Type = require(script.Parent.Type)
local Symbol = require(script.Parent.Symbol)
local function noop()
return nil
end
local ElementUtils = {}
--[[
A signal value indicating that a child should use its parent's key, because
it has no key of its own.
This occurs when you return only one element from a function component or
stateful render function.
]]
ElementUtils.UseParentKey = Symbol.named("UseParentKey")
type Iterator<K, V> = ({ [K]: V }, K?) -> (K?, V?)
type Element = { [any]: any }
--[[
Returns an iterator over the children of an element.
`elementOrElements` may be one of:
* a boolean
* nil
* a single element
* a fragment
* a table of elements
If `elementOrElements` is a boolean or nil, this will return an iterator with
zero elements.
If `elementOrElements` is a single element, this will return an iterator with
one element: a tuple where the first value is ElementUtils.UseParentKey, and
the second is the value of `elementOrElements`.
If `elementOrElements` is a fragment or a table, this will return an iterator
over all the elements of the array.
If `elementOrElements` is none of the above, this function will throw.
]]
function ElementUtils.iterateElements<K>(elementOrElements): (Iterator<K, Element>, any, nil)
local richType = Type.of(elementOrElements)
-- Single child
if richType == Type.Element then
local called = false
return function(_, _)
if called then
return nil
else
called = true
return ElementUtils.UseParentKey, elementOrElements
end
end
end
local regularType = typeof(elementOrElements)
if elementOrElements == nil or regularType == "boolean" then
return (noop :: any) :: Iterator<K, Element>
end
if regularType == "table" then
return pairs(elementOrElements)
end
error("Invalid elements")
end
--[[
Gets the child corresponding to a given key, respecting Roact's rules for
children. Specifically:
* If `elements` is nil or a boolean, this will return `nil`, regardless of
the key given.
* If `elements` is a single element, this will return `nil`, unless the key
is ElementUtils.UseParentKey.
* If `elements` is a table of elements, this will return `elements[key]`.
]]
function ElementUtils.getElementByKey(elements, hostKey)
if elements == nil or typeof(elements) == "boolean" then
return nil
end
if Type.of(elements) == Type.Element then
if hostKey == ElementUtils.UseParentKey then
return elements
end
return nil
end
if typeof(elements) == "table" then
return elements[hostKey]
end
error("Invalid elements")
end
return ElementUtils