This commit is contained in:
Andrea Fletcher 2026-08-06 04:02:36 -07:00 committed by GitHub
commit 2d1e5983c6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 276 additions and 0 deletions

View file

@ -66,6 +66,7 @@ local Instance = {} :: any do
children: { Data },
changed: { [string]: RBXScriptSignal },
properties: { [string]: unknown },
tags: { [string]: true },
destroying: RBXScriptSignal,
class: string,
type: "Instance"
@ -158,6 +159,7 @@ local Instance = {} :: any do
children = {},
changed = {},
properties = {},
tags = {},
class = class,
destroying = Signal.new() :: any,
type = "Instance" :: "Instance"
@ -211,6 +213,29 @@ local Instance = {} :: any do
return data.changed[property]
end
function methods.AddTag(userdata: userdata, tag: string)
if type(tag) ~= "string" then error("tag must be a string", 2) end
get_data(userdata).tags[tag] = true
end
function methods.RemoveTag(userdata: userdata, tag: string)
if type(tag) ~= "string" then error("tag must be a string", 2) end
get_data(userdata).tags[tag] = nil
end
function methods.HasTag(userdata: userdata, tag: string): boolean
if type(tag) ~= "string" then error("tag must be a string", 2) end
return get_data(userdata).tags[tag] == true
end
function methods.GetTags(userdata: userdata): { string }
local out = {}
for name in get_data(userdata).tags do
table.insert(out, name)
end
return out
end
function methods.Destroy(userdata: userdata)
local data = get_data(userdata);
Signal.fire(data.destroying)

View file

@ -24,6 +24,7 @@ local vide = require "../../vide"
local spring = vide.spring
local action = vide.action
local changed = vide.changed
local tag = vide.tag
local apply = vide.apply
local step = vide.step
local graph = require "../../vide/src/graph"
@ -2340,6 +2341,122 @@ TEST("changed()", wrap_root(function()
end
end))
TEST("tag()", wrap_root(function()
do CASE "apply single tag"
local frame = create "Frame" {
tag("MyTag")
}
CHECK(frame:HasTag("MyTag"))
CHECK(#frame:GetTags() == 1)
end
do CASE "apply multiple tags"
local frame = create "Frame" {
tag({ "A", "B", "C" })
}
CHECK(frame:HasTag("A"))
CHECK(frame:HasTag("B"))
CHECK(frame:HasTag("C"))
CHECK(#frame:GetTags() == 3)
end
do CASE "compose multiple tag() actions"
local frame = create "Frame" {
tag("A"),
tag("B")
}
CHECK(frame:HasTag("A"))
CHECK(frame:HasTag("B"))
end
do CASE "remove tags on scope destroy"
local _, frame, destroy = root(function(destroy)
return create "Frame" {
tag({ "A", "B" })
}, destroy
end)
CHECK(frame:HasTag("A"))
CHECK(frame:HasTag("B"))
destroy()
CHECK(not frame:HasTag("A"))
CHECK(not frame:HasTag("B"))
end
do CASE "reactive single tag"
local current = source("A")
local frame = create "Frame" {
tag(current)
}
CHECK(frame:HasTag("A"))
CHECK(#frame:GetTags() == 1)
current("B")
CHECK(not frame:HasTag("A"))
CHECK(frame:HasTag("B"))
CHECK(#frame:GetTags() == 1)
end
do CASE "reactive multiple tags"
local current = source({ "A", "B" })
local frame = create "Frame" {
tag(current)
}
CHECK(frame:HasTag("A"))
CHECK(frame:HasTag("B"))
CHECK(#frame:GetTags() == 2)
-- preserve "A", remove "B", add "C"
current({ "A", "C" })
CHECK(frame:HasTag("A"))
CHECK(not frame:HasTag("B"))
CHECK(frame:HasTag("C"))
CHECK(#frame:GetTags() == 2)
end
do CASE "reactive tag removed on scope destroy"
local _, frame, destroy = root(function(destroy)
local current = source("A")
return create "Frame" {
tag(current)
}, destroy
end)
CHECK(frame:HasTag("A"))
destroy()
CHECK(not frame:HasTag("A"))
CHECK(#frame:GetTags() == 0)
end
do CASE "reactive tag derived from source"
local name = source("hello")
local frame = create "Frame" {
tag(function() return "prefix-" .. name() end)
}
CHECK(frame:HasTag("prefix-hello"))
name("world")
CHECK(not frame:HasTag("prefix-hello"))
CHECK(frame:HasTag("prefix-world"))
end
end))
TEST("batch()", wrap_root(function()
do CASE "evaluation deferred"
local a = source(0)