mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
Use type functions for vide.create
This commit is contained in:
parent
c16022586e
commit
d7d2f5167e
2 changed files with 87 additions and 73 deletions
128
src/create.luau
128
src/create.luau
|
|
@ -5,11 +5,9 @@ local defaults = require "./defaults"
|
||||||
local apply = require "./apply"
|
local apply = require "./apply"
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
|
|
||||||
local ctor_cache = {} :: { [string]: () -> Instance }
|
local ctor_cache = {} :: { [string]: (AnyProps) -> Instance }
|
||||||
|
local function lazy_init(_, class: string)
|
||||||
setmetatable(ctor_cache :: any, {
|
local function ctor(properties: AnyProps): Instance
|
||||||
__index = function(self, class)
|
|
||||||
local function ctor(properties: Props): Instance
|
|
||||||
local ok, instance: Instance = pcall(Instance.new, class :: any)
|
local ok, instance: Instance = pcall(Instance.new, class :: any)
|
||||||
if not ok then error(`invalid class name { class }`, 0) end
|
if not ok then error(`invalid class name { class }`, 0) end
|
||||||
|
|
||||||
|
|
@ -25,70 +23,86 @@ setmetatable(ctor_cache :: any, {
|
||||||
return apply(instance, properties)
|
return apply(instance, properties)
|
||||||
end
|
end
|
||||||
|
|
||||||
self[class] = ctor
|
ctor_cache[class] = ctor
|
||||||
return ctor
|
return ctor
|
||||||
end
|
end
|
||||||
})
|
setmetatable(ctor_cache, { __index = lazy_init })
|
||||||
|
|
||||||
local function create_instance(class: string)
|
-- todo: remove support for different overloads
|
||||||
return ctor_cache[class]
|
local function create(class_or_instance: string|Instance, properties: AnyProps?): ((AnyProps) -> Instance) | Instance
|
||||||
|
if type(class_or_instance) ~= "string" and typeof(class_or_instance) ~= "Instance" then
|
||||||
|
error("bad argument #1, expected string or instance, got " .. typeof(class_or_instance), 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clone_instance(instance: Instance)
|
local ctor = if type(class_or_instance) == "string"
|
||||||
return function(properties: Props): Instance
|
then ctor_cache[class_or_instance]
|
||||||
local clone = instance:Clone()
|
else function(properties)
|
||||||
|
local clone = class_or_instance:Clone()
|
||||||
if not clone then error "attempt to clone a non-archivable instance" end
|
if not clone then error "attempt to clone a non-archivable instance" end
|
||||||
return apply(clone, properties)
|
return apply(clone, properties)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return if properties
|
||||||
|
then ctor(properties)
|
||||||
|
else ctor
|
||||||
end
|
end
|
||||||
|
|
||||||
local function create(class_or_instance: string | Instance, props: Props?): ((Props) -> Instance) | Instance
|
type Instances = {
|
||||||
local result: (Props) -> Instance
|
Folder: Folder,
|
||||||
if type(class_or_instance) == "string" then
|
BillboardGui: BillboardGui,
|
||||||
result = create_instance(class_or_instance)
|
CanvasGroup: CanvasGroup,
|
||||||
elseif typeof(class_or_instance) == "Instance" then
|
Frame: Frame,
|
||||||
result = clone_instance(class_or_instance)
|
ImageButton: ImageButton,
|
||||||
else
|
ImageLabel: ImageLabel,
|
||||||
error("bad argument #1, expected string or instance, got " .. typeof(class_or_instance), 0)
|
ScreenGui: ScreenGui,
|
||||||
return nil :: never
|
ScrollingFrame: ScrollingFrame,
|
||||||
|
SurfaceGui: SurfaceGui,
|
||||||
|
TextBox: TextBox,
|
||||||
|
TextButton: TextButton,
|
||||||
|
TextLabel: TextLabel,
|
||||||
|
UIAspectRatioConstraint: UIAspectRatioConstraint,
|
||||||
|
UICorner: UICorner,
|
||||||
|
UIGradient: UIGradient,
|
||||||
|
UIGridLayout: UIGridLayout,
|
||||||
|
UIListLayout: UIListLayout,
|
||||||
|
}
|
||||||
|
|
||||||
|
type function Properties(instance: type?)
|
||||||
|
local properties = types.newtable()
|
||||||
|
|
||||||
|
while instance do
|
||||||
|
for i, v in instance:properties() do
|
||||||
|
local connector = v.read and v.read.tag == "table" and v.read:readproperty(types.singleton("Connect"))
|
||||||
|
if connector then
|
||||||
|
if not connector then continue end
|
||||||
|
local params = connector:parameters().head
|
||||||
|
if not params then continue end
|
||||||
|
local listener = params[2]
|
||||||
|
if not listener then continue end
|
||||||
|
properties:setproperty(i, types.optional(listener))
|
||||||
|
elseif v.write then
|
||||||
|
properties:setproperty(i, types.optional(types.unionof(
|
||||||
|
v.write,
|
||||||
|
types.newfunction({}, { head = { v.write } })
|
||||||
|
)))
|
||||||
end
|
end
|
||||||
if props then
|
|
||||||
return result(props)
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
type Props = { [any]: any }
|
instance = instance:readparent()
|
||||||
|
end
|
||||||
|
|
||||||
type Create<Name, Instance> = ((Name, Props) -> Instance) & ((Name) -> (Props) -> Instance)
|
properties:setindexer(types.number, types.any)
|
||||||
|
|
||||||
return (create :: any) ::
|
return properties
|
||||||
& ( <T>(T & Instance) -> (Props) -> T )
|
end
|
||||||
& ( <T>(T & Instance, Props) -> T )
|
|
||||||
& Create<"Folder", Folder>
|
type AnyProps = { [any]: any }
|
||||||
& Create<"BillboardGui", BillboardGui>
|
type Create = (
|
||||||
& Create<"CanvasGroup", CanvasGroup>
|
(Instance) -> (AnyProps) -> Instance
|
||||||
& Create<"Frame", Frame>
|
) & (
|
||||||
& Create<"ImageButton", ImageButton>
|
(string, AnyProps) -> Instance
|
||||||
& Create<"ImageLabel", ImageLabel>
|
) & (
|
||||||
& Create<"ScreenGui", ScreenGui>
|
<Name>(Name|keyof<Instances>) -> (Properties<index<Instances, Name>>) -> index<Instances, Name>
|
||||||
& Create<"ScrollingFrame", ScrollingFrame>
|
)
|
||||||
& Create<"SurfaceGui", SurfaceGui>
|
|
||||||
& Create<"TextBox", TextBox>
|
return (create :: any) :: Create
|
||||||
& Create<"TextButton", TextButton>
|
|
||||||
& Create<"TextLabel", TextLabel>
|
|
||||||
& Create<"UIAspectRatioConstraint", UIAspectRatioConstraint>
|
|
||||||
& Create<"UICorner", UICorner>
|
|
||||||
& Create<"UIGradient", UIGradient>
|
|
||||||
& Create<"UIGridLayout", UIGridLayout>
|
|
||||||
& Create<"UIListLayout", UIListLayout>
|
|
||||||
& Create<"UIPadding", UIPadding>
|
|
||||||
& Create<"UIPageLayout", UIPageLayout>
|
|
||||||
& Create<"UIScale", UIScale>
|
|
||||||
& Create<"UISizeConstraint", UISizeConstraint>
|
|
||||||
& Create<"UIStroke", UIStroke>
|
|
||||||
& Create<"UITableLayout", UITableLayout>
|
|
||||||
& Create<"UITextSizeConstraint", UITextSizeConstraint>
|
|
||||||
& Create<"VideoFrame", VideoFrame>
|
|
||||||
& Create<"ViewportFrame", ViewportFrame>
|
|
||||||
& Create<string, Instance>
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ end
|
||||||
|
|
||||||
local vide = require "../src/"
|
local vide = require "../src/"
|
||||||
local count = vide.source(0)
|
local count = vide.source(0)
|
||||||
create("TextButton") {
|
create("TextButton") { -- todo: why is `:: "TextButton"` not necessary?
|
||||||
BackgroundTransparency = 1,
|
BackgroundTransparency = 1,
|
||||||
AnchorPoint = "bad value", -- should error
|
AnchorPoint = "bad value", -- should error
|
||||||
InvalidProperty = true, -- should error
|
InvalidProperty = true, -- should error
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue