@manyducks.co/dolla 0.69.2 → 0.69.3
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/README.md +64 -50
- package/notes/views.md +3 -9
- package/package.json +1 -1
- package/notes/state.md +0 -71
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ States come in two varieties, each with a constructor function and a TypeScript
|
|
|
24
24
|
- `.set(value: T)` to replace the stored value.
|
|
25
25
|
- `.update(callback: (current: T) => T)` which takes a function that receives the current value and returns a new one.
|
|
26
26
|
|
|
27
|
-
The constructor functions are `$` for `Readable`
|
|
27
|
+
The constructor functions are `$` for `Readable` and `$$` for `Writable`. By convention, the names of each are prefixed with `$` or `$$` to indicate its type, making the data flow a lot easier to understand at a glance.
|
|
28
28
|
|
|
29
29
|
```js
|
|
30
30
|
import { $, $$ } from "@manyducks.co/dolla";
|
|
@@ -131,12 +131,12 @@ Notice that the structure above composes a data pipeline; if any of the data cha
|
|
|
131
131
|
The `unwrap` function returns the current value of a Readable or Writable, or if passed a non-Readable value returns that exact value. This function is used to guarantee you have a plain value when you may be dealing with either a container or a plain value.
|
|
132
132
|
|
|
133
133
|
```js
|
|
134
|
-
import { unwrap } from "@manyducks.co/dolla";
|
|
134
|
+
import { $, $$, unwrap } from "@manyducks.co/dolla";
|
|
135
135
|
|
|
136
136
|
const $$number = $$(5);
|
|
137
137
|
|
|
138
138
|
unwrap($$number); // 5
|
|
139
|
-
unwrap(
|
|
139
|
+
unwrap($(5)); // 5
|
|
140
140
|
unwrap(5); // 5
|
|
141
141
|
```
|
|
142
142
|
|
|
@@ -398,7 +398,10 @@ Stores are helpful for managing persistent state that needs to be accessed in ma
|
|
|
398
398
|
```js
|
|
399
399
|
import { App } from "@manyducks.co/dolla";
|
|
400
400
|
|
|
401
|
-
const app = App(
|
|
401
|
+
const app = App({
|
|
402
|
+
view: LayoutView,
|
|
403
|
+
stores: [MessageStore],
|
|
404
|
+
});
|
|
402
405
|
|
|
403
406
|
// We define a store that just exports a message.
|
|
404
407
|
function MessageStore() {
|
|
@@ -407,9 +410,6 @@ function MessageStore() {
|
|
|
407
410
|
};
|
|
408
411
|
}
|
|
409
412
|
|
|
410
|
-
// Register it on the app.
|
|
411
|
-
app.store(MessageStore);
|
|
412
|
-
|
|
413
413
|
// All instances of MessageView will share just one instance of MessageStore.
|
|
414
414
|
function MessageView(props, ctx) {
|
|
415
415
|
const store = ctx.getStore(MessageStore);
|
|
@@ -431,9 +431,6 @@ function LayoutView() {
|
|
|
431
431
|
);
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
// Use LayoutView as the app's main view.
|
|
435
|
-
app.main(LayoutView);
|
|
436
|
-
|
|
437
434
|
// Connect the app.
|
|
438
435
|
app.connect("#app");
|
|
439
436
|
```
|
|
@@ -537,15 +534,20 @@ const app = App({
|
|
|
537
534
|
</div>
|
|
538
535
|
);
|
|
539
536
|
},
|
|
540
|
-
});
|
|
541
|
-
|
|
542
|
-
app.addStore(RouterStore, {
|
|
543
|
-
hash: true, // Use hash-based routing (default false)
|
|
544
537
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
538
|
+
stores: [
|
|
539
|
+
{
|
|
540
|
+
store: RouterStore,
|
|
541
|
+
options: {
|
|
542
|
+
hash: true, // Use hash-based routing (default false)
|
|
543
|
+
|
|
544
|
+
// Here are a couple of routes to be rendered into our layout:
|
|
545
|
+
routes: [
|
|
546
|
+
{ path: "/tasks", view: TasksView },
|
|
547
|
+
{ path: "/completed", view: CompletedView },
|
|
548
|
+
],
|
|
549
|
+
},
|
|
550
|
+
},
|
|
549
551
|
],
|
|
550
552
|
});
|
|
551
553
|
```
|
|
@@ -553,25 +555,32 @@ app.addStore(RouterStore, {
|
|
|
553
555
|
Routes can also be nested. Just like the main view and its routes, subroutes will be displayed in the outlet of their parent view.
|
|
554
556
|
|
|
555
557
|
```jsx
|
|
556
|
-
app
|
|
557
|
-
|
|
558
|
+
const app = App({
|
|
559
|
+
stores: [
|
|
558
560
|
{
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
561
|
+
store: RouterStore,
|
|
562
|
+
options: {
|
|
563
|
+
routes: [
|
|
564
|
+
{
|
|
565
|
+
path: "/tasks",
|
|
566
|
+
view: TasksView,
|
|
567
|
+
routes: [
|
|
568
|
+
{ path: "/", view: TaskListView },
|
|
569
|
+
|
|
570
|
+
// In routes, `{value}` is a dynamic value that matches anything,
|
|
571
|
+
// and `{#value}` is a dynamic value that matches a number.
|
|
572
|
+
{ path: "/{#id}", view: TaskDetailsView },
|
|
573
|
+
{ path: "/{#id}/edit", view: TaskEditView },
|
|
574
|
+
|
|
575
|
+
// If the route is any other than the ones defined above, redirect to the list.
|
|
576
|
+
// Redirects support './' and '../' style relative paths.
|
|
577
|
+
{ path: "*", redirect: "./" },
|
|
578
|
+
],
|
|
579
|
+
},
|
|
580
|
+
{ path: "/completed", view: CompletedView },
|
|
581
|
+
],
|
|
582
|
+
},
|
|
573
583
|
},
|
|
574
|
-
{ path: "/completed", view: CompletedView },
|
|
575
584
|
],
|
|
576
585
|
});
|
|
577
586
|
```
|
|
@@ -606,22 +615,27 @@ Now, here are some route examples in the context of an app:
|
|
|
606
615
|
import { App, RouterStore } from "@manyducks.co/dolla";
|
|
607
616
|
import { PersonDetails, ThingIndex, ThingDetails, ThingEdit, ThingDelete } from "./components.js";
|
|
608
617
|
|
|
609
|
-
const app = App(
|
|
610
|
-
|
|
611
|
-
app.addStore(RouterStore, {
|
|
612
|
-
routes: [
|
|
613
|
-
{ path: "/people/{name}", view: PersonDetails },
|
|
618
|
+
const app = App({
|
|
619
|
+
stores: [
|
|
614
620
|
{
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
621
|
+
store: RouterStore,
|
|
622
|
+
options: {
|
|
623
|
+
routes: [
|
|
624
|
+
{ path: "/people/{name}", view: PersonDetails },
|
|
625
|
+
{
|
|
626
|
+
// A `null` component with subroutes acts as a namespace for those subroutes.
|
|
627
|
+
// Passing a view instead of `null` results in subroutes being rendered inside that view wherever `ctx.outlet()` is called.
|
|
628
|
+
path: "/things",
|
|
629
|
+
view: null,
|
|
630
|
+
routes: [
|
|
631
|
+
{ path: "/", view: ThingIndex }, // matches `/things`
|
|
632
|
+
{ path: "/{#id}", view: ThingDetails }, // matches `/things/{#id}`
|
|
633
|
+
{ path: "/{#id}/edit", view: ThingEdit }, // matches `/things/{#id}/edit`
|
|
634
|
+
{ path: "/{#id}/delete", view: ThingDelete }, // matches `/things/{#id}/delete`
|
|
635
|
+
],
|
|
636
|
+
},
|
|
637
|
+
],
|
|
638
|
+
},
|
|
625
639
|
},
|
|
626
640
|
],
|
|
627
641
|
});
|
package/notes/views.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
```js
|
|
2
|
-
import { View, Store,
|
|
2
|
+
import { View, Store, $, $$ } from "@manyducks.co/dolla";
|
|
3
3
|
|
|
4
4
|
const SomeView = View("SomeView")
|
|
5
5
|
.props((t) => ({
|
|
@@ -13,16 +13,10 @@ const SomeView = View("SomeView")
|
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
const SomeStore = Store("SomeStore").build((ctx) => {
|
|
16
|
-
const $$value =
|
|
16
|
+
const $$value = $$(0);
|
|
17
17
|
|
|
18
18
|
return {
|
|
19
|
-
$value: $$value
|
|
19
|
+
$value: $($$value),
|
|
20
20
|
};
|
|
21
21
|
});
|
|
22
|
-
|
|
23
|
-
// Stores can be configured in an app like so:
|
|
24
|
-
|
|
25
|
-
const app = App();
|
|
26
|
-
|
|
27
|
-
app.addStore(SomeStore.configure(options));
|
|
28
22
|
```
|
package/package.json
CHANGED
package/notes/state.md
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# State
|
|
2
|
-
|
|
3
|
-
I want to update the state API to be a single constructor object, similar to built-ins like `Math` and `Array`. The current API has a lot of separate functions that work together in various ways, but I feel it would be easier to explain and understand if these functions were under one namespace.
|
|
4
|
-
|
|
5
|
-
Current API:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { readable, writable, computed, unwrap, proxy, type Readable, type Writable } from "@manyducks.co/dolla";
|
|
9
|
-
|
|
10
|
-
const $$writable = writable({ someValue: 5, otherValue: "test" });
|
|
11
|
-
const $readable = readable($$writable);
|
|
12
|
-
const $computed = computed($$writable, (value) => value.someValue * 256);
|
|
13
|
-
const unwrapped = unwrap($computed);
|
|
14
|
-
const $$proxy = proxy($$writable, {
|
|
15
|
-
get(source) {
|
|
16
|
-
return source.get().someValue;
|
|
17
|
-
},
|
|
18
|
-
set(source, value) {
|
|
19
|
-
source.update((current) => {
|
|
20
|
-
return { ...current, someValue: value };
|
|
21
|
-
});
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
const $multiComputed = computed([$one, $$two, $three], ([one, two, three], [oldOne, oldTwo, oldThree]) => {
|
|
25
|
-
return one + two + three;
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
$$writable.get();
|
|
29
|
-
$$writable.set({ someValue: 12, otherValue: null });
|
|
30
|
-
$$writable.update((current) => ({ ...current, someValue: 100 }));
|
|
31
|
-
|
|
32
|
-
$readable.get();
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
The main problem with the above is that we have two things (readable and writable) and a bunch of disconnected utility functions.
|
|
36
|
-
|
|
37
|
-
Proposed API:
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
import { State, type Readable, type Writable } from "@manyducks.co/dolla";
|
|
41
|
-
|
|
42
|
-
const $$writable = State.writable({ someValue: 5, otherValue: "test" }); // Longhand
|
|
43
|
-
const $$writable = State({ someValue: 5, otherValue: "test" }); // Shorthand
|
|
44
|
-
const $readable = State.readable($$writable);
|
|
45
|
-
const $readable = $$writable.readable(); // Directly from a writable
|
|
46
|
-
const $computed = State.from($$writable, (value) => value.someValue * 256);
|
|
47
|
-
const unwrapped = State.unwrap($computed);
|
|
48
|
-
const $$proxy = State.proxy($$writable, {
|
|
49
|
-
get(current) {
|
|
50
|
-
return current.someValue;
|
|
51
|
-
},
|
|
52
|
-
set(value, update) {
|
|
53
|
-
update((current) => {
|
|
54
|
-
return { ...current, someValue: value };
|
|
55
|
-
});
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
const $multiComputed = State.from($one, $$two, $three, (one, two, three, ctx) => {
|
|
59
|
-
// ctx.lastValues = [oldOne, oldTwo, oldThree];
|
|
60
|
-
// ctx.lastReturned = oldOne + oldTwo + oldThree
|
|
61
|
-
return one + two + three;
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
$$writable.get();
|
|
65
|
-
$$writable.set({ someValue: 12, otherValue: null });
|
|
66
|
-
$$writable.update((current) => ({ ...current, someValue: 100 }));
|
|
67
|
-
|
|
68
|
-
$readable.get();
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Now we have one state primitive (`State`), all instances of which implement `Readable` and some of which implement `Writable`. All utility functions are under the same namespace. This also avoids conflicts with Node streams' Readable and Writable which can be an issue with automatic imports.
|