Merge pull request #97 from TemujinCalidius/fix/build-page-review

fix(builder): chooser cards were unclickable and misrouted picks
This commit is contained in:
Samuel Lison
2026-07-30 17:59:50 +10:00
committed by GitHub
5 changed files with 55 additions and 23 deletions
+14 -2
View File
@@ -267,8 +267,11 @@ function BuildAdmin.applyType(instances: { Instance }, schema: any, all: { any }
end
-- The honest inverse of applyType: remove every known component tag, its attributes, and the
-- engine's `_`-prefixed stamps. Returns { cleared }.
function BuildAdmin.clear(instances: { Instance }, all: { any }): any
-- engine's `_`-prefixed stamps. `extraTags` removes specific additional tags by name — the page
-- passes the unknown tags it just displayed, so its "Clear" button actually clears what the user
-- was shown. Tags are never removed speculatively: an unlisted tag may belong to another plugin.
-- Returns { cleared }.
function BuildAdmin.clear(instances: { Instance }, all: { any }, extraTags: { string }?): any
local cleared = 0
for _, instance in instances do
if not alive(instance) then
@@ -282,6 +285,15 @@ function BuildAdmin.clear(instances: { Instance }, all: { any }): any
touched = true
end
end
for _, tag in (extraTags or {}) :: { string } do
if CollectionService:HasTag(instance, tag) then
CollectionService:RemoveTag(instance, tag)
touched = true
end
end
if instance:GetAttribute(BOUND_ATTR) ~= nil then
touched = true
end
stripEngineStamps(instance)
if touched then
cleared += 1
+12 -15
View File
@@ -49,8 +49,11 @@ local function countAdvanced(specs: { any }): number
end
-- One clickable "what is this?" card. Ineligible components render dim and inert, with the reason.
local function chooserCard(schema: any, display: any, eligible: boolean, reason: string?, onPick): Frame
local panel = Theme.panel()
-- The CARD ITSELF is the button when it's pickable: a full-size button parented INTO a panel would
-- be laid out by the panel's UIListLayout as another row (no opt-out; ZIndex doesn't affect
-- layout), leaving the card body dead and the button spilling onto the next card.
local function chooserCard(schema: any, display: any, eligible: boolean, reason: string?, onPick): GuiObject
local panel: any = if eligible then Theme.panelButton() else Theme.panel()
local title = Theme.label({
Size = UDim2.new(1, 0, 0, 20),
Text = display.title,
@@ -74,15 +77,7 @@ local function chooserCard(schema: any, display: any, eligible: boolean, reason:
panel
if eligible then
-- A transparent button over the whole card keeps the panel's styling but makes it clickable.
local hit = Theme.make("TextButton", {
Size = UDim2.fromScale(1, 1),
BackgroundTransparency = 1,
Text = "",
ZIndex = 3,
}) :: TextButton
hit.Parent = panel
hit.MouseButton1Click:Connect(function()
(panel :: TextButton).MouseButton1Click:Connect(function()
onPick(schema)
end)
Theme.hover(panel, Theme.COLOR.PANEL, Theme.COLOR.PANEL_HOVER)
@@ -160,12 +155,13 @@ function BuildAdminUi.mount(container: Frame, BuildAdmin: any, ContentAdmin: any
end
end
local function clearType(instances: { Instance }, all: { any })
local res = actions.clear(instances, all)
local function clearType(instances: { Instance }, all: { any }, extraTags: { string }?)
local res = actions.clear(instances, all, extraTags)
chooserOpen = false
refresh()
if typeof(res) == "table" then
say(`✓ cleared {res.cleared or 0} object(s)`)
local n = res.cleared or 0
say(if n > 0 then `✓ cleared {n} object(s)` else "nothing to clear on that object")
end
end
@@ -432,7 +428,8 @@ function BuildAdminUi.mount(container: Frame, BuildAdmin: any, ContentAdmin: any
})
clearBtn.Parent = scroll
clearBtn.MouseButton1Click:Connect(function()
clearType({ instance }, all)
-- Pass the unknown tags we just listed, so Clear removes exactly what was shown.
clearType({ instance }, all, id.unknownTags)
end)
end
+6 -4
View File
@@ -140,18 +140,20 @@ function FieldRow.build(opts: any): Frame
end
if hasHelp then
Theme.label({
-- `row` owns a UIListLayout, which overwrites child Position — so the indent under the
-- label column has to come from padding, not Position.
local help = Theme.label({
Size = UDim2.fromScale(1, 0),
AutomaticSize = Enum.AutomaticSize.Y,
Position = UDim2.fromOffset(22, 0),
Text = spec.help,
TextColor3 = Theme.COLOR.DIM,
TextWrapped = true,
TextSize = 11,
TextTruncate = Enum.TextTruncate.None,
LayoutOrder = 2,
}).Parent =
row
})
Theme.pad(22, 0, 0, 2).Parent = help
help.Parent = row
end
return row
+21
View File
@@ -171,6 +171,27 @@ function Theme.panel(): Frame
}) :: Frame
end
-- A CLICKABLE panel: identical styling to Theme.panel, but the card itself is the button.
-- Use this instead of parenting a full-size button "overlay" into a panel — the panel's own
-- UIListLayout lays out EVERY GuiObject child (there is no opt-out, and ZIndex doesn't change
-- layout), so such an "overlay" becomes another list row: the card body stops being clickable and
-- the oversized button spills onto whatever is rendered next.
function Theme.panelButton(): TextButton
return Theme.make("TextButton", {
BackgroundColor3 = Theme.COLOR.PANEL,
BorderSizePixel = 0,
Size = UDim2.fromScale(1, 0),
AutomaticSize = Enum.AutomaticSize.Y,
Text = "",
AutoButtonColor = false, -- Theme.hover owns the highlight, matching the other cards
}, {
Theme.corner(8),
Theme.stroke(),
Theme.pad(8, 8, 6, 8),
Theme.make("UIListLayout", { Padding = UDim.new(0, 2), SortOrder = Enum.SortOrder.LayoutOrder }),
}) :: TextButton
end
-- A small count/status pill (rail badges, entry badges).
function Theme.badge(text: string, textColor: Color3?): TextLabel
return Theme.make("TextLabel", {
+2 -2
View File
@@ -123,9 +123,9 @@ local buildActions = {
return BuildAdmin.applyType(instances, schema, all)
end)
end,
clear = function(instances: { Instance }, all: { any }): any
clear = function(instances: { Instance }, all: { any }, extraTags: { string }?): any
return record("Build: clear component", function()
return BuildAdmin.clear(instances, all)
return BuildAdmin.clear(instances, all, extraTags)
end)
end,
setField = function(instance: Instance, spec: any, raw: any): any