This commit is contained in:
lx
2026-07-06 14:01:11 -04:00
commit c4f97d729d
16468 changed files with 935321 additions and 0 deletions
@@ -0,0 +1,12 @@
--[[
Package link auto-generated by Rotriever
]]
local PackageIndex = script.Parent.Parent
local package = PackageIndex["roblox_cryo"]["cryo"]
if package.ClassName == "ModuleScript" then
return require(package)
end
return package
@@ -0,0 +1,12 @@
--[[
Package link auto-generated by Rotriever
]]
local PackageIndex = script.Parent.Parent
local package = PackageIndex["roblox_roact-fit-components"]["roact-fit-components"]
if package.ClassName == "ModuleScript" then
return require(package)
end
return package
@@ -0,0 +1,12 @@
--[[
Package link auto-generated by Rotriever
]]
local PackageIndex = script.Parent.Parent
local package = PackageIndex["roblox_lumberyak-6ce30d59-0.1.1"]["lumberyak"]
if package.ClassName == "ModuleScript" then
return require(package)
end
return package
@@ -0,0 +1,12 @@
--[[
Package link auto-generated by Rotriever
]]
local PackageIndex = script.Parent.Parent
local package = PackageIndex["roblox_otter"]["otter"]
if package.ClassName == "ModuleScript" then
return require(package)
end
return package
@@ -0,0 +1,12 @@
--[[
Package link auto-generated by Rotriever
]]
local PackageIndex = script.Parent.Parent
local package = PackageIndex["roblox_roact"]["roact"]
if package.ClassName == "ModuleScript" then
return require(package)
end
return package
@@ -0,0 +1,16 @@
return {
-- Returns the signed distance from a point to a range. Returns 0 if the
-- point is within the range, positive if it's below and negative if it's
-- above.
fromPointToRangeSigned = function(point: number, rangeTop: number, rangeSize: number)
local rangeBottom = rangeTop + rangeSize
if point < rangeTop then
return point - rangeTop
elseif point > rangeBottom then
return point - rangeBottom
else
return 0
end
end
}
@@ -0,0 +1,83 @@
--[[
KeyPool provides a pool of objects suitable for use as map keys.
Create a new KeyPool, then call pool:get() to get a new key. Once you're done with it, call key:release().
Example:
local pool = KeyPool.new("foo")
...
local key1 = pool:get()
local key2 = pool:get()
map[key1] = thing1
map[key2] = thing2
...
map[key1] = nil
key1:release()
key1 = nil
]]
local Root = script:FindFirstAncestor("infinite-scroller").Parent
local t = require(Root.t)
-- Forward declarations
local KeyPool = {}
KeyPool.__index = KeyPool
local Key = {}
Key.__index = Key
-- This is Key.new, but we don't want to expose that publicly.
local function newkey(pool: KeyPool, index)
local key = {
pool = pool,
index = index,
}
setmetatable(key, Key)
return key
end
-- KeyPool functions
function KeyPool.new(class: string)
assert(t.string(class))
local pool = {
class = class,
available = {},
limit = 0,
count = 0,
}
setmetatable(pool, KeyPool)
return pool
end
export type KeyPool = typeof(KeyPool.new(""))
export type Key = typeof(newkey(KeyPool.new(""), 1))
-- Get a currently unused key, or create a new one if everything is in use.
function KeyPool.get(self: KeyPool): Key
if self.count == 0 then
self.limit = self.limit + 1
return newkey(self, self.limit)
end
local key = self.available[self.count]
self.count = self.count - 1
return key
end
-- Key functions
function Key.__tostring(self: Key)
return self.pool.class .. "_" .. string.format("%02d", self.index)
end
-- Return this key to the pool it came from. Whatever previously held this key should not keep the reference after
-- calling this.
function Key.release(self: Key)
self.pool.count = self.pool.count + 1
self.pool.available[self.pool.count] = self
end
return KeyPool
@@ -0,0 +1,4 @@
local Root = script:FindFirstAncestor("infinite-scroller").Parent
local Lumberyak = require(Root.Lumberyak)
return Lumberyak.Logger.new(nil, script:GetFullName())
@@ -0,0 +1,31 @@
-- Enum for specifying the leading edge of the scroller.
local Root = script:FindFirstAncestor("infinite-scroller").Parent
local t = require(Root.t)
local Orientation = {
Up = "Orientation.Up",
Down = "Orientation.Down",
Left = "Orientation.Left",
Right = "Orientation.Right",
}
local metaindex = {
isOrientation = t.union(
t.literal(Orientation.Up),
t.literal(Orientation.Down),
t.literal(Orientation.Left),
t.literal(Orientation.Right)
)
}
setmetatable(Orientation, {
__index = function(self, key)
return metaindex[key] or
error(tostring(key) .. " is not a valid member of Scroller.Orientation", 2)
end,
__newindex = function()
error("Scroller.Orientation is read-only", 2)
end,
})
return Orientation
@@ -0,0 +1,28 @@
local epsilon = 1e-15
return {
nearest = function(num)
local q, r = math.modf(num)
if r <= -0.5 then
return q - 1
elseif r >= 0.5 then
return q + 1
else
return q
end
end,
towardsZero = function(num)
local result, _ = math.modf(num)
return result
end,
awayFromZero = function(num)
local q, r = math.modf(num)
if r < -epsilon then
return q - 1
elseif r > epsilon then
return q + 1
else
return q
end
end,
}
@@ -0,0 +1,10 @@
local Root = script:FindFirstAncestor("infinite-scroller").Parent
local Lumberyak = require(Root.Lumberyak)
local TimeLogger = Lumberyak.Logger.new(nil, script:GetFullName())
TimeLogger:setContext({
tick = tick,
prefix = "{tick}: ",
})
return TimeLogger
@@ -0,0 +1,67 @@
-- Find the new indicies of the trailing, anchor and leading elements.
-- props is expected to contain itemList, the identifier function and the maximum search distance.
-- state is expected to contain the old top, anchor and bottom indices and ids.
return function(props, state): (number?, number?, number?)
local topIndex = state.trail.index
local topID = state.trail.id
local anchorIndex = state.anchor.index
local anchorID = state.anchor.id
local bottomIndex = state.lead.index
local bottomID = state.lead.id
local listSize = #props.itemList
-- If too much got deleted and the previous anchor index is off the bottom of the list, start the search from
-- the bottom.
if topIndex > listSize then
topIndex = listSize
end
if anchorIndex > listSize then
anchorIndex = listSize
end
if bottomIndex > listSize then
bottomIndex = listSize
end
-- No access to self:getID
local getID = function(index): string
return props.identifier(props.itemList[index])
end
local topStill = getID(topIndex) == topID
local anchorStill = getID(anchorIndex) == anchorID
local bottomStill = getID(bottomIndex) == bottomID
if topStill and anchorStill and bottomStill then
-- Nothing important moved
return topIndex, anchorIndex, bottomIndex
end
local step = 0
local foundTop = topStill and topIndex or nil
local foundAnchor = nil
local foundBottom = bottomStill and bottomIndex or nil
-- Scan outward from the old anchor index until we find the top and bottom or hit the max distance
local deltas = {top=-1, bottom=1}
repeat
for _, delta: number in pairs(deltas) do
local pos = anchorIndex + delta * step
if pos >= 1 and pos <= listSize then
local id = getID(pos)
if id == topID then
foundTop = pos
end
if id == anchorID then
foundAnchor = pos
end
if id == bottomID then
foundBottom = pos
end
end
end
step = step + 1
until (foundTop and foundAnchor and foundBottom) or step > props.maximumSearchDistance
return foundTop, foundAnchor, foundBottom
end
@@ -0,0 +1,71 @@
local Round = require(script.Parent.Round)
export type Indices = {
anchorIndex: number?,
leadIndex: number?,
trailIndex: number?,
}
-- Returns the three new indices with any nils filled in and any misorderings corrected.
-- new and old should be tables containing an anchorIndex, a leadIndex and a trailIndex.
return function(new: Indices, old: Indices, listSize: number): Indices
local isNewAnchorPresent: boolean = new.anchorIndex ~= nil
local isNewLeadPresent: boolean = new.leadIndex ~= nil
local isNewTrailPresent: boolean = new.trailIndex ~= nil
local finalAnchorIndex: number = tonumber(new.anchorIndex or 0)
local finalLeadIndex: number = tonumber(new.leadIndex or 0)
local finalTrailIndex: number = tonumber(new.trailIndex or 0)
local oldAnchorIndex: number = tonumber(old.anchorIndex or 0)
local oldLeadIndex: number = tonumber(old.leadIndex or 0)
local oldTrailIndex: number = tonumber(old.trailIndex or 0)
-- There are 8 possibilities here as any combination of these could be deleted. Also, we can't use findIndexAt
-- here since that requires access to the children's measurements.
if not isNewAnchorPresent then
if isNewLeadPresent and isNewTrailPresent then
-- Estimate that the new anchor is proportionally the same distance from the lead and trail indices.
if finalLeadIndex == finalTrailIndex then
-- Guard against divide by zero.
finalAnchorIndex = finalLeadIndex
else
local oldRatio = (oldAnchorIndex - oldLeadIndex) / (oldTrailIndex - oldLeadIndex)
finalAnchorIndex = Round.nearest((finalTrailIndex - finalLeadIndex) * oldRatio + finalLeadIndex)
finalAnchorIndex = math.min(math.max(finalAnchorIndex, 1), listSize)
end
elseif isNewLeadPresent then
-- Given only the new leading index, estimate that the new anchor is the same distance away as it was.
finalAnchorIndex = finalLeadIndex + oldAnchorIndex - oldLeadIndex
finalAnchorIndex = math.min(math.max(finalAnchorIndex, 1), listSize)
elseif isNewTrailPresent then
-- Given only the new trailing index, estimate that the new anchor is the same distance away as it was.
finalAnchorIndex = finalTrailIndex + oldAnchorIndex - oldTrailIndex
finalAnchorIndex = math.min(math.max(finalAnchorIndex, 1), listSize)
else
-- Everything is gone. Just reuse the same index if that's still within the bounds of the list.
finalAnchorIndex = math.min(math.max(oldAnchorIndex, 1), listSize)
end
end
-- If the leading and trailing indices haven't been worked out yet, estimate that the new ones should be the
-- same distance from the anchor as the old ones were.
if not isNewTrailPresent then
finalTrailIndex = finalAnchorIndex + oldTrailIndex - oldAnchorIndex
finalTrailIndex = math.min(math.max(finalTrailIndex, 1), listSize)
end
if not isNewLeadPresent then
finalLeadIndex = finalAnchorIndex + oldLeadIndex - oldAnchorIndex
finalLeadIndex = math.min(math.max(finalLeadIndex, 1), listSize)
end
-- Make sure the resulting indices are in the right order.
local minIndex = math.min(finalAnchorIndex, finalLeadIndex, finalTrailIndex)
local maxIndex = math.max(finalAnchorIndex, finalLeadIndex, finalTrailIndex)
return {
trailIndex = minIndex,
anchorIndex = finalAnchorIndex,
leadIndex = maxIndex,
}
end
@@ -0,0 +1,7 @@
local Scroller = require(script.Components.Scroller)
local Logger = require(script.Components.Logger)
return {
Scroller = Scroller,
Logger = Logger,
}
@@ -0,0 +1,13 @@
# Generated by Rotriever. Format subject to change in future releases.
name = "roblox/infinite-scroller"
version = "0.7.3"
commit = "8dbd1980cdd54930abdd9d251263f364c9aa6f0b"
source = "url+https://github.com/roblox/infinite-scroller"
dependencies = [
"Cryo roblox/cryo 1.0.0 url+https://github.com/roblox/cryo",
"FitFrame roblox/roact-fit-components 1.2.5 url+https://github.com/roblox/roact-fit-components",
"Lumberyak roblox/lumberyak 0.1.1 url+https://github.com/roblox/lumberyak",
"Otter roblox/otter 0.1.3 url+https://github.com/roblox/otter",
"Roact roblox/roact 1.3.1 url+https://github.com/roblox/roact",
"t roblox/t 1.2.5 url+https://github.com/roblox/t",
]
@@ -0,0 +1,12 @@
--[[
Package link auto-generated by Rotriever
]]
local PackageIndex = script.Parent.Parent
local package = PackageIndex["roblox_t"]["t"]
if package.ClassName == "ModuleScript" then
return require(package)
end
return package