From 6da33722e9799c21daca98639d509ba5a56aef7f Mon Sep 17 00:00:00 2001 From: centauri <83140718+centau@users.noreply.github.com> Date: Sat, 17 Jan 2026 20:15:05 +0000 Subject: [PATCH] Add delayed scope destruction to docs --- CHANGELOG.md | 2 + docs/api/animation.md | 4 +- docs/api/reactivity-dynamic.md | 47 ++++++++++++------ docs/tut/advanced/dynamic-scopes.md | 4 +- docs/tut/crash-course/11-dynamic-scopes.md | 55 +++++++++++++++++++++- 5 files changed, 92 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01f2dd1..3781126 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). effects to set children. - `spring()` returns a second value, a setter to set position, velocity and impulse. +- Improved `spring()` updating and unscheduling. - `show()` now receives a source to its callback returning the current value of the condition. - Ignore `false` passed as a child. - Flag `vide.defaults` to disable the setting of default properties. - Delayed scope destruction for control flow functions: `show()` `switch()` `indexes()` `values()`. +- Better `create()` types for the new type solver. ### Changed diff --git a/docs/api/animation.md b/docs/api/animation.md index 9b5baf4..ca06b39 100644 --- a/docs/api/animation.md +++ b/docs/api/animation.md @@ -11,11 +11,11 @@ Returns a new source with a value always moving torwards the input source value. source: () -> T & Animatable, period: number = 1, damping_ratio: number = 1 - ): (() -> T, SpringConfig) + ): (() -> T, SpringControl) type Animatable = number | CFrame | Color3 | UDim | UDim2 | Vector2 | Vector3 | Rect - type SpringConfig = ({ + type SpringControl = ({ position: T?, velocity: T?, impulse: T? diff --git a/docs/api/reactivity-dynamic.md b/docs/api/reactivity-dynamic.md index 875c12f..f0b3229 100644 --- a/docs/api/reactivity-dynamic.md +++ b/docs/api/reactivity-dynamic.md @@ -1,7 +1,7 @@ -# Reactivity: Dynamic Scoping +# Reactivity: Dynamic Scopes -Dynamic scoping is the act of creating and destroying new scopes in response to -source updates. Vide provides functions for some common use-cases to do this. +Dynamic scopes are scopes that are created or destroyed in response to +source updates. Vide provides functions for some common use-cases for dynamic scopes. ## show() REACTIVE @@ -11,8 +11,10 @@ if the source is falsey. - **Type** ```luau - function show(source: () -> unknown, component: () -> T): () -> T? - function show(source: () -> unknown, component: () -> T, fallback: () -> U): () -> T | U + function show(source: () -> unknown, component: Constructor): () -> T? + function show(source: () -> unknown, component: Constructor, fallback: () -> U): () -> T | U + + type Constructor = () -> (T, number?) ``` - **Details** @@ -25,6 +27,9 @@ if the source is falsey. Returns a source holding an instance of the currently shown component or `nil` if no component is currently shown. + Destruction of the scope can be delayed by returning the number of seconds + to delay by, after the component. + ## switch() REACTIVE Shows one of a set of components depending on a source and a mapping table. @@ -32,7 +37,9 @@ Shows one of a set of components depending on a source and a mapping table. - **Type** ```luau - function switch(source: () -> K): (map: Map V>): () -> V? + function switch(source: () -> K): (map: Map>): () -> V? + + type Constructor = () -> (T, number?) ``` - **Details** @@ -46,6 +53,9 @@ Shows one of a set of components depending on a source and a mapping table. Returns a source holding an instance of the currently shown component or `nil` if no component is currently shown. + Destruction of the scope can be delayed by returning the number of seconds + to delay by, after the component. + - **Example** ```luau @@ -71,8 +81,9 @@ Shows a component for each index in a table. ```luau function indexes( source: () -> Map, - transform: (value: () -> VI, index: KI) -> VO + constructor: (value: () -> VI, index: KI) -> (VO, number?) ): Array + ``` - **Details** @@ -81,21 +92,24 @@ Shows a component for each index in a table. When the source table updates, a component is generated for each index in the table. - - For any added index, the `transform` function is run in a new stable + - For any added index, the `constructor` function is run in a new stable scope to produce an instance that is cached. - For any removed index, the stable scope for that index is destroyed. - The `transform` function is called with: + The `constructor` function is called with: 1. A *source containing the index's value*. 2. The *index itself*. - Anytime an existing index's value changes, the `transform` function is not + Anytime an existing index's value changes, the `constructor` function is not rerun, instead, that index's corresponding source is updated with the new value. Returns a source holding an array of instances currently shown. + Destruction of the scope can be delayed by returning the number of seconds + to delay by, after the component. + - **Example** ```luau @@ -128,7 +142,7 @@ Shows a component for each value in a table. ```luau function values( source: () -> Map, - transform: (value: VI, index: () -> KI) -> VO + constructor: (value: VI, index: () -> KI) -> (VO, number?) ): Array - **Details** @@ -141,21 +155,24 @@ Shows a component for each value in a table. When the source table updates, a component is generated for each value in the table. - - For any added value, the `transform` function is run in a new stable scope + - For any added value, the `constructor` function is run in a new stable scope to produce an instance that is cached. - For any removed value, the stable scope for that value is destroyed. - The `transform` function is called with: + The `constructor` function is called with: 1. The *value itself*. 2. A *source containing the value's index*. - Anytime an existing value's index changes, the `transform` function is not + Anytime an existing value's index changes, the `constructor` function is not rerun, instead, that value's corresponding source is updated with the new index. Returns a source holding an array of instances currently shown. - + + Destruction of the scope can be delayed by returning the number of seconds + to delay by, after the component. + ::: warning Having the same values appear multiple times in the input source table can cause unexpected behavior. Strict mode has checks for this. diff --git a/docs/tut/advanced/dynamic-scopes.md b/docs/tut/advanced/dynamic-scopes.md index 99fe746..139a19c 100644 --- a/docs/tut/advanced/dynamic-scopes.md +++ b/docs/tut/advanced/dynamic-scopes.md @@ -1,6 +1,6 @@ -# Dynamic Scoping +# Dynamic Scopes -Dynamic scoping is the act of creating and destroying new scopes in response to +Dynamic scopes are scopes that are created and destroyed in response to source updates. This is needed for conditionally rendering parts of your UI, such as opening and closing menus. diff --git a/docs/tut/crash-course/11-dynamic-scopes.md b/docs/tut/crash-course/11-dynamic-scopes.md index bede8d8..1c12e51 100644 --- a/docs/tut/crash-course/11-dynamic-scopes.md +++ b/docs/tut/crash-course/11-dynamic-scopes.md @@ -4,7 +4,7 @@ Eventually you may need a way to dynamically create and destroy UI elements resulting from source updates. Vide provides functions to help you do this, known as *dynamic scope* functions. -These functions create and destroy components for you in response to source +These functions create and destroy scopes for you in response to source updates. They return a source containing the created component. This source can be parented as a child which will update the shown children whenever the source updates. @@ -156,3 +156,56 @@ local data = src() table.insert(data, 3) -- no effects will run src(data) -- effects will run ``` + +-------------------------------------------------------------------------------- + +All dynamic scope functions also support delaying the destruction of the scope. +This is useful for playing any sort of animation or effect before the UI +instance is removed. + +If you have the following code, for example: + +```lua +local function Menu() + return create "Frame" {} +end + +local toggled = source(true) + +create "ScreenGui" { + show(toggled, function() + return Menu {} + end) +} + +toggled(false) -- menu will disappear immediately +``` + +```lua +local function Menu(props: { Visible: () -> boolean }) + local transparency = spring(function() + return if p.Visible then 0 else 1 + end + + return create "Frame" { + BackgroundTransparency = transparency + } +end + +local toggled = source(true) + +create "ScreenGui" { + show(toggled, function(_, present) + return Menu { p.Visible = present }, 3 -- give a generous 3 seconds for the spring to complete before destroying + end) +} + +toggled(false) +-- `present` will go `false` immediately +-- transparency will begin being sprung +-- after 3 seconds the scope is destroyed, giving the spring enough time to complete +``` + +If `toggled` goes from truthy to falsey, beginning the timer, but then back +to truthy before the timer finishes, the timer is cancelled and the scope is +not destroyed.