223 lines
9 KiB
TypeScript
223 lines
9 KiB
TypeScript
|
|
||
|
import React from 'react';
|
||
|
import { ContentPage } from '../../components/ContentPage';
|
||
|
import { ApiSection } from '../../types';
|
||
|
|
||
|
const composeApi: ApiSection[] = [
|
||
|
{
|
||
|
title: 'Chemical.Compose',
|
||
|
description: 'The `Compose` API is used for declaratively creating and managing Roblox UI Instances. It allows you to bind UI properties to reactive state (Values or Computeds) and handle UI events.',
|
||
|
entries: [
|
||
|
{
|
||
|
signature: 'Chemical.Compose(target: string | Instance): (properties: GuiProperties) => Instance & CompositionHandle',
|
||
|
description: 'Starts a UI composition. It takes a target, which can be a string (ClassName of the Instance to create, e.g., "TextLabel") or an existing Instance to adopt and manage.',
|
||
|
parameters: [
|
||
|
{ name: 'target', type: 'string | Instance', description: 'The ClassName of the UI element to create, or an existing Instance to manage.' },
|
||
|
],
|
||
|
returns: { type: '(properties: GuiProperties) => Instance & CompositionHandle', description: 'A function that takes a properties table and returns the created/managed Instance. The instance is augmented with a `.Destroy()` method specific to the composition.' },
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Compose = Chemical.Compose
|
||
|
-- Assuming playerGui is defined, e.g., local playerGui = game.Players.LocalPlayer:WaitForChild("PlayerGui")
|
||
|
|
||
|
local MyScreen = Compose("ScreenGui")({ Parent = playerGui })
|
||
|
|
||
|
-- Create a new TextLabel
|
||
|
local MyLabelFactory = Compose("TextLabel")
|
||
|
|
||
|
local labelInstance = MyLabelFactory({
|
||
|
Name = "ScoreLabel",
|
||
|
Text = "Score: 0",
|
||
|
Parent = MyScreen -- Parent to the ScreenGui
|
||
|
})
|
||
|
|
||
|
-- Adopt an existing Frame
|
||
|
local existingFrame = Instance.new("Frame")
|
||
|
existingFrame.Parent = MyScreen -- Parent to the ScreenGui
|
||
|
local MyFrameManager = Compose(existingFrame)
|
||
|
MyFrameManager({
|
||
|
BackgroundColor3 = Color3.new(1, 0, 0)
|
||
|
})
|
||
|
`,
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
{
|
||
|
title: 'Properties Table (GuiProperties)',
|
||
|
description: 'The properties table passed to the composer function defines the attributes and event handlers for the UI Instance.',
|
||
|
entries: [
|
||
|
{
|
||
|
signature: 'Standard Properties (e.g., Name, Size, Position, Text, BackgroundColor3)',
|
||
|
description: 'You can set any standard Roblox Instance property. If the value provided is a Chemical `Value` or `Computed`, the Instance property will reactively update whenever the stateful object changes.',
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Value = Chemical.Value
|
||
|
local Compose = Chemical.Compose
|
||
|
local Children = Chemical.Symbols.Children -- Alias for Children key
|
||
|
-- Assuming playerGui is defined
|
||
|
|
||
|
local labelText = Value("Loading...")
|
||
|
local labelColor = Value(Color3.new(1,1,1))
|
||
|
|
||
|
local MyScreen = Compose("ScreenGui")({
|
||
|
Parent = playerGui,
|
||
|
[Children] = {
|
||
|
Compose("TextLabel")({
|
||
|
Text = labelText, -- Reactive binding
|
||
|
TextColor3 = labelColor, -- Reactive binding
|
||
|
Size = UDim2.new(0, 200, 0, 50)
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
|
||
|
|
||
|
labelText:set("Ready!") -- The TextLabel's Text property updates
|
||
|
labelColor:set(Color3.new(0,1,0)) -- The TextLabel's TextColor3 updates
|
||
|
`,
|
||
|
},
|
||
|
{
|
||
|
signature: 'Parent: Instance',
|
||
|
description: 'Sets the `Parent` of the created/managed Instance.',
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Compose = Chemical.Compose
|
||
|
local Children = Chemical.Symbols.Children -- Alias for Children key
|
||
|
-- Assuming playerGui is defined
|
||
|
|
||
|
local MyScreen = Compose("ScreenGui")({ Parent = playerGui })
|
||
|
local MyFrame = Compose("Frame")({ Parent = MyScreen })
|
||
|
|
||
|
Compose("TextLabel")({
|
||
|
Parent = MyFrame, -- Sets the parent to MyFrame
|
||
|
[Children] = {} -- Empty children if none, but key must be present if Children symbol is used.
|
||
|
})
|
||
|
`,
|
||
|
},
|
||
|
{
|
||
|
signature: '[Chemical.Symbols.Children]: { Instance | CompositionHandle }',
|
||
|
description: 'An array of child Instances or other Compositions to parent under this element. The key for this property MUST be the `Chemical.Symbols.Children` symbol (often aliased to a local variable `Children` and used as `[Children]`).',
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Compose = Chemical.Compose
|
||
|
local Children = Chemical.Symbols.Children -- Alias the symbol
|
||
|
-- Assuming playerGui exists
|
||
|
|
||
|
Compose("ScreenGui")({
|
||
|
Parent = playerGui,
|
||
|
[Children] = { -- Use the aliased Children symbol
|
||
|
Compose("Frame")({
|
||
|
Name = "Container",
|
||
|
Size = UDim2.fromScale(0.8, 0.8),
|
||
|
Position = UDim2.fromScale(0.1, 0.1),
|
||
|
[Children] = { -- Use the aliased Children symbol
|
||
|
Compose("TextButton")({ Name = "Button1", Text = "B1", Size = UDim2.fromScale(0.2, 0.1) }),
|
||
|
Compose("ImageLabel")({ Name = "Icon", Size = UDim2.fromScale(0.2,0.2), Position = UDim2.fromOffset(100,0) })
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
`,
|
||
|
},
|
||
|
{
|
||
|
signature: '[Chemical.OnEvent(eventName: string)]: (Instance, ...args) -> ()',
|
||
|
description: 'Attaches an event handler to a Roblox Instance event (e.g., "Activated", "MouseButton1Click", "MouseEnter"). The `eventName` should match the Roblox event name.',
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Compose = Chemical.Compose
|
||
|
local OnEvent = Chemical.OnEvent
|
||
|
local Children = Chemical.Symbols.Children -- Alias for Children key
|
||
|
-- Assuming playerGui is defined
|
||
|
|
||
|
local MyScreen = Compose("ScreenGui")({
|
||
|
Parent = playerGui,
|
||
|
[Children] = {
|
||
|
Compose("TextButton")({
|
||
|
Text = "Click Me",
|
||
|
[OnEvent("Activated")] = function(buttonInstance)
|
||
|
print(buttonInstance.Name .. " was activated!")
|
||
|
end,
|
||
|
[OnEvent("MouseEnter")] = function(buttonInstance)
|
||
|
buttonInstance.BackgroundColor3 = Color3.new(0.5, 0.5, 0.5)
|
||
|
end,
|
||
|
[OnEvent("MouseLeave")] = function(buttonInstance)
|
||
|
buttonInstance.BackgroundColor3 = Color3.new(0.2, 0.2, 0.2)
|
||
|
end
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
`,
|
||
|
},
|
||
|
{
|
||
|
signature: '[Chemical.OnChange(propertyName: string)]: ((newValue: any) -> ()) | Value<any>',
|
||
|
description: 'Listens for changes to a specific property of the Instance (using `Instance:GetPropertyChangedSignal(propertyName)`). The provided callback function will be executed, or if a Chemical `Value` is provided, its `:set()` method will be called with the new property value.',
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Value = Chemical.Value
|
||
|
local Compose = Chemical.Compose
|
||
|
local OnChange = Chemical.OnChange
|
||
|
local Children = Chemical.Symbols.Children -- Alias for Children key
|
||
|
local Effect = Chemical.Effect
|
||
|
-- Assuming playerGui is defined
|
||
|
|
||
|
local currentText = Value("")
|
||
|
local MyScreen = Compose("ScreenGui")({
|
||
|
Parent = playerGui,
|
||
|
[Children] = {
|
||
|
Compose("TextBox")({
|
||
|
Name = "MyInput",
|
||
|
PlaceholderText = "Enter text here...",
|
||
|
[OnChange("Text")] = function(newText) -- Callback function
|
||
|
print("TextBox text changed to:", newText)
|
||
|
end,
|
||
|
-- OR bind to a Value:
|
||
|
-- [OnChange("Text")] = currentText
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
|
||
|
-- If bound to currentText:
|
||
|
-- Effect(function() print("currentText Value is:", currentText:get()) end)
|
||
|
`,
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
{
|
||
|
title: 'Composition Handle',
|
||
|
description: 'The function returned by `Chemical.Compose(target)` returns the Instance itself, but this instance is also augmented with a specific `Destroy` method related to the composition.',
|
||
|
entries: [
|
||
|
{
|
||
|
signature: 'compositionHandle:Destroy()',
|
||
|
description: 'Destroys the UI composition created by `Chemical.Compose`. This includes: destroying the root Instance, disconnecting all event listeners and property change signals established by the composition, and destroying any Effects that were created to bind reactive properties. If the composition managed child compositions, their `Destroy` methods are also called.',
|
||
|
example: `
|
||
|
local Chemical = require(game.ReplicatedStorage.Chemical)
|
||
|
local Compose = Chemical.Compose
|
||
|
local Children = Chemical.Symbols.Children -- Alias for Children key
|
||
|
-- Assuming playerGui is defined
|
||
|
|
||
|
local MyScreen = Compose("ScreenGui")({
|
||
|
Parent = playerGui,
|
||
|
[Children] = {
|
||
|
Compose("TextLabel")({
|
||
|
Text = "Hello"
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
local labelComposition = MyScreen.Children[1] -- Accessing the composed TextLabel
|
||
|
|
||
|
-- ... later
|
||
|
-- To destroy the label specifically (if it were assigned to a variable directly from Compose)
|
||
|
-- labelComposition:Destroy()
|
||
|
|
||
|
-- To destroy the entire screen and all its composed children:
|
||
|
MyScreen:Destroy() -- The ScreenGui instance and its TextLabel are destroyed, and all Chemical bindings are cleaned up.
|
||
|
`,
|
||
|
notes: "This is different from `instance:Destroy()`. While `instance:Destroy()` destroys the Roblox Instance, `compositionHandle:Destroy()` also cleans up Chemical-specific resources like effects and event connections associated with that composition."
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
];
|
||
|
|
||
|
export const ComposePage: React.FC = () => {
|
||
|
return <ContentPage title="Chemical.Compose" sections={composeApi} />;
|
||
|
};
|