mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
This commit is contained in:
parent
8e31946dda
commit
13965868ce
13 changed files with 421 additions and 448 deletions
54
README.md
54
README.md
|
|
@ -1,54 +1,14 @@
|
||||||
# Notice
|
# Notice
|
||||||
|
|
||||||
The library is currently in a very early development stage, with breaking changes being made often, out of date documentation and no versioning. Not recommended for use.
|
The library is currently in a very early development stage, with breaking
|
||||||
|
changes being made often, out of date documentation and no versioning. Not
|
||||||
<br>
|
recommended for use.
|
||||||
|
|
||||||
# Vide
|
# Vide
|
||||||
|
|
||||||
Vide is a declarative, reactive Luau library for building user interfaces on Roblox.
|
Vide is a declarative, reactive Luau library for building user interfaces on
|
||||||
|
Roblox.
|
||||||
|
|
||||||
## API Reference
|
- ### [API Reference](docs/api/index.md)
|
||||||
|
|
||||||
### [Reactivity: Core](docs/api/reactivity-core)
|
- ### [Crash Course](docs/tut/crash-course/1-introduction.md)
|
||||||
|
|
||||||
- [wrap()](docs/api/reactivity-core#wrap)
|
|
||||||
- [derive()](docs/api/reactivity-core#derive)
|
|
||||||
- [foreach()](docs/api/reactivity-core#wrap)
|
|
||||||
- [match()](docs/api/reactivity-core#match)
|
|
||||||
- [watch()](docs/api/reactivity-core#watch)
|
|
||||||
|
|
||||||
### [Reactivity: Utility](docs/api/reactivity-utility)
|
|
||||||
|
|
||||||
- [isState()](docs/api/reactivity-utility#isState)
|
|
||||||
- [unwrap()](docs/api/reactivity-utility#unwrap)
|
|
||||||
- [readonly()](docs/api/reactivity-utility#readonly)
|
|
||||||
- [mutate()](docs/api/reactivity-utility#mutate)
|
|
||||||
|
|
||||||
### [Element Creation](docs/api/creation)
|
|
||||||
|
|
||||||
- [create()](docs/api/creation#create)
|
|
||||||
- [apply()](docs/api/creation#apply)
|
|
||||||
- [Layout](docs/api/creation#Layout)
|
|
||||||
- [Children](docs/api/creation#Children)
|
|
||||||
- [Event](docs/api/creation#Event)
|
|
||||||
- [Changed](docs/api/creation#Changed)
|
|
||||||
- [Bind](docs/api/creation#Bind)
|
|
||||||
- [Created](docs/api/creation#Created)
|
|
||||||
|
|
||||||
### [Animation](docs/api/animation)
|
|
||||||
|
|
||||||
- [spring()](docs/api/animation#spring)
|
|
||||||
|
|
||||||
### [Types](docs/api/types)
|
|
||||||
|
|
||||||
- [State<T>](docs/api/types#State)
|
|
||||||
- [Prop<T>](docs/api/types#Prop)
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## Tutorials
|
|
||||||
|
|
||||||
### [Crash Course](docs/tutorials/crash-course)
|
|
||||||
|
|
||||||
### [Reactive Graph](docs/tutorials/reactive-graph)
|
|
||||||
|
|
|
||||||
22
docs/api/index.md
Normal file
22
docs/api/index.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# API Reference
|
||||||
|
|
||||||
|
### [Reactivity: Core](../api/reactivity-core.md)
|
||||||
|
|
||||||
|
- [source()](../api/reactivity-core.md#source)
|
||||||
|
- [derive()](../api/reactivity-core.md#derive)
|
||||||
|
- [map()](../api/reactivity-core.md#map)
|
||||||
|
- [watch()](../api/reactivity-core.md#watch)
|
||||||
|
|
||||||
|
### [Reactivity: Utility](../api/reactivity-utility.md)
|
||||||
|
|
||||||
|
- [cleanup()](../api/reactivity-utility.md#cleanup)
|
||||||
|
|
||||||
|
### [Element Creation](../api/creation.md)
|
||||||
|
|
||||||
|
- [create()](../api/creation.md#create)
|
||||||
|
|
||||||
|
### [Animation](../api/animation.md)
|
||||||
|
|
||||||
|
- [spring()](../api/animation.md#spring)
|
||||||
|
|
||||||
|
### [Strict Mode](../api/strict.md)
|
||||||
|
|
@ -1,351 +0,0 @@
|
||||||
# Vide Crash Course
|
|
||||||
|
|
||||||
This is a brief tutorial designed to give you a quick run through the usage of
|
|
||||||
Vide.
|
|
||||||
|
|
||||||
Vide is largely inspired by Solid and Fusion.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Why Vide?
|
|
||||||
|
|
||||||
Creating UI is a slow and tedious process. The purpose of Vide is to make UI
|
|
||||||
declarative and concise, making it faster to create and more importantly easier
|
|
||||||
to maintain. Vide achieves this using a reactive style of programming which
|
|
||||||
allows you to focus on the flow of data through your application without
|
|
||||||
worrying about manually updating UI instances.
|
|
||||||
|
|
||||||
Some of the main focuses behind Vide's design choices:
|
|
||||||
|
|
||||||
- Concise syntax to reduce verbosity as much as possible.
|
|
||||||
- Reducing the amount of imports needed for usage by using Luau's syntax and
|
|
||||||
semantics.
|
|
||||||
- Being completely typecheckable.
|
|
||||||
- Flexibility, particularly with integrating other libraries.
|
|
||||||
|
|
||||||
## Creating UI Instances
|
|
||||||
|
|
||||||
Instances are created using [`create()`](../api/creation#create).
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local vide = require(vide)
|
|
||||||
local create = vide.create
|
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local frame = create "Frame" {
|
|
||||||
Name = "Background",
|
|
||||||
Position = UDim2.fromScale(0.5, 0.5)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
`create()` returns a constructor for a given class which then takes a table of
|
|
||||||
properties to assign when creating a new instance for that class.
|
|
||||||
|
|
||||||
String keys are assumed to be properties, integer keys are assumed to be
|
|
||||||
children.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
create "ScreenGui" {
|
|
||||||
Parent = game.StarterGui,
|
|
||||||
|
|
||||||
create("Frame") {
|
|
||||||
AnchorPoint = Vector2.new(0.5, 0.5),
|
|
||||||
Position = UDim2.fromScale(0.5, 0.5),
|
|
||||||
Size = UDim2.fromScale(0.4, 0.7),
|
|
||||||
|
|
||||||
create("TextLabel") {
|
|
||||||
Text = "hi"
|
|
||||||
},
|
|
||||||
|
|
||||||
create("TextLabel") {
|
|
||||||
Text = "bye"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To connect to an event, just set the event property name to a function.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
create "TextButton" {
|
|
||||||
Activated = function()
|
|
||||||
print "clicked!"
|
|
||||||
end
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
All event arguments are passed into the function.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## State
|
|
||||||
|
|
||||||
State in Vide are special objects that store data.
|
|
||||||
|
|
||||||
A state object in Vide can be created using
|
|
||||||
[`source()`](../api/reactivity-core#source).
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local source = vide.source
|
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local visible = source(false)
|
|
||||||
|
|
||||||
local image = create("ImageLabel") {
|
|
||||||
Visible = visible -- bind property to state
|
|
||||||
}
|
|
||||||
|
|
||||||
visible(false) -- image label is hidden
|
|
||||||
|
|
||||||
visible(true) -- image label is shown
|
|
||||||
```
|
|
||||||
|
|
||||||
`source()` creates a new data source which can be set by calling it with the new
|
|
||||||
value to set.
|
|
||||||
|
|
||||||
Any time the value is set, anything depending on it will automatically be
|
|
||||||
updated using the new value.
|
|
||||||
|
|
||||||
Vide detects when you assign a state object as a property value. This is known
|
|
||||||
as *binding* and doing so will cause the property to *automatically* update
|
|
||||||
whenever that state object's value is changed.
|
|
||||||
|
|
||||||
You as the programmer do not have to worry about manually updating variables or
|
|
||||||
UI instances, you can just focus on defining how the data maps to UI and
|
|
||||||
everything will update when changes occur.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Derived State
|
|
||||||
|
|
||||||
You can create new state from other states. This is known as *deriving state*.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local count = source(0)
|
|
||||||
|
|
||||||
local function text()
|
|
||||||
return "count: " .. count()
|
|
||||||
end
|
|
||||||
|
|
||||||
create "TextLabel" {
|
|
||||||
Text = text
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To read from a state, you call without any arguments which returns its stored
|
|
||||||
value.
|
|
||||||
|
|
||||||
Assigning a non-event property a function will bind that property to that
|
|
||||||
function, anytime a state being read from inside that function is changed, the
|
|
||||||
function will be re-ran and the property value updated.
|
|
||||||
|
|
||||||
Sometimes when using expensive computations to derive state, you only want to
|
|
||||||
recalculate it when a source state has changed.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local derive = vide.derive
|
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local count = source(0)
|
|
||||||
|
|
||||||
local factorial = derive(function()
|
|
||||||
local n = 1
|
|
||||||
for i = 2, count() do
|
|
||||||
n *= i
|
|
||||||
end
|
|
||||||
return n
|
|
||||||
end)
|
|
||||||
```
|
|
||||||
|
|
||||||
`derive()` will cache and return the same value until a source state has
|
|
||||||
changed, where it will recompute and cache a new value.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
create "TextLabel" {
|
|
||||||
Text = function()
|
|
||||||
return "factorial: " .. factorial()
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
count(3) -- displays "factorial: 6"
|
|
||||||
count(4) -- displays "factorial: 24"
|
|
||||||
```
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Components
|
|
||||||
|
|
||||||
Components are custom-made reusable pieces of UI made from other pieces of UI.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local function Background(args)
|
|
||||||
return create("Frame") {
|
|
||||||
BackgroundColor3 = Color3.new(0, 0, 0),
|
|
||||||
Position = args.Position,
|
|
||||||
Size = args.Size
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local background = Background {
|
|
||||||
Position = UDim2.new(),
|
|
||||||
Size = UDim2.new()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Above is a simple example of a frame component with its background color set to
|
|
||||||
black.
|
|
||||||
|
|
||||||
A single parameter `args` is used to pass properties to the component.
|
|
||||||
|
|
||||||
Components allow you to *encapsulate* behavior. You can only modify the
|
|
||||||
component in ways that you allow in the component.
|
|
||||||
|
|
||||||
This also promotes code reusability. Anytime you want a black frame all you do
|
|
||||||
is call `Background {}` instead of creating a new frame and settings it color
|
|
||||||
each time.
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
## Stateful components
|
|
||||||
|
|
||||||
Often, you need components that maintain their own internal state, such as a
|
|
||||||
toggle-able button or a counter.
|
|
||||||
|
|
||||||
Below you can see how a simple counter component can be implemented.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local function Counter()
|
|
||||||
local count = source(0)
|
|
||||||
|
|
||||||
return create "TextButton" {
|
|
||||||
Text = function()
|
|
||||||
return "count: " .. count()
|
|
||||||
end
|
|
||||||
|
|
||||||
Activated = function()
|
|
||||||
count(count() + 1)
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
Each time you call `Counter {}`, it will create a new counter component which
|
|
||||||
each maintains their own count state.
|
|
||||||
|
|
||||||
Clicking on the UI element will automatically increment and display its count.
|
|
||||||
|
|
||||||
## Nested Properties and Typechecking
|
|
||||||
|
|
||||||
When a key is assigned a table, Vide does not attempt to assign it to a
|
|
||||||
property, instead, the table is iterated and processed just like the nesting
|
|
||||||
table.
|
|
||||||
|
|
||||||
Below is an example of how you can use this to pass groups of similar properties
|
|
||||||
together such as position and size, while also using typechecking.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
type Layout = {
|
|
||||||
Layout = {
|
|
||||||
Position: UDim2?,
|
|
||||||
Size: UDim2?,
|
|
||||||
AnchorPoint: Vector2?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local function Button(args: Layout & {
|
|
||||||
Text: string,
|
|
||||||
Callback: () -> ()
|
|
||||||
})
|
|
||||||
local count = source(0)
|
|
||||||
|
|
||||||
return create "TextButton" {
|
|
||||||
Text = args.Text
|
|
||||||
Activated = args.Callback,
|
|
||||||
Layout = args.Layout
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
Button {
|
|
||||||
Text = "Click me!",
|
|
||||||
|
|
||||||
Callback = function()
|
|
||||||
print "clicked me!"
|
|
||||||
end,
|
|
||||||
|
|
||||||
Layout = {
|
|
||||||
Position = UDim2.new(),
|
|
||||||
Size = UDim2.new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here the button component is assigned a position and size as if you passed those
|
|
||||||
properties directly.
|
|
||||||
|
|
||||||
The same can be done for properties such as children.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
type Children = {
|
|
||||||
Children = Array<Instance>
|
|
||||||
}
|
|
||||||
|
|
||||||
local function List(args: Children & Layout)
|
|
||||||
return create "Frame" {
|
|
||||||
Layout = args.Layout,
|
|
||||||
Children = args.Children,
|
|
||||||
|
|
||||||
create "UIListLayout" {}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
List {
|
|
||||||
Layout = {
|
|
||||||
Position = UDim2.new()
|
|
||||||
},
|
|
||||||
|
|
||||||
Children = {
|
|
||||||
create "TextLabel" { Text = "1" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Tables of data
|
|
||||||
|
|
||||||
Vide has functions for dealing with table states.
|
|
||||||
|
|
||||||
Below is an example using the above `List` class.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
type Item = {
|
|
||||||
Name: string,
|
|
||||||
Icon: number
|
|
||||||
}
|
|
||||||
|
|
||||||
local items = source({} :: Array<Item>)
|
|
||||||
|
|
||||||
List {
|
|
||||||
Children = map(items, function(item, i)
|
|
||||||
return create "ImageLabel" {
|
|
||||||
Image = function()
|
|
||||||
return "rbxassetid://" .. item().Icon
|
|
||||||
end,
|
|
||||||
|
|
||||||
LayoutOrder = i
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here we map each element in `items` to a value returned by a callback.
|
|
||||||
|
|
||||||
The callback is called only *once* per key. The first argument given to the
|
|
||||||
callback is a state that has the value of the table key's value.
|
|
||||||
|
|
||||||
Anytime the value of the corresponding table key changes, the state value
|
|
||||||
changes too. This saves us from having to recreate a UI element any time a
|
|
||||||
table index changes.
|
|
||||||
|
|
||||||
## WIP
|
|
||||||
27
docs/tut/crash-course/1-introduction.md
Normal file
27
docs/tut/crash-course/1-introduction.md
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# [Introduction](./index.md)
|
||||||
|
|
||||||
|
This is a brief tutorial designed to give you a quick run through the usage of
|
||||||
|
Vide.
|
||||||
|
|
||||||
|
Vide is largely inspired by other UI libraries such as Solid and Fusion.
|
||||||
|
|
||||||
|
## Why Vide?
|
||||||
|
|
||||||
|
Creating UI is a slow and tedious process. The purpose of Vide is to make UI
|
||||||
|
declarative and concise, making it faster to create and more importantly easier
|
||||||
|
to maintain. Vide achieves this using a reactive style of programming which
|
||||||
|
allows you to focus on the flow of data through your application without
|
||||||
|
worrying about manually updating UI instances.
|
||||||
|
|
||||||
|
Some of the main focuses behind Vide's design choices:
|
||||||
|
|
||||||
|
- Concise syntax to reduce verbosity as much as possible.
|
||||||
|
- Reducing the amount of imports needed for usage by using Luau's syntax and
|
||||||
|
semantics.
|
||||||
|
- Being completely typecheckable.
|
||||||
|
- Flexibility, particularly with integrating other libraries and allowing users
|
||||||
|
to use their own patterns.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [Element Creation →](./2-creation.md)
|
||||||
67
docs/tut/crash-course/2-creation.md
Normal file
67
docs/tut/crash-course/2-creation.md
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# [Creating UI Elements](./index.md)
|
||||||
|
|
||||||
|
Instances are created using [`create()`](../../api/creation.md#create).
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local vide = require(path_to_vide)
|
||||||
|
local create = vide.create
|
||||||
|
```
|
||||||
|
|
||||||
|
`create()` returns a constructor for a given class which then takes a table of
|
||||||
|
properties to assign when creating a new instance for that class.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local frame = create "Frame" {
|
||||||
|
Name = "Background",
|
||||||
|
Position = UDim2.fromScale(0.5, 0.5)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
String keys are assigned as properties and integer keys are assigned as child
|
||||||
|
instances.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
create "ScreenGui" {
|
||||||
|
Parent = game.StarterGui,
|
||||||
|
|
||||||
|
create "Frame" {
|
||||||
|
AnchorPoint = Vector2.new(0.5, 0.5),
|
||||||
|
Position = UDim2.fromScale(0.5, 0.5),
|
||||||
|
Size = UDim2.fromScale(0.4, 0.7),
|
||||||
|
|
||||||
|
create "TextLabel" {
|
||||||
|
Text = "hi"
|
||||||
|
},
|
||||||
|
|
||||||
|
create"TextLabel" {
|
||||||
|
Text = "bye"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To connect to an event, just set the event property name to a function.
|
||||||
|
|
||||||
|
All event arguments are passed into the function.
|
||||||
|
|
||||||
|
|
||||||
|
```lua
|
||||||
|
create "TextButton" {
|
||||||
|
Activated = function()
|
||||||
|
print "clicked!"
|
||||||
|
end
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
In short:
|
||||||
|
|
||||||
|
- String keys = properties
|
||||||
|
- Function values = events
|
||||||
|
- Non-function values = property values
|
||||||
|
- Numeric keys = children
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [← Introduction](./1-introduction.md) | [Components →](./3-components.md)
|
||||||
52
docs/tut/crash-course/3-components.md
Normal file
52
docs/tut/crash-course/3-components.md
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# [Components](./index.md)
|
||||||
|
|
||||||
|
Components are custom-made reusable pieces of UI made from other pieces of UI.
|
||||||
|
|
||||||
|
Using components you make your application more modular and better organized.
|
||||||
|
|
||||||
|
Components leverage functions to create self-contained UI that can even have
|
||||||
|
its own state and behavior.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local function Button(props: {
|
||||||
|
Position: UDim2,
|
||||||
|
Text: string,
|
||||||
|
Callback: () -> ()
|
||||||
|
})
|
||||||
|
return create "TextButton" {
|
||||||
|
BackgroundColor3 = Color3.fromRGB(50, 50, 50),
|
||||||
|
Size = UDim2.fromOffset(400, 250),
|
||||||
|
|
||||||
|
Position = props.Position,
|
||||||
|
Text = props.Text,
|
||||||
|
Callback = props.Callback
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local button = Button {
|
||||||
|
Position = UDim2.new(),
|
||||||
|
Text = "Click me!",
|
||||||
|
|
||||||
|
Callback = function()
|
||||||
|
print "clicked"
|
||||||
|
end
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Above is a simple example of a button component with its background color set to
|
||||||
|
a dark grey and with a fixed size.
|
||||||
|
|
||||||
|
A single parameter `props` is used to pass properties to the component.
|
||||||
|
|
||||||
|
Components allow you to *encapsulate* behavior. You can only modify the
|
||||||
|
component in ways that you allow in the component.
|
||||||
|
|
||||||
|
This also promotes code reusability. Anytime you want a new button all you do
|
||||||
|
is call `Button {}` instead of creating and setting every property each time.
|
||||||
|
|
||||||
|
This can be extended to much more complicated UI.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [← Element Creation](./2-creation.md) | [State →](./4-state.md)
|
||||||
|
|
||||||
57
docs/tut/crash-course/4-state.md
Normal file
57
docs/tut/crash-course/4-state.md
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# [State](./index.md)
|
||||||
|
|
||||||
|
State in Vide are special objects that store data.
|
||||||
|
|
||||||
|
A state object in Vide can be created using
|
||||||
|
[`source()`](../../api/reactivity-core.md#source).
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local source = vide.source
|
||||||
|
```
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- create a new source
|
||||||
|
local count = source(0)
|
||||||
|
|
||||||
|
-- set source value
|
||||||
|
count(10)
|
||||||
|
|
||||||
|
-- get source value
|
||||||
|
print(count()) -- "10"
|
||||||
|
```
|
||||||
|
|
||||||
|
Below is an example of a counter component that has state.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local function Counter()
|
||||||
|
local count = source(0)
|
||||||
|
|
||||||
|
return create "TextButton" {
|
||||||
|
Text = count
|
||||||
|
|
||||||
|
Activated = function()
|
||||||
|
count(count() + 1)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Any time the source value is set, anything depending on it will automatically be
|
||||||
|
updated using the new value.
|
||||||
|
|
||||||
|
Vide detects when you assign a function to a property. This is known
|
||||||
|
as *binding* and doing so will cause the property to *automatically* update
|
||||||
|
whenever a state in that function is updated, by rerunning the function and
|
||||||
|
assigning its return value. You can only bind non-event
|
||||||
|
properties, otherwise the function is connected as the event callback.
|
||||||
|
|
||||||
|
You as the programmer do not have to worry about manually updating variables or
|
||||||
|
UI instances, you can just focus on defining how the data maps to UI and
|
||||||
|
everything will update when changes occur.
|
||||||
|
|
||||||
|
Each call of `Counter {}` will create a new counter element, each with their own
|
||||||
|
independent count state.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [← Components](./3-components.md) | [Derived State →](./5-derived-state.md)
|
||||||
57
docs/tut/crash-course/5-derived-state.md
Normal file
57
docs/tut/crash-course/5-derived-state.md
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
# [Derived State](./index.md)
|
||||||
|
|
||||||
|
You can create new state from existing states. This is known as *deriving
|
||||||
|
state*.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local count = source(0)
|
||||||
|
|
||||||
|
local function text()
|
||||||
|
return "count: " .. count()
|
||||||
|
end
|
||||||
|
|
||||||
|
create "TextLabel" {
|
||||||
|
Text = text
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Assigning a non-event property a function will bind that property to that
|
||||||
|
function, anytime a state being read from inside that function is changed, the
|
||||||
|
function will be re-ran and the property value updated.
|
||||||
|
|
||||||
|
Sometimes when using expensive computations to derive state, you only want to
|
||||||
|
recalculate it when a source state has changed.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local derive = vide.derive
|
||||||
|
```
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local count = source(0)
|
||||||
|
|
||||||
|
local factorial = derive(function()
|
||||||
|
local n = 1
|
||||||
|
for i = 2, count() do
|
||||||
|
n *= i
|
||||||
|
end
|
||||||
|
return n
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
`derive()` will cache and return the same value until a source state has
|
||||||
|
changed, where it will recompute and cache a new value.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
create "TextLabel" {
|
||||||
|
Text = function()
|
||||||
|
return "factorial: " .. factorial()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
count(3) -- displays "factorial: 6"
|
||||||
|
count(4) -- displays "factorial: 24"
|
||||||
|
```
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [← State](./4-State.md) | [Table State →](./6-table-state.md)
|
||||||
39
docs/tut/crash-course/6-table-state.md
Normal file
39
docs/tut/crash-course/6-table-state.md
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# [Table State](./index.md)
|
||||||
|
|
||||||
|
Vide has functions for dealing with table states.
|
||||||
|
|
||||||
|
Below is an example using the above `List` class.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
type Item = {
|
||||||
|
Name: string,
|
||||||
|
Icon: number
|
||||||
|
}
|
||||||
|
|
||||||
|
local items = source({} :: Array<Item>)
|
||||||
|
|
||||||
|
List {
|
||||||
|
Children = map(items, function(item, i)
|
||||||
|
return create "ImageLabel" {
|
||||||
|
Image = function()
|
||||||
|
return "rbxassetid://" .. item().Icon
|
||||||
|
end,
|
||||||
|
|
||||||
|
LayoutOrder = i
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here we map each element in `items` to a value returned by a callback.
|
||||||
|
|
||||||
|
The callback is called only *once* per key. The first argument given to the
|
||||||
|
callback is a state that has the value of the table key's value.
|
||||||
|
|
||||||
|
Anytime the value of the corresponding table key changes, the state value
|
||||||
|
changes too. This saves us from having to recreate a UI element any time a
|
||||||
|
table index changes.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [← Derived State](./5-derived-state.md) | [Property Groups →](./7-property-groups.md)
|
||||||
78
docs/tut/crash-course/7-property-groups.md
Normal file
78
docs/tut/crash-course/7-property-groups.md
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
# [Property Groups](./index.md)
|
||||||
|
|
||||||
|
When a key is assigned a table, Vide does not attempt to assign it to a
|
||||||
|
property, instead, the table is iterated and processed just like the nesting
|
||||||
|
table.
|
||||||
|
|
||||||
|
Below is an example of how you can use this to pass groups of similar properties
|
||||||
|
together such as position and size, while also using typechecking.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
type Layout = {
|
||||||
|
Layout = {
|
||||||
|
Position: UDim2?,
|
||||||
|
Size: UDim2?,
|
||||||
|
AnchorPoint: Vector2?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local function Button(args: Layout & {
|
||||||
|
Text: string,
|
||||||
|
Callback: () -> ()
|
||||||
|
})
|
||||||
|
local count = source(0)
|
||||||
|
|
||||||
|
return create "TextButton" {
|
||||||
|
Text = args.Text
|
||||||
|
Activated = args.Callback,
|
||||||
|
Layout = args.Layout
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
Button {
|
||||||
|
Text = "Click me!",
|
||||||
|
|
||||||
|
Callback = function()
|
||||||
|
print "clicked me!"
|
||||||
|
end,
|
||||||
|
|
||||||
|
Layout = {
|
||||||
|
Position = UDim2.new(),
|
||||||
|
Size = UDim2.new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Here the button component is assigned a position and size as if you passed those
|
||||||
|
properties directly.
|
||||||
|
|
||||||
|
The same can be done for properties such as children.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
type Children = {
|
||||||
|
Children = Array<Instance>
|
||||||
|
}
|
||||||
|
|
||||||
|
local function List(args: Children & Layout)
|
||||||
|
return create "Frame" {
|
||||||
|
Layout = args.Layout,
|
||||||
|
Children = args.Children,
|
||||||
|
|
||||||
|
create "UIListLayout" {}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
List {
|
||||||
|
Layout = {
|
||||||
|
Position = UDim2.new()
|
||||||
|
},
|
||||||
|
|
||||||
|
Children = {
|
||||||
|
create "TextLabel" { Text = "1" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
### [← Table State](./6-table-state.md)
|
||||||
15
docs/tut/crash-course/index.md
Normal file
15
docs/tut/crash-course/index.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Crash Course
|
||||||
|
|
||||||
|
1. ### [Introduction](./1-introduction.md)
|
||||||
|
|
||||||
|
2. ### [Element Creation](./2-creation.md)
|
||||||
|
|
||||||
|
3. ### [Components](./3-introduction.md)
|
||||||
|
|
||||||
|
4. ### [State](./4-introduction.md)
|
||||||
|
|
||||||
|
5. ### [Derived State](./5-introduction.md)
|
||||||
|
|
||||||
|
6. ### [Table State](./6-introduction.md)
|
||||||
|
|
||||||
|
7. ### [Property Groups](./7-introduction.md)
|
||||||
|
|
@ -486,7 +486,6 @@ end)
|
||||||
|
|
||||||
TEST("cleanup()", function()
|
TEST("cleanup()", function()
|
||||||
local source = vide.source
|
local source = vide.source
|
||||||
local derive = vide.derive
|
|
||||||
local watch = vide.watch
|
local watch = vide.watch
|
||||||
local cleanup = vide.cleanup
|
local cleanup = vide.cleanup
|
||||||
|
|
||||||
|
|
|
||||||
49
todo.md
49
todo.md
|
|
@ -11,52 +11,3 @@
|
||||||
- batch
|
- batch
|
||||||
- async/loading/suspense
|
- async/loading/suspense
|
||||||
- define order with nested properties
|
- define order with nested properties
|
||||||
|
|
||||||
```lua
|
|
||||||
type Action<T> = {
|
|
||||||
type: T,
|
|
||||||
priority: number,
|
|
||||||
callback: (Instance) -> ()
|
|
||||||
}
|
|
||||||
|
|
||||||
local function action(priority: number, fn: (Instance) -> ()): Action
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local function changed(property: string, callback: () -> ())
|
|
||||||
return action(1, function(instance)
|
|
||||||
instance:GetPropertyChangedSignal(property):Connect(callback)
|
|
||||||
end) :: Action<"Changed">
|
|
||||||
end
|
|
||||||
|
|
||||||
create "TextBox" {
|
|
||||||
Text = "test",
|
|
||||||
|
|
||||||
changed "Text" < function(self, data)
|
|
||||||
|
|
||||||
end
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## version 1
|
|
||||||
|
|
||||||
```lua
|
|
||||||
map(items, function(item, i)
|
|
||||||
return Item {
|
|
||||||
Item = item, -- primitive
|
|
||||||
LayoutOrder = i
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
```
|
|
||||||
|
|
||||||
## version 2
|
|
||||||
|
|
||||||
```lua
|
|
||||||
each(items, function(item, i)
|
|
||||||
return Item {
|
|
||||||
Item = item, -- state
|
|
||||||
LayoutOrder = i
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue