@quenty/blend 2.0.0-canary.236.5597d0a.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,23 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- # [2.0.0-canary.236.5597d0a.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/blend@1.1.0...@quenty/blend@2.0.0-canary.236.5597d0a.0) (2021-12-18)
6
+ ## [2.0.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/blend@2.0.0...@quenty/blend@2.0.1) (2021-12-30)
7
+
8
+ **Note:** Version bump only for package @quenty/blend
9
+
10
+
11
+
12
+
13
+
14
+ # [2.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/blend@1.2.0...@quenty/blend@2.0.0) (2021-12-22)
15
+
16
+ **Note:** Version bump only for package @quenty/blend
17
+
18
+
19
+
20
+
21
+
22
+ # [1.2.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/blend@1.1.0...@quenty/blend@1.2.0) (2021-12-18)
7
23
 
8
24
 
9
25
  ### Features
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  ## Blend
2
2
  <div align="center">
3
- <a href="http://quenty.github.io/api/">
4
- <img src="https://img.shields.io/badge/docs-website-green.svg" alt="Documentation" />
3
+ <a href="http://quenty.github.io/NevermoreEngine/">
4
+ <img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/docs.yml/badge.svg" alt="Documentation status" />
5
5
  </a>
6
6
  <a href="https://discord.gg/mhtGUS8">
7
- <img src="https://img.shields.io/badge/discord-nevermore-blue.svg" alt="Discord" />
7
+ <img src="https://img.shields.io/discord/385151591524597761?color=5865F2&label=discord&logo=discord&logoColor=white" alt="Discord" />
8
8
  </a>
9
9
  <a href="https://github.com/Quenty/NevermoreEngine/actions">
10
10
  <img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/build.yml/badge.svg" alt="Build and release status" />
@@ -13,6 +13,8 @@
13
13
 
14
14
  Declarative UI system inspired by Fusion
15
15
 
16
+ <div align="center"><a href="https://quenty.github.io/NevermoreEngine/api/Blend">View docs →</a></div>
17
+
16
18
  ## Installation
17
19
  ```
18
20
  npm install @quenty/blend --save
@@ -24,49 +26,4 @@ This system is designed to be very similar to fusion, except that we do not havi
24
26
 
25
27
  * No global state
26
28
  * Extensible
27
- * No implicit reliance upon GC
28
-
29
- ## Usage
30
-
31
- See files in src/Client/Test that are stories. Blend returns an observable that will create/return one instance.
32
-
33
- Note that subscribe function anchors everything into a maid/cleanup function that can be used to disconnect the whole tree.
34
-
35
- ```lua
36
- local require = ... -- Nevermore import here
37
- local Blend = require("Blend")
38
- local Maid = require("Maid")
39
-
40
- local maid = Maid.new()
41
-
42
- local isVisible = Instance.new("BoolValue")
43
- isVisible.Value = false
44
-
45
- local percentVisible = Blend.Spring(Blend.Computed(isVisible, function(visible)
46
- return visible and 1 or 0
47
- end), 35)
48
-
49
- local transparency = Blend.Computed(percentVisible, function(percent)
50
- return 1 - percent
51
- end)
52
-
53
- maid:GiveTask((Blend.New "Frame" {
54
- Size = UDim2.new(0.5, 0, 0.5, 0);
55
- BackgroundColor3 = Color3.new(0.9, 0.9, 0.9);
56
- AnchorPoint = Vector2.new(0.5, 0.5);
57
- Position = UDim2.new(0.5, 0, 0.5, 0);
58
- BackgroundTransparency = transparency;
59
- Parent = parent; -- TODO: Assign parent
60
-
61
- [Blend.Children] = {
62
- Blend.New "UIScale" {
63
- Scale = Blend.Computed(percentVisible, function(percent)
64
- return 0.8 + 0.2*percent
65
- end);
66
- };
67
- Blend.New "UICorner" {
68
- CornerRadius = UDim.new(0.05, 0);
69
- };
70
- };
71
- }):Subscribe())
72
- ```
29
+ * No implicit reliance upon GC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/blend",
3
- "version": "2.0.0-canary.236.5597d0a.0",
3
+ "version": "2.0.1",
4
4
  "description": "Declarative UI system.",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -27,23 +27,23 @@
27
27
  "access": "public"
28
28
  },
29
29
  "dependencies": {
30
- "@quenty/acceltween": "2.0.0",
31
- "@quenty/brio": "4.0.0-canary.236.5597d0a.0",
32
- "@quenty/instanceutils": "4.0.0-canary.236.5597d0a.0",
33
- "@quenty/loader": "3.1.1",
34
- "@quenty/maid": "2.0.1",
35
- "@quenty/promise": "4.0.0-canary.236.5597d0a.0",
36
- "@quenty/rx": "4.0.0-canary.236.5597d0a.0",
37
- "@quenty/spring": "3.0.0-canary.236.5597d0a.0",
38
- "@quenty/steputils": "3.0.0",
39
- "@quenty/string": "2.2.0",
40
- "@quenty/symbol": "2.0.0",
41
- "@quenty/valuebaseutils": "4.0.0-canary.236.5597d0a.0",
42
- "@quenty/valueobject": "4.0.0-canary.236.5597d0a.0"
30
+ "@quenty/acceltween": "^2.0.1",
31
+ "@quenty/brio": "^3.5.1",
32
+ "@quenty/instanceutils": "^3.5.1",
33
+ "@quenty/loader": "^3.1.2",
34
+ "@quenty/maid": "^2.0.2",
35
+ "@quenty/promise": "^3.3.1",
36
+ "@quenty/rx": "^3.5.1",
37
+ "@quenty/spring": "^3.0.1",
38
+ "@quenty/steputils": "^3.0.1",
39
+ "@quenty/string": "^2.2.1",
40
+ "@quenty/symbol": "^2.0.1",
41
+ "@quenty/valuebaseutils": "^3.5.1",
42
+ "@quenty/valueobject": "^3.5.1"
43
43
  },
44
44
  "devDependencies": {
45
- "@quenty/contentproviderutils": "4.0.0-canary.236.5597d0a.0",
46
- "@quenty/playerthumbnailutils": "4.0.0-canary.236.5597d0a.0"
45
+ "@quenty/contentproviderutils": "^3.3.1",
46
+ "@quenty/playerthumbnailutils": "^3.4.1"
47
47
  },
48
- "gitHead": "5597d0abdadd88f369f1401a558a8d6d1a1c5aab"
48
+ "gitHead": "d146c77d0a8e452824de0ab0b4b03ba0370bcc1b"
49
49
  }
@@ -1,6 +1,7 @@
1
- ---
2
- -- @module Blend
3
- -- @author Quenty
1
+ --[=[
2
+ Declarative UI system inspired by Fusion
3
+ @class Blend
4
+ ]=]
4
5
 
5
6
  local require = require(script.Parent.loader).load(script)
6
7
 
@@ -25,6 +26,26 @@ local Blend = {}
25
26
 
26
27
  Blend.Children = Symbol.named("children")
27
28
 
29
+ --[=[
30
+ Creates a new function which will return an observable that, given the props
31
+ in question, will construct a new instance and assign all props. This is the
32
+ equivalent of a pipe-able Rx command.
33
+
34
+ ```lua
35
+ Blend.New "ScreenGui" {
36
+ Parent = game.Players.LocalPlayer.PlayerGui;
37
+ [Blend.Children] = {
38
+ Blend.New "Frame" {
39
+ Size = UDim2.new(1, 0, 1, 0);
40
+ BackgroundTransparency = 0.5;
41
+ };
42
+ };
43
+ };
44
+
45
+ @param className string
46
+ @return (props: { [string]: any; }) -> Observable<Instance>
47
+ ```
48
+ ]=]
28
49
  function Blend.New(className)
29
50
  assert(type(className) == "string", "Bad className")
30
51
 
@@ -51,6 +72,12 @@ function Blend.New(className)
51
72
  end
52
73
  end
53
74
 
75
+ --[=[
76
+ Creates a new Blend State which is actually just a ValueObject underneath.
77
+
78
+ @param defaultValue T
79
+ @return ValueObject<T>
80
+ ]=]
54
81
  function Blend.State(defaultValue)
55
82
  return ValueObject.new(defaultValue)
56
83
  end
@@ -72,6 +99,32 @@ function Blend.Dynamic(...)
72
99
  })
73
100
  end
74
101
 
102
+ --[=[
103
+ Takes a list of variables and uses them to compute an observable that
104
+ will combine into any value. These variables can be any value, and if they
105
+ can be converted into an Observable, they will be, which will be used to compute
106
+ the value.
107
+
108
+ ```lua
109
+ local verbState = Blend.State("hi")
110
+ local nameState = Blend.State("alice")
111
+
112
+ local computed = Blend.Computed(verbState, nameState, function(verb, name)
113
+ return verb .. " " .. name
114
+ end)
115
+
116
+ computed:Subscribe(function(sentence)
117
+ print(sentence)
118
+ end) --> "hi alice"
119
+
120
+ nameState.Value = "bob" --> "hi bob"
121
+ verbState.Value = "bye" --> "bye bob"
122
+ nameState.Value = "alice" --> "bye alice"
123
+ ```
124
+
125
+ @param ... A series of convertable states, followed by a function at the end.
126
+ @return Observable<T>
127
+ ]=]
75
128
  function Blend.Computed(...)
76
129
  local values = {...}
77
130
  local n = select("#", ...)
@@ -106,6 +159,22 @@ function Blend.Computed(...)
106
159
  end
107
160
  end
108
161
 
162
+ --[=[
163
+ Short hand to register a propertyEvent changing
164
+
165
+ ```lua
166
+ Blend.mount(workspace, {
167
+ [Blend.OnChange "Name"] = function(name)
168
+ print(name)
169
+ end;
170
+ }) --> Immediately will print "Workspace"
171
+
172
+ workspace.Name = "Hello" --> Prints "Hello"
173
+ ```
174
+
175
+ @param propertyName string
176
+ @return (instance: Instance) -> Observable
177
+ ]=]
109
178
  function Blend.OnChange(propertyName)
110
179
  assert(type(propertyName) == "string", "Bad propertyName")
111
180
 
@@ -114,6 +183,24 @@ function Blend.OnChange(propertyName)
114
183
  end
115
184
  end
116
185
 
186
+ --[=[
187
+ Short hand to register an event from the instance
188
+
189
+ ```lua
190
+ Blend.mount(workspace, {
191
+ [Blend.OnEvent "ChildAdded"] = function(child)
192
+ print("Child added", child)
193
+ end;
194
+ })
195
+
196
+ local folder = Instance.new("Folder")
197
+ folder.Name = "Hi"
198
+ folder.Parent = workspace --> prints "Child added Hi"
199
+ ```
200
+
201
+ @param eventName string
202
+ @return (instance: Instance) -> Observable
203
+ ]=]
117
204
  function Blend.OnEvent(eventName)
118
205
  assert(type(eventName) == "string", "Bad eventName")
119
206
 
@@ -153,7 +240,7 @@ function Blend.ComputedPairs(source, compute)
153
240
  local brio = Brio.new(result)
154
241
  innerMaid:GiveTask(brio)
155
242
 
156
- local cleanup = Blend.addChildren(parent, brio)
243
+ local cleanup = Blend.mountChildren(parent, brio)
157
244
  if cleanup then
158
245
  innerMaid:GiveTask(cleanup)
159
246
  end
@@ -173,6 +260,13 @@ function Blend.ComputedPairs(source, compute)
173
260
  end
174
261
  end
175
262
 
263
+ --[=[
264
+ Like Blend.Spring, but for AccelTween
265
+
266
+ @param source any -- Source observable (or convertable)
267
+ @param acceleration any -- Source acceleration (or convertable)
268
+ @return Observable
269
+ ]=]
176
270
  function Blend.AccelTween(source, acceleration)
177
271
  local sourceObservable = Blend.toPropertyObservable(source) or Rx.of(source)
178
272
  local accelerationObservable = Blend.toNumberObservable(acceleration)
@@ -211,7 +305,27 @@ function Blend.AccelTween(source, acceleration)
211
305
  end)
212
306
  end
213
307
 
214
-
308
+ --[=[
309
+ Converts this arbitrary value into an observable that will initialize a spring
310
+ and interpolate it between values upon subscription.
311
+
312
+ ```lua
313
+ local percentVisible = Blend.State(0)
314
+ local visibleSpring = Blend.Spring(percentVisible, 30)
315
+ local transparency = Blend.Computed(visibleSpring, function(percent)
316
+ return 1 - percent
317
+ end);
318
+
319
+ Blend.mount(frame, {
320
+ BackgroundTransparency = visibleSpring;
321
+ })
322
+ ```
323
+
324
+ @param source any
325
+ @param speed any
326
+ @param damper any
327
+ @return Observable?
328
+ ]=]
215
329
  function Blend.Spring(source, speed, damper)
216
330
  local sourceObservable = Blend.toPropertyObservable(source) or Rx.of(source)
217
331
  local speedObservable = Blend.toNumberObservable(speed)
@@ -261,6 +375,12 @@ function Blend.Spring(source, speed, damper)
261
375
  end)
262
376
  end
263
377
 
378
+ --[=[
379
+ Converts this arbitrary value into an observable suitable for use in properties.
380
+
381
+ @param value any
382
+ @return Observable?
383
+ ]=]
264
384
  function Blend.toPropertyObservable(value)
265
385
  if Observable.isObservable(value) then
266
386
  return value
@@ -280,6 +400,12 @@ function Blend.toPropertyObservable(value)
280
400
  return nil
281
401
  end
282
402
 
403
+ --[=[
404
+ Converts this arbitrary value into an observable that emits numbers.
405
+
406
+ @param value number | any
407
+ @return Observable<number>?
408
+ ]=]
283
409
  function Blend.toNumberObservable(value)
284
410
  if type(value) == "number" then
285
411
  return Rx.of(value)
@@ -288,6 +414,12 @@ function Blend.toNumberObservable(value)
288
414
  end
289
415
  end
290
416
 
417
+ --[=[
418
+ Converts this arbitrary value into an observable that can be used to emit events.
419
+
420
+ @param value any
421
+ @return Observable?
422
+ ]=]
291
423
  function Blend.toEventObservable(value)
292
424
  if Observable.isObservable(value) then
293
425
  return value
@@ -298,6 +430,12 @@ function Blend.toEventObservable(value)
298
430
  end
299
431
  end
300
432
 
433
+ --[=[
434
+ Converts this arbitrary value into an event handler, which can be subscribed to
435
+
436
+ @param value any
437
+ @return function?
438
+ ]=]
301
439
  function Blend.toEventHandler(value)
302
440
  if type(value) == "function" then
303
441
  return value
@@ -319,7 +457,18 @@ function Blend.toEventHandler(value)
319
457
  return nil
320
458
  end
321
459
 
322
- function Blend.addChildren(parent, value)
460
+ --[=[
461
+ Mounts children to the parent and returns an object which will cleanup and delete
462
+ all children when removed.
463
+
464
+ Note that this effectively recursively mounts children and their values, which is
465
+ the heart of the reactive tree.
466
+
467
+ @param parent Instance
468
+ @param value any
469
+ @return MaidTask
470
+ ]=]
471
+ function Blend.mountChildren(parent, value)
323
472
  if typeof(value) == "Instance" then
324
473
  value.Parent = parent
325
474
 
@@ -336,7 +485,7 @@ function Blend.addChildren(parent, value)
336
485
  local maid = Maid.new()
337
486
 
338
487
  -- Add for lifetime
339
- local cleanup = Blend.addChildren(parent, value:GetValue())
488
+ local cleanup = Blend.mountChildren(parent, value:GetValue())
340
489
  if cleanup then
341
490
  maid:GiveTask(cleanup)
342
491
  end
@@ -355,7 +504,7 @@ function Blend.addChildren(parent, value)
355
504
  local maid = Maid.new()
356
505
 
357
506
  maid:GiveTask(observable:Subscribe(function(result)
358
- maid._current = Blend.addChildren(parent, result)
507
+ maid._current = Blend.mountChildren(parent, result)
359
508
  end))
360
509
 
361
510
  return maid
@@ -365,7 +514,7 @@ function Blend.addChildren(parent, value)
365
514
  -- hope we're actually recursing over a nested table.
366
515
  -- this allows us to add arrays into the blend.
367
516
  for _, item in pairs(value) do
368
- local cleanup = Blend.addChildren(parent, item)
517
+ local cleanup = Blend.mountChildren(parent, item)
369
518
  if cleanup then
370
519
  maid:GiveTask(cleanup)
371
520
  end
@@ -384,6 +533,22 @@ function Blend.addChildren(parent, value)
384
533
  return nil
385
534
  end
386
535
 
536
+ --[=[
537
+ Mounts the instance to the props. This handles mounting children, and events.
538
+
539
+ The contract is that the props table is turned into observables. Note the following.
540
+
541
+ * Keys of strings are turned into properties
542
+ * If this can be turned into an observable, it will be used to subscribe to this event
543
+ * Otherwise, we assign directly
544
+ * Keys of functions are invoked on the instance in question
545
+ * If this returns an observable (or can be turned into one), we subscribe the event immediately
546
+ * If the key is [Blend.Children] then we invoke mountChildren on it
547
+
548
+ @param instance Instance
549
+ @param props table
550
+ @return Maid
551
+ ]=]
387
552
  function Blend.mount(instance, props)
388
553
  local maid = Maid.new()
389
554
 
@@ -432,7 +597,7 @@ function Blend.mount(instance, props)
432
597
 
433
598
  local childProp = props[Blend.Children]
434
599
  if childProp then
435
- local cleanup = Blend.addChildren(instance, childProp)
600
+ local cleanup = Blend.mountChildren(instance, childProp)
436
601
  if cleanup then
437
602
  maid:GiveTask(cleanup)
438
603
  end
@@ -1,6 +1,6 @@
1
- ---
2
- -- @module Blend.story
3
- -- @author Quenty
1
+ --[[
2
+ @class Blend.story
3
+ ]]
4
4
 
5
5
  local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).load(script)
6
6
 
@@ -1,6 +1,6 @@
1
- ---
2
- -- @module Blend.story
3
- -- @author Quenty
1
+ --[[
2
+ @class Blend.story
3
+ ]]
4
4
 
5
5
  local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).load(script)
6
6
 
@@ -1,6 +1,6 @@
1
- ---
2
- -- @module BlendTextbox.story
3
- -- @author Quenty
1
+ --[[
2
+ @class BlendTextbox.story
3
+ ]]
4
4
 
5
5
  local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).load(script)
6
6
 
@@ -1,6 +1,6 @@
1
- ---
2
- -- @module Blend.story
3
- -- @author Quenty
1
+ --[[
2
+ @class Blend.story
3
+ ]]
4
4
 
5
5
  local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).load(script)
6
6
 
@@ -1,6 +1,6 @@
1
- ---
2
- -- @module BlendTextbox.story
3
- -- @author Quenty
1
+ --[[
2
+ @class BlendTextbox.story
3
+ ]]
4
4
 
5
5
  local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).load(script)
6
6
 
@@ -1,6 +1,4 @@
1
- --- Main injection point
2
- -- @script ClientMain
3
- -- @author Quenty
1
+ -- Main injection point
4
2
 
5
3
  local packages = game:GetService("ReplicatedStorage"):WaitForChild("Packages")
6
4
 
@@ -1,6 +1,5 @@
1
- --- Main injection point
1
+ -- Main injection point
2
2
  -- @script ServerMain
3
- -- @author Quenty
4
3
 
5
4
  local ServerScriptService = game:GetService("ServerScriptService")
6
5