@manyducks.co/dolla 0.68.1 → 0.69.0
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 +133 -107
- package/lib/app.d.ts +13 -73
- package/lib/index.d.ts +7 -9
- package/lib/index.js +888 -1097
- package/lib/index.js.map +4 -4
- package/lib/nodes/observer.d.ts +1 -1
- package/lib/nodes/outlet.d.ts +1 -1
- package/lib/nodes/repeat.d.ts +1 -1
- package/lib/spring.d.ts +0 -40
- package/lib/state.d.ts +54 -36
- package/lib/store.d.ts +12 -3
- package/lib/stores/language.d.ts +5 -9
- package/lib/stores/router.d.ts +17 -16
- package/lib/types.d.ts +4 -12
- package/lib/view.d.ts +12 -3
- package/notes/state.md +71 -0
- package/notes/views.md +28 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,35 +9,54 @@ Dolla is a frontend framework that covers the common needs of complex apps, such
|
|
|
9
9
|
|
|
10
10
|
Dolla gives you a set of composable state container primitives. Everything that happens in your app is a direct result of a value changing inside one of these containers. There is no VDOM. There is no other way to make the app function than to use these containers correctly. However, the advantage is that state, transformations and their side effects are expressed right in front of your eyes rather than being hidden deep in the framework. It's a bit more work to understand up front, but when you do the whole app becomes easier to understand and maintain.
|
|
11
11
|
|
|
12
|
+
A Dolla app is like a house. In this house, State is to data as pipes are to water. Views are appliances that receive that data and make it do something for the user. ShowerView sprays liquid data over their head. FreezerView makes data ice cubes for later. Stores are parts of this system the user doesn't interact with directly, but that hold or process data. WaterHeaterStore keeps data nice and hot for ShowerView and SinkView. SewerStore drains used data away from the app for further processing.
|
|
13
|
+
|
|
14
|
+
But if you're reading this, you're probably a programmer and not a plumber. All of this is to say, State is a static structure that moves a constantly changing stream of data between Views where data informs the state of DOM nodes the user sees and interacts with. Stores are a type of stateful data component that can be used to share data between Views or provide methods to abstract away interacting with an API.
|
|
15
|
+
|
|
12
16
|
Let's first get into some examples.
|
|
13
17
|
|
|
14
18
|
## State
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
States come in two varieties, each with a constructor function and a TypeScript type to match. These are:
|
|
21
|
+
|
|
22
|
+
- `Readable<T>`, which has only a `.get()` method that returns the current value.
|
|
23
|
+
- `Writable<T>`, which extends `Readable<T>` and adds a couple methods:
|
|
24
|
+
- `.set(value: T)` to replace the stored value.
|
|
25
|
+
- `.update(callback: (current: T) => T)` which takes a function that receives the current value and returns a new one.
|
|
17
26
|
|
|
18
|
-
|
|
27
|
+
The constructor functions are `$` for `Readable`s and `$$` for `Writable`s. By convention, the names for each are prefixed with the same number of `$`s to indicate its type. This makes the data flow in code a lot easier to understand at a glance.
|
|
19
28
|
|
|
20
29
|
```js
|
|
21
|
-
|
|
30
|
+
import { $, $$ } from "@manyducks.co/dolla";
|
|
31
|
+
|
|
32
|
+
// By convention, Writable names are prefixed with two dollar signs and Readable with one.
|
|
33
|
+
const $$number = $$(5);
|
|
22
34
|
|
|
23
35
|
// Returns the current value held by the Writable.
|
|
24
36
|
$$number.get();
|
|
25
|
-
|
|
26
37
|
// Stores a new value to the Writable.
|
|
27
38
|
$$number.set(12);
|
|
28
|
-
|
|
29
39
|
// Uses a callback to update the value. Takes the current value and returns the next.
|
|
30
40
|
$$number.update((current) => current + 1);
|
|
41
|
+
|
|
42
|
+
// Convert to a read-only Readable with the same live value.
|
|
43
|
+
const $readOnlyNumber = $($$number);
|
|
44
|
+
|
|
45
|
+
// Derive a new state from an existing one.
|
|
46
|
+
const $doubled = $($$number, (value) => value * 2);
|
|
47
|
+
$doubled.get(); // 26 ($$number is 13)
|
|
48
|
+
|
|
49
|
+
// Derive one new state from the latest values of many other states.
|
|
50
|
+
const $many = $($$number, $doubled, (num, doubled) => num + doubled);
|
|
31
51
|
```
|
|
32
52
|
|
|
33
|
-
For
|
|
53
|
+
Now how do we use it? For a real example, a simple greeter app. The user types their name into a text input and that value is reflected in a heading above the input. For this we will use the `writable` function to create a state container. That container can be slotted into our JSX as a text node or DOM property. Any changes to the value will now be reflected in the DOM.
|
|
34
54
|
|
|
35
55
|
```jsx
|
|
36
|
-
import {
|
|
56
|
+
import { $$ } from "@manyducks.co/dolla";
|
|
37
57
|
|
|
38
58
|
function UserView() {
|
|
39
|
-
|
|
40
|
-
const $$name = writable("Valued Customer");
|
|
59
|
+
const $$name = $$("Valued Customer");
|
|
41
60
|
|
|
42
61
|
return (
|
|
43
62
|
<section>
|
|
@@ -56,31 +75,16 @@ function UserView() {
|
|
|
56
75
|
}
|
|
57
76
|
```
|
|
58
77
|
|
|
59
|
-
### Readables
|
|
60
|
-
|
|
61
|
-
Readables are like Writables with only a `get` function. Typically, readables are derived from a Writable or derived from other states with `computed`.
|
|
62
|
-
|
|
63
|
-
```js
|
|
64
|
-
import { writable, readable } from "@manyducks.co/dolla";
|
|
65
|
-
|
|
66
|
-
const $$value = writable("This is the value.");
|
|
67
|
-
|
|
68
|
-
// By convention Readable names start with '$'.
|
|
69
|
-
const $value = readable($$value);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
You can now safely pass `$value` around without worrying about that code changing it. `$value` will always reflect the value of `$$value`.
|
|
73
|
-
|
|
74
78
|
### Computed
|
|
75
79
|
|
|
76
80
|
Computed states take one or more Readables or Writables and produce a new value _computed_ from those.
|
|
77
81
|
|
|
78
82
|
```js
|
|
79
|
-
import {
|
|
83
|
+
import { $, $$ } from "@manyducks.co/dolla";
|
|
80
84
|
|
|
81
|
-
const $$count =
|
|
85
|
+
const $$count = $$(100);
|
|
82
86
|
|
|
83
|
-
const $double =
|
|
87
|
+
const $double = $($$count, (value) => value * 2);
|
|
84
88
|
```
|
|
85
89
|
|
|
86
90
|
In that example, `$$double` will always have a value derived from that of `$$count`.
|
|
@@ -88,13 +92,13 @@ In that example, `$$double` will always have a value derived from that of `$$cou
|
|
|
88
92
|
Let's look at a more typical example where we're basically joining two pieces of data; a list of users and the ID of the selected user.
|
|
89
93
|
|
|
90
94
|
```js
|
|
91
|
-
import {
|
|
95
|
+
import { $, $$ } from "@manyducks.co/dolla";
|
|
92
96
|
|
|
93
97
|
// Let's assume this list of users was fetched from an API somewhere.
|
|
94
|
-
const $$people =
|
|
98
|
+
const $$people = $$([
|
|
95
99
|
{
|
|
96
100
|
id: 1,
|
|
97
|
-
name: "
|
|
101
|
+
name: "Borb",
|
|
98
102
|
},
|
|
99
103
|
{
|
|
100
104
|
id: 2,
|
|
@@ -107,15 +111,15 @@ const $$people = writable([
|
|
|
107
111
|
]);
|
|
108
112
|
|
|
109
113
|
// Let's assume this ID was chosen from an input where the above users were displayed.
|
|
110
|
-
const $$selectedId =
|
|
114
|
+
const $$selectedId = $$(2);
|
|
111
115
|
|
|
112
116
|
// Now we get the object of the person who is selected.
|
|
113
|
-
const $selectedPerson =
|
|
117
|
+
const $selectedPerson = $($$people, $$selectedId, (people, selectedId) => {
|
|
114
118
|
return people.find((person) => person.id === selectedId);
|
|
115
119
|
});
|
|
116
120
|
|
|
117
121
|
// Now we get a Readable of just that person's name. Say we're going to display it on the page somewhere.
|
|
118
|
-
const $personName =
|
|
122
|
+
const $personName = $($selectedPerson, (person) => person.name);
|
|
119
123
|
|
|
120
124
|
console.log($personName.get()); // "Bex"
|
|
121
125
|
```
|
|
@@ -127,12 +131,12 @@ Notice that the structure above composes a data pipeline; if any of the data cha
|
|
|
127
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.
|
|
128
132
|
|
|
129
133
|
```js
|
|
130
|
-
import {
|
|
134
|
+
import { unwrap } from "@manyducks.co/dolla";
|
|
131
135
|
|
|
132
|
-
const $$number =
|
|
136
|
+
const $$number = $$(5);
|
|
133
137
|
|
|
134
138
|
unwrap($$number); // 5
|
|
135
|
-
unwrap(readable(5)); // 5
|
|
139
|
+
unwrap(State.readable(5)); // 5
|
|
136
140
|
unwrap(5); // 5
|
|
137
141
|
```
|
|
138
142
|
|
|
@@ -177,7 +181,7 @@ function ListItemView(props) {
|
|
|
177
181
|
}
|
|
178
182
|
```
|
|
179
183
|
|
|
180
|
-
As you may have guessed, you can pass
|
|
184
|
+
As you may have guessed, you can pass States as props and slot them in in exactly the same way. This is important because Views do not re-render the way you might expect from other frameworks. Whatever you pass as props is what the View gets for its entire lifecycle.
|
|
181
185
|
|
|
182
186
|
### View Helpers
|
|
183
187
|
|
|
@@ -213,7 +217,7 @@ The `repeat` helper repeats a render function for each item in a list. The `keyF
|
|
|
213
217
|
|
|
214
218
|
```jsx
|
|
215
219
|
function RepeatedListView() {
|
|
216
|
-
const $items =
|
|
220
|
+
const $items = $(["Squirrel", "Chipmunk", "Groundhog"]);
|
|
217
221
|
|
|
218
222
|
return (
|
|
219
223
|
<ul>
|
|
@@ -332,7 +336,7 @@ function ExampleView(props, ctx) {
|
|
|
332
336
|
}
|
|
333
337
|
```
|
|
334
338
|
|
|
335
|
-
#### Observing
|
|
339
|
+
#### Observing States
|
|
336
340
|
|
|
337
341
|
The `observe` function starts observing when the view is connected and stops when disconnected. This takes care of cleaning up observers so you don't have to worry about memory leaks.
|
|
338
342
|
|
|
@@ -353,10 +357,10 @@ function ExampleView(props, ctx) {
|
|
|
353
357
|
Putting it all together, we have a view that maintains a counter. The user sees the current count displayed, and below it three buttons; one to increment by 1, one to decrement by 1, and one to reset the value to 0.
|
|
354
358
|
|
|
355
359
|
```jsx
|
|
356
|
-
import {
|
|
360
|
+
import { $$ } from "@manyducks.co/dolla";
|
|
357
361
|
|
|
358
362
|
function CounterView(props, ctx) {
|
|
359
|
-
const $$count =
|
|
363
|
+
const $$count = $$(0);
|
|
360
364
|
|
|
361
365
|
function increment() {
|
|
362
366
|
$$count.update((n) => n + 1);
|
|
@@ -392,9 +396,9 @@ Stores are accessed with the `getStore` function available on the context object
|
|
|
392
396
|
Stores are helpful for managing persistent state that needs to be accessed in many places.
|
|
393
397
|
|
|
394
398
|
```js
|
|
395
|
-
import {
|
|
399
|
+
import { App } from "@manyducks.co/dolla";
|
|
396
400
|
|
|
397
|
-
const app =
|
|
401
|
+
const app = App();
|
|
398
402
|
|
|
399
403
|
// We define a store that just exports a message.
|
|
400
404
|
function MessageStore() {
|
|
@@ -476,9 +480,9 @@ function LayoutView() {
|
|
|
476
480
|
## Apps and Routing
|
|
477
481
|
|
|
478
482
|
```jsx
|
|
479
|
-
import {
|
|
483
|
+
import { App } from "@manyducks.co/dolla";
|
|
480
484
|
|
|
481
|
-
const app =
|
|
485
|
+
const app = App({
|
|
482
486
|
// Debug options control what gets printed from messages logged through view and store contexts.
|
|
483
487
|
debug: {
|
|
484
488
|
// A comma-separated list of filters. '*' means allow everything and '-dolla/*' means suppress messages with labels beginning with 'dolla/'.
|
|
@@ -495,63 +499,80 @@ const app = makeApp({
|
|
|
495
499
|
error: true,
|
|
496
500
|
},
|
|
497
501
|
|
|
498
|
-
// Router options control how routes are matched
|
|
499
|
-
router: {
|
|
500
|
-
hash: true, // Use hash-based routing
|
|
501
|
-
},
|
|
502
|
-
|
|
503
502
|
mode: "development", // or "production" (enables additional debug features and logging in "development")
|
|
503
|
+
|
|
504
|
+
view: (_, ctx) => {
|
|
505
|
+
// Define a custom root view. By default this just renders any routes like so:
|
|
506
|
+
return ctx.outlet();
|
|
507
|
+
},
|
|
504
508
|
});
|
|
505
509
|
```
|
|
506
510
|
|
|
507
|
-
####
|
|
511
|
+
#### Routes and Outlets
|
|
508
512
|
|
|
509
513
|
The main view (defined with the app's `main` method) is the top-level view that will always be displayed while the app is connected.
|
|
510
514
|
|
|
511
515
|
```jsx
|
|
512
|
-
// Here is a hypothetical main view with a layout and navigation:
|
|
513
|
-
app
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
<
|
|
517
|
-
<
|
|
518
|
-
<
|
|
519
|
-
<
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
<
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
516
|
+
// Here is an app with a hypothetical main view with a layout and navigation:
|
|
517
|
+
const app = App({
|
|
518
|
+
view: (_, ctx) => {
|
|
519
|
+
return (
|
|
520
|
+
<div class="todo-layout">
|
|
521
|
+
<nav>
|
|
522
|
+
<ul>
|
|
523
|
+
<li>
|
|
524
|
+
<a href="/tasks">Tasks</a>
|
|
525
|
+
</li>
|
|
526
|
+
<li>
|
|
527
|
+
<a href="/completed">Completed</a>
|
|
528
|
+
</li>
|
|
529
|
+
</ul>
|
|
530
|
+
</nav>
|
|
531
|
+
{/*
|
|
532
|
+
* An outlet is where children of a view are shown.
|
|
533
|
+
* Because this is a main view, children in this case
|
|
534
|
+
* are the views that correspond to matched routes.
|
|
535
|
+
*/}
|
|
536
|
+
{ctx.outlet()}
|
|
537
|
+
</div>
|
|
538
|
+
);
|
|
539
|
+
},
|
|
534
540
|
});
|
|
535
541
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
542
|
+
app.addStore(RouterStore, {
|
|
543
|
+
hash: true, // Use hash-based routing (default false)
|
|
544
|
+
|
|
545
|
+
// Here are a couple of routes to be rendered into our layout:
|
|
546
|
+
routes: [
|
|
547
|
+
{ path: "/tasks", view: TasksView },
|
|
548
|
+
{ path: "/completed", view: CompletedView },
|
|
549
|
+
],
|
|
550
|
+
});
|
|
539
551
|
```
|
|
540
552
|
|
|
541
553
|
Routes can also be nested. Just like the main view and its routes, subroutes will be displayed in the outlet of their parent view.
|
|
542
554
|
|
|
543
555
|
```jsx
|
|
544
|
-
app.
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
556
|
+
app.addStore(RouterStore, {
|
|
557
|
+
routes: [
|
|
558
|
+
{
|
|
559
|
+
path: "/tasks",
|
|
560
|
+
view: TasksView,
|
|
561
|
+
routes: [
|
|
562
|
+
{ path: "/", view: TaskListView },
|
|
563
|
+
|
|
564
|
+
// In routes, `{value}` is a dynamic value that matches anything,
|
|
565
|
+
// and `{#value}` is a dynamic value that matches a number.
|
|
566
|
+
{ path: "/{#id}", view: TaskDetailsView },
|
|
567
|
+
{ path: "/{#id}/edit", view: TaskEditView },
|
|
568
|
+
|
|
569
|
+
// If the route is any other than the ones defined above, redirect to the list.
|
|
570
|
+
// Redirects support './' and '../' style relative paths.
|
|
571
|
+
{ path: "*", redirect: "./" },
|
|
572
|
+
],
|
|
573
|
+
},
|
|
574
|
+
{ path: "/completed", view: CompletedView },
|
|
575
|
+
],
|
|
555
576
|
});
|
|
556
577
|
```
|
|
557
578
|
|
|
@@ -561,11 +582,9 @@ Dolla makes heavy use of client-side routing. You can define as many routes as y
|
|
|
561
582
|
will determine which one the app shows at any given time. By building an app around routes, lots of things one expects
|
|
562
583
|
from a web app will just work; back and forward buttons, sharable URLs, bookmarks, etc.
|
|
563
584
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
order-based routers like that of `express`. On the other hand, order-based routers can support regular expressions as
|
|
568
|
-
patterns which Dolla's router cannot.
|
|
585
|
+
Routes are matched by highest specificity regardless of the order they were registered.
|
|
586
|
+
This avoids some confusing situations that come up with order-based routers like that of `express`.
|
|
587
|
+
On the other hand, order-based routers can support regular expressions as patterns which Dolla's router cannot.
|
|
569
588
|
|
|
570
589
|
#### Route Patterns
|
|
571
590
|
|
|
@@ -584,31 +603,38 @@ to your code (`router` store, `$params` readable). Below are some examples of pa
|
|
|
584
603
|
Now, here are some route examples in the context of an app:
|
|
585
604
|
|
|
586
605
|
```js
|
|
606
|
+
import { App, RouterStore } from "@manyducks.co/dolla";
|
|
587
607
|
import { PersonDetails, ThingIndex, ThingDetails, ThingEdit, ThingDelete } from "./components.js";
|
|
588
608
|
|
|
589
|
-
const app =
|
|
590
|
-
|
|
591
|
-
app
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
609
|
+
const app = App();
|
|
610
|
+
|
|
611
|
+
app.addStore(RouterStore, {
|
|
612
|
+
routes: [
|
|
613
|
+
{ path: "/people/{name}", view: PersonDetails },
|
|
614
|
+
{
|
|
615
|
+
// A `null` component with subroutes acts as a namespace for those subroutes.
|
|
616
|
+
// Passing a view instead of `null` results in subroutes being rendered inside that view wherever `ctx.outlet()` is called.
|
|
617
|
+
path: "/things",
|
|
618
|
+
view: null,
|
|
619
|
+
routes: [
|
|
620
|
+
{ path: "/", view: ThingIndex }, // matches `/things`
|
|
621
|
+
{ path: "/{#id}", view: ThingDetails }, // matches `/things/{#id}`
|
|
622
|
+
{ path: "/{#id}/edit", view: ThingEdit }, // matches `/things/{#id}/edit`
|
|
623
|
+
{ path: "/{#id}/delete", view: ThingDelete }, // matches `/things/{#id}/delete`
|
|
624
|
+
],
|
|
625
|
+
},
|
|
626
|
+
],
|
|
627
|
+
});
|
|
602
628
|
```
|
|
603
629
|
|
|
604
630
|
As you may have inferred from the code above, when the URL matches a pattern the corresponding view is displayed. If we
|
|
605
631
|
visit `/people/john`, we will see the `PersonDetails` view and the params will be `{ name: "john" }`. Params can be
|
|
606
|
-
accessed inside those views through
|
|
632
|
+
accessed inside those views through `RouterStore`.
|
|
607
633
|
|
|
608
634
|
```js
|
|
609
635
|
function PersonDetails(props, ctx) {
|
|
610
636
|
// `router` store allows you to work with the router from inside the app.
|
|
611
|
-
const router = ctx.getStore(
|
|
637
|
+
const router = ctx.getStore(RouterStore);
|
|
612
638
|
|
|
613
639
|
// Info about the current route is exported as a set of Readables. Query params are also Writable through $$query:
|
|
614
640
|
const { $path, $pattern, $params, $$query } = router;
|
package/lib/app.d.ts
CHANGED
|
@@ -2,19 +2,25 @@ import { CrashCollector } from "./classes/CrashCollector.js";
|
|
|
2
2
|
import { DebugHub, type DebugOptions } from "./classes/DebugHub.js";
|
|
3
3
|
import { DOMHandle } from "./markup.js";
|
|
4
4
|
import { initStore, type Store } from "./store.js";
|
|
5
|
-
import { type LanguageConfig } from "./stores/language.js";
|
|
6
|
-
import { type RedirectContext, type RouterOptions } from "./stores/router.js";
|
|
7
5
|
import { type BuiltInStores } from "./types.js";
|
|
8
6
|
import { type View } from "./view.js";
|
|
9
|
-
interface
|
|
7
|
+
interface StoreConfig<O, E> {
|
|
8
|
+
store: Store<O, E>;
|
|
9
|
+
options?: O;
|
|
10
|
+
}
|
|
11
|
+
interface IAppOptions {
|
|
10
12
|
/**
|
|
11
13
|
* Options for the debug system.
|
|
12
14
|
*/
|
|
13
15
|
debug?: DebugOptions;
|
|
14
16
|
/**
|
|
15
|
-
*
|
|
17
|
+
* The view to be rendered by the app.
|
|
18
|
+
*/
|
|
19
|
+
view?: View<{}>;
|
|
20
|
+
/**
|
|
21
|
+
* App-level stores.
|
|
16
22
|
*/
|
|
17
|
-
|
|
23
|
+
stores?: StoreConfig<any, any>[];
|
|
18
24
|
/**
|
|
19
25
|
* Configures the app based on the environment it's running in.
|
|
20
26
|
*/
|
|
@@ -42,80 +48,14 @@ export interface StoreRegistration<O = any> {
|
|
|
42
48
|
options?: O;
|
|
43
49
|
instance?: ReturnType<typeof initStore>;
|
|
44
50
|
}
|
|
45
|
-
interface AppRouter {
|
|
46
|
-
/**
|
|
47
|
-
* Adds a new pattern, a view to display while that pattern matches the current URL, and an optional function to configure route chaining.
|
|
48
|
-
* Route chaining allows you to add nested routes and redirects that are displayed within the `view`'s outlet while `pattern` matches the current URL.
|
|
49
|
-
*
|
|
50
|
-
* @param pattern - A URL pattern to match against the current URL.
|
|
51
|
-
* @param view - The view to display while `pattern` matches the current URL.
|
|
52
|
-
* @param subroutes - A callback that takes a router object. Use this to append nested routes and redirects.
|
|
53
|
-
*/
|
|
54
|
-
route<I>(pattern: string, view: View<I>, subroutes?: (router: AppRouter) => void): this;
|
|
55
|
-
/**
|
|
56
|
-
* Adds a new pattern and chains a set of nested routes that are displayed without a layout `view`.
|
|
57
|
-
*
|
|
58
|
-
* @param pattern - A URL pattern to match against the current URL.
|
|
59
|
-
* @param view - Pass null to render subroutes without a parent view.
|
|
60
|
-
* @param subroutes - A callback that takes a router object. Use this to append nested routes and redirects.
|
|
61
|
-
*/
|
|
62
|
-
route(pattern: string, view: null, subroutes: (router: AppRouter) => void): this;
|
|
63
|
-
/**
|
|
64
|
-
* Adds a new pattern that will redirect to a different route when matched.
|
|
65
|
-
*
|
|
66
|
-
* @param pattern - A URL pattern to match against the current URL.
|
|
67
|
-
* @param redirectPath - A path to redirect to when `pattern` matches the current URL.
|
|
68
|
-
*/
|
|
69
|
-
redirect(pattern: string, redirectPath: string): this;
|
|
70
|
-
/**
|
|
71
|
-
* Adds a new pattern that will redirect to a different route when matched, as calculated by a callback function.
|
|
72
|
-
* Useful when you require more insight into the path that matched the pattern before deciding where to send the user.
|
|
73
|
-
*
|
|
74
|
-
* @param pattern - A URL pattern to match against the current URL.
|
|
75
|
-
* @param createPath - A function that generates a redirect path from the current URL match.
|
|
76
|
-
*/
|
|
77
|
-
redirect(pattern: string, createPath: (ctx: RedirectContext) => string): this;
|
|
78
|
-
}
|
|
79
51
|
interface ConfigureContext {
|
|
80
52
|
}
|
|
81
53
|
type ConfigureCallback = (ctx: ConfigureContext) => void | Promise<void>;
|
|
82
|
-
export interface
|
|
54
|
+
export interface IApp {
|
|
83
55
|
readonly isConnected: boolean;
|
|
84
|
-
/**
|
|
85
|
-
* Displays view at the root of the app. All other routes render inside this view's outlet.
|
|
86
|
-
*/
|
|
87
|
-
main<A extends Record<string, any>>(view: View<A>, attributes?: A): this;
|
|
88
56
|
/**
|
|
89
57
|
* Makes this store accessible from any other component in the app, except for stores registered before this one.
|
|
90
58
|
*/
|
|
91
|
-
store<O>(store: Store<O, any>, options?: O): this;
|
|
92
|
-
/**
|
|
93
|
-
* Returns the shared instance of `store`.
|
|
94
|
-
*/
|
|
95
|
-
getStore<T extends Store<any, any>>(store: T): ReturnType<T>;
|
|
96
|
-
/**
|
|
97
|
-
* Returns the shared instance of a built-in store.
|
|
98
|
-
*/
|
|
99
|
-
getStore<N extends keyof BuiltInStores>(name: N): BuiltInStores[N];
|
|
100
|
-
/**
|
|
101
|
-
* Adds a new language translation to the app.
|
|
102
|
-
*
|
|
103
|
-
* @param tag - A valid BCP47 language tag, like `en-US`, `en-GB`, `ja`, etc.
|
|
104
|
-
* @param config - Language configuration.
|
|
105
|
-
*/
|
|
106
|
-
language(tag: string, config: LanguageConfig): this;
|
|
107
|
-
/**
|
|
108
|
-
* Sets the initial language. The app will default to the first language added if this is not called.
|
|
109
|
-
*/
|
|
110
|
-
setLanguage(tag: string): this;
|
|
111
|
-
/**
|
|
112
|
-
* Sets the initial language based on the user's locale.
|
|
113
|
-
* Falls back to `fallback` language if provided, otherwise falls back to the first language added.
|
|
114
|
-
*
|
|
115
|
-
* @param tag - Set to "auto" to autodetect the user's language.
|
|
116
|
-
* @param fallback - The language tag to default to if the app fails to detect an appropriate language.
|
|
117
|
-
*/
|
|
118
|
-
setLanguage(tag: "auto", fallback?: string): this;
|
|
119
59
|
/**
|
|
120
60
|
* Runs `callback` after app-level stores are connected to the app, but before views are connected to the DOM.
|
|
121
61
|
* Use this function to run async configuration code before displaying content to the user.
|
|
@@ -134,5 +74,5 @@ export interface App extends AppRouter {
|
|
|
134
74
|
*/
|
|
135
75
|
disconnect(): Promise<void>;
|
|
136
76
|
}
|
|
137
|
-
export declare function
|
|
77
|
+
export declare function App(options?: IAppOptions): IApp;
|
|
138
78
|
export {};
|
package/lib/index.d.ts
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export { readable, writable, computed, proxy, observe, unwrap, isReadable, isWritable } from "./state.js";
|
|
1
|
+
export { App } from "./app.js";
|
|
2
|
+
export { $, $$, observe, unwrap, isReadable, isWritable, type Readable, type Writable } from "./state.js";
|
|
4
3
|
export { m, cond, repeat, portal } from "./markup.js";
|
|
5
4
|
export { Fragment } from "./views/fragment.js";
|
|
6
|
-
export { StoreScope } from "./views/store-scope.js";
|
|
7
|
-
export
|
|
8
|
-
export
|
|
9
|
-
export type
|
|
10
|
-
export
|
|
5
|
+
export { StoreScope, type StoreScopeProps } from "./views/store-scope.js";
|
|
6
|
+
export { RouterStore } from "./stores/router.js";
|
|
7
|
+
export { LanguageStore } from "./stores/language.js";
|
|
8
|
+
export { HTTPStore, type HTTPMiddleware } from "./stores/http.js";
|
|
9
|
+
export { DialogStore, type DialogProps } from "./stores/dialog.js";
|
|
11
10
|
export type { ViewContext } from "./view.js";
|
|
12
11
|
export type { StoreContext } from "./store.js";
|
|
13
12
|
export type { Markup } from "./markup.js";
|
|
14
|
-
export type { HTTPMiddleware } from "./stores/http.js";
|
|
15
13
|
export type { InputType, Renderable } from "./types.js";
|
|
16
14
|
import type { IntrinsicElements as Elements } from "./types";
|
|
17
15
|
declare global {
|