effer 0.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/.codesandbox/icon.png +0 -0
- package/.codesandbox/tasks.json +12 -0
- package/.codesandbox/template.json +7 -0
- package/.devcontainer/devcontainer.json +22 -0
- package/.eslintrc.json +12 -0
- package/.tsbuildinfo/build.tsbuildinfo +1 -0
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/build/cjs/index.js +208 -0
- package/build/cjs/index.js.map +1 -0
- package/build/dts/index.d.ts +169 -0
- package/build/dts/index.d.ts.map +1 -0
- package/build/esm/index.js +195 -0
- package/build/esm/index.js.map +1 -0
- package/eslint.config.mjs +121 -0
- package/package.json +77 -0
- package/setupTests.ts +3 -0
- package/src/index.ts +239 -0
- package/test/index.test.ts +3 -0
- package/tsconfig.base.json +40 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +8 -0
- package/tsconfig.src.json +11 -0
- package/tsconfig.test.json +14 -0
- package/vitest.config.ts +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Effer
|
|
2
|
+
|
|
3
|
+
An Effect native UI library based on lit-html.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
WIP.
|
|
8
|
+
|
|
9
|
+
## Creating a Counter with Effer
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// INSIDE counter.ts
|
|
15
|
+
|
|
16
|
+
import { Data, Effect } from "effect";
|
|
17
|
+
import { Effer, html, makeReducer } from "effer";
|
|
18
|
+
|
|
19
|
+
type Msg = Data.TaggedEnum<{
|
|
20
|
+
Increment: {};
|
|
21
|
+
Decrement: {};
|
|
22
|
+
}>
|
|
23
|
+
const { Increment, Decrement, $match } = Data.taggedEnum<Msg>()
|
|
24
|
+
|
|
25
|
+
const makeCounterState = makeReducer(
|
|
26
|
+
0,
|
|
27
|
+
(state: number, msg: Msg) => $match({
|
|
28
|
+
Increment: () => Effect.succeed(state + 1),
|
|
29
|
+
Decrement: () => Effect.succeed(state - 1),
|
|
30
|
+
})(msg)
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
export class CounterService extends Effect.Service<CounterService>()('CounterService', {
|
|
34
|
+
effect: makeCounterState
|
|
35
|
+
}) {}
|
|
36
|
+
|
|
37
|
+
const _Counter = () => Effect.gen(function*() {
|
|
38
|
+
const { attach, queueMsg } = yield* Effer
|
|
39
|
+
const [counterStream, counterQueue] = yield* CounterService
|
|
40
|
+
|
|
41
|
+
return html`
|
|
42
|
+
<section class="counter-container d-flex flex-row align-items-baseline justify-content-center">
|
|
43
|
+
<button
|
|
44
|
+
class="btn btn-primary btn-sm counter-button"
|
|
45
|
+
id="decButton"
|
|
46
|
+
@click=${queueMsg(counterQueue, () => Increment())}
|
|
47
|
+
>
|
|
48
|
+
- 1
|
|
49
|
+
</button>
|
|
50
|
+
Count is ${yield* attach(counterStream)}
|
|
51
|
+
<button
|
|
52
|
+
class="btn btn-primary btn-sm counter-button"
|
|
53
|
+
id="incButton"
|
|
54
|
+
@click=${queueMsg(counterQueue, () => Decrement())}
|
|
55
|
+
>
|
|
56
|
+
+ 1
|
|
57
|
+
</button>
|
|
58
|
+
</section>
|
|
59
|
+
`
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Optional - make your component a service for ease of dependency management and mocking
|
|
63
|
+
|
|
64
|
+
export class Counter extends Effect.Service<Counter>()('Counter', {
|
|
65
|
+
effect: _Counter(),
|
|
66
|
+
dependencies: [CounterService.Default, Effer.Default]
|
|
67
|
+
}) {}
|
|
68
|
+
|
|
69
|
+
// INSIDE main.ts
|
|
70
|
+
|
|
71
|
+
const ComponentsLayer = Layer.empty.pipe(
|
|
72
|
+
Layer.merge(Counter.Default),
|
|
73
|
+
// ... merge in any other component layers
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
App().pipe(
|
|
77
|
+
Effect.andThen(
|
|
78
|
+
// render our component to the DOM element with ID 'app'
|
|
79
|
+
app => render(app, document.getElementById('app')!)
|
|
80
|
+
),
|
|
81
|
+
Layer.effectDiscard, // transform the render effect into a Layer
|
|
82
|
+
Layer.provide(ComponentsLayer), // merge in Component layers
|
|
83
|
+
Layer.provideMerge(layer), // merge in Effer layer
|
|
84
|
+
Layer.launch, // launch our combined Effer app layer
|
|
85
|
+
BrowserRuntime.runMain
|
|
86
|
+
)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
To bring our UI and business logic together, Effer gives us two tools: attach and queueMsg, both available in the Effer service.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const { attach, queueMsg } = yield* Effer
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
In the UI, we need to represent data changing over time. Effect gives us Streams as a way to do that. The attach method of the Effer service lets you "attach" a stream (or anything that can be converted to a Stream) to the UI, and the UI will automatically display the most up-to-date value of that Stream.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
html`
|
|
100
|
+
Count is ${yield* attach(counterStream)}
|
|
101
|
+
`
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Here is a complete list of what can be attached:
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
type Attachable<A,E,R> =
|
|
108
|
+
| Effect<A,E,R>
|
|
109
|
+
| SubscriptionRef<A>
|
|
110
|
+
| PubSub<A>
|
|
111
|
+
| Queue<A>
|
|
112
|
+
| Stream<A,E,R>
|
|
113
|
+
| Channel<Chunk.Chunk<A>, unknown, E, unknown, unknown, unknown, R>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
When we need to handle events from the UI, we do so with the queueMsg method of the Effer service. This function can go anywhere an event listener callback is expected (like onclick, onchange, etc.). It takes a queue to send the event to, and a function that maps from the DOM event to the queue's event that we want to dispatch:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
html`
|
|
120
|
+
<button
|
|
121
|
+
class="btn btn-primary btn-sm counter-button"
|
|
122
|
+
id="decButton"
|
|
123
|
+
@click=${queueMsg(counterQueue, (e: MouseEvent) => Increment())}
|
|
124
|
+
>
|
|
125
|
+
`
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Managing State
|
|
129
|
+
|
|
130
|
+
### makeReducer - For Complex State or Logic
|
|
131
|
+
|
|
132
|
+
To manage state, Effer provides two helper functions: makeReducer and makeState. These are very similar to useReducer and useState in React, except you use them outside your UI components as part of your business logic.
|
|
133
|
+
|
|
134
|
+
makeReducer lets you define a state and update it using events:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
type Msg = Data.TaggedEnum<{
|
|
138
|
+
Increment: {};
|
|
139
|
+
Decrement: {};
|
|
140
|
+
}>
|
|
141
|
+
const { Increment, Decrement, $match } = Data.taggedEnum<Msg>()
|
|
142
|
+
|
|
143
|
+
const makeCounterState = makeReducer(
|
|
144
|
+
0,
|
|
145
|
+
(state: number, msg: Msg) => $match({
|
|
146
|
+
Increment: () => Effect.succeed(state + 1),
|
|
147
|
+
Decrement: () => Effect.succeed(state - 1),
|
|
148
|
+
})(msg)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
// Making our state values a Service so we can easily pass it around
|
|
152
|
+
export class CounterService extends Effect.Service<CounterService>()('CounterService', {
|
|
153
|
+
effect: makeCounterState
|
|
154
|
+
}) {}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
We define the expected update messages as Increment and Decrement, and we provide a function that takes the old state and a message, and provides a new updated state. Now when we inject the service, we will get the stream of values as well as a queue to send updates to:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
// counterQueue will accept either Increment or Decrement and the stream will update
|
|
161
|
+
// according to the update function
|
|
162
|
+
const [counterStream, counterQueue] = yield* CounterService
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### makeState - For Simple State Management
|
|
166
|
+
|
|
167
|
+
makeState is very similar, but more simplified. We just provide an initial state, and the queue will accept new state values instead of messages.
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const makeCounterState = makeState(0)
|
|
171
|
+
|
|
172
|
+
// Making our state values a Service so we can easily pass it around
|
|
173
|
+
export class CounterService extends Effect.Service<CounterService>()('CounterService', {
|
|
174
|
+
effect: makeCounterState
|
|
175
|
+
}) {}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
// the counterQueue now accepts a number (the new count) instead of update messages
|
|
180
|
+
const [counterStream, counterQueue] = yield* CounterService
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### makeAsyncResult - For Async State and Logic
|
|
184
|
+
|
|
185
|
+
If we have an effect that as asynchronous, like making an HTTP call, we can wrap that effect in makeAsyncResult:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const posts = yield* makeAsyncResult(getPostsAsyncEffect) // an async effect wrapped in makeAsyncResult
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
When you wrap an `Effect<A,E,R>` in makeAsyncResult, you get 3 things. The first is a `Stream<Result<A,E>, never, R>` where `Result<A,E>` is:
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
export type Result<A,E> = Data.TaggedEnum<{
|
|
195
|
+
Loading: {}
|
|
196
|
+
Success: { readonly data: A }
|
|
197
|
+
Failure: { readonly error: E }
|
|
198
|
+
}> & {}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The other thing makeAsyncResult gives us is a helper function called `match()` for matching the state of the streaming Result values:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
const posts = yield* makeAsyncResult(getPostsAsyncEffect) // an async effect wrapped in makeAsyncResult
|
|
205
|
+
// mapping the state of our Result to what we want to display on screen
|
|
206
|
+
const postsTable = posts.stream.pipe(
|
|
207
|
+
Stream.map(postsClient.match({
|
|
208
|
+
Loading: () => html`<h1>Loading...</h1>`, // if the async effect is still loading, show this
|
|
209
|
+
Success: ({ data }) => data.map(post => PostCard(post)), // if it loaded successfully, show the PostCard component
|
|
210
|
+
Failure: ({ error }) => html`<p>Error retrieving data: ${error}</p>` // if it errored out, show this
|
|
211
|
+
}))
|
|
212
|
+
)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Note that since `Result<A,E>` is a TaggedEnum, `match()` is exactly the same as the `$match()` function you get from creating a TaggedEnum. See the [Effect Documentation](https://effect.website/docs/data-types/data/#union-of-tagged-structs)
|
|
216
|
+
|
|
217
|
+
## Navigation and URLs
|
|
218
|
+
|
|
219
|
+
Effer offers a NavService for handling things related to navigation and URLs. Here is its interface:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
interface NavService {
|
|
223
|
+
url: Ref.Ref<URL>; // the current URL as a Ref
|
|
224
|
+
pathStream: Stream.Stream<URL>; // a stream of the current URL value for reacting to changes
|
|
225
|
+
getQueryParam: (name: string) => Effect.Effect<string, NoSuchElementException, never> // helper to get a query param from the URL
|
|
226
|
+
navigate: typeof window.navigation.navigate; // the window's navigate() method
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
You can use this inside of an Effect (like an Effer component) to navigate like so:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
export const App = () => Effect.gen(function*() {
|
|
234
|
+
const { pathStream } = yield* NavService // get the pathStream from NavService
|
|
235
|
+
const { attach } = yield* Effer
|
|
236
|
+
// a function that maps from a path string to the Effer component we want to display
|
|
237
|
+
const navFn = (path: string) => {
|
|
238
|
+
switch (path) {
|
|
239
|
+
case '/counters':
|
|
240
|
+
return yield* Counter
|
|
241
|
+
case '/todos':
|
|
242
|
+
return yield* Todos
|
|
243
|
+
case '/posts':
|
|
244
|
+
return yield* Posts
|
|
245
|
+
default:
|
|
246
|
+
return yield* Todos
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// getting the pathname from the pathStream then running that through our nav function
|
|
251
|
+
const page = pathStream.pipe(
|
|
252
|
+
Stream.map(url => url.pathname),
|
|
253
|
+
Stream.map(navFn)
|
|
254
|
+
)
|
|
255
|
+
// attaching the page stream to the template so the current page displays
|
|
256
|
+
return html`
|
|
257
|
+
<main class="w-100">
|
|
258
|
+
${ yield* attach(page) }
|
|
259
|
+
</main>
|
|
260
|
+
`
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
You can also use NavService to retrieve query params from the current URL:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
const {getQueryParam} = yield* NavService
|
|
268
|
+
// Getting a "count" query param and parsing it into an integer
|
|
269
|
+
const startingCount: number = yield* getQueryParam('count').pipe(
|
|
270
|
+
Effect.map(parseInt),
|
|
271
|
+
Effect.orElseSucceed(() => 0)
|
|
272
|
+
)
|
|
273
|
+
```
|
|
274
|
+
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.render = exports.makeState = exports.makeReducer = exports.makeAsyncResult = exports.layer = exports.html = exports.NavService = exports.Effer = exports.AsyncReplaceDirective = void 0;
|
|
7
|
+
var _effect = require("effect");
|
|
8
|
+
var _Cause = require("effect/Cause");
|
|
9
|
+
var _Channel = require("effect/Channel");
|
|
10
|
+
var _Effect = require("effect/Effect");
|
|
11
|
+
var _Predicate = require("effect/Predicate");
|
|
12
|
+
var _Stream = require("effect/Stream");
|
|
13
|
+
var _litHtml = require("lit-html");
|
|
14
|
+
var _asyncReplace = require("lit-html/directives/async-replace.js");
|
|
15
|
+
var Nav = _interopRequireWildcard(require("@typed/navigation"));
|
|
16
|
+
var _id = require("@typed/id");
|
|
17
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
18
|
+
/**
|
|
19
|
+
* Create an HTML template result that can be rendered to the DOM
|
|
20
|
+
*/
|
|
21
|
+
const html = exports.html = _litHtml.html;
|
|
22
|
+
/**
|
|
23
|
+
* Renders a template result to the container
|
|
24
|
+
*/
|
|
25
|
+
const render = exports.render = _litHtml.render;
|
|
26
|
+
class AsyncReplaceDirective extends _asyncReplace.AsyncReplaceDirective {}
|
|
27
|
+
exports.AsyncReplaceDirective = AsyncReplaceDirective;
|
|
28
|
+
const isQueue = val => (0, _Predicate.hasProperty)(val, _effect.Unify.ignoreSymbol) && (0, _Predicate.hasProperty)(val[_effect.Unify.ignoreSymbol], 'Dequeue');
|
|
29
|
+
const isStream = val => (0, _Predicate.hasProperty)(val, _Stream.StreamTypeId);
|
|
30
|
+
const isSubscriptionRef = val => (0, _Predicate.hasProperty)(val, _effect.SubscriptionRef.SubscriptionRefTypeId);
|
|
31
|
+
/**
|
|
32
|
+
* The Effer service provides methods for attaching Attachable values to the template and queueing events
|
|
33
|
+
*/
|
|
34
|
+
class Effer extends /*#__PURE__*/_effect.Effect.Service()('Effer', {
|
|
35
|
+
effect: /*#__PURE__*/_effect.Effect.gen(function* () {
|
|
36
|
+
const attach = val => {
|
|
37
|
+
let stream;
|
|
38
|
+
if ((0, _Channel.isChannel)(val)) {
|
|
39
|
+
stream = _effect.Stream.fromChannel(val);
|
|
40
|
+
} else if (isSubscriptionRef(val)) {
|
|
41
|
+
stream = val.changes;
|
|
42
|
+
} else if ((0, _Effect.isEffect)(val) && !isQueue(val)) {
|
|
43
|
+
stream = _effect.Stream.fromEffect(val);
|
|
44
|
+
} else if (isQueue(val)) {
|
|
45
|
+
stream = _effect.Stream.fromQueue(val);
|
|
46
|
+
} else if (isStream(val)) {
|
|
47
|
+
stream = val;
|
|
48
|
+
} else {
|
|
49
|
+
stream = _effect.Stream.fromPubSub(val);
|
|
50
|
+
}
|
|
51
|
+
return stream.pipe(_effect.Stream.toAsyncIterableEffect, _effect.Effect.andThen(iter => (0, _asyncReplace.asyncReplace)(iter)));
|
|
52
|
+
};
|
|
53
|
+
const queueMsg = (offer, mapper) => {
|
|
54
|
+
if (mapper) {
|
|
55
|
+
return e => offer(mapper(e));
|
|
56
|
+
}
|
|
57
|
+
return offer;
|
|
58
|
+
};
|
|
59
|
+
return {
|
|
60
|
+
/**
|
|
61
|
+
* Attaches any Attachable value to the template:
|
|
62
|
+
* ```ts
|
|
63
|
+
* const Counter = () => Effect.gen(function*() {
|
|
64
|
+
* [ countRef, countQueue ] = yield* CounterService // service made with makeReducer or makeState
|
|
65
|
+
*
|
|
66
|
+
* return html`
|
|
67
|
+
* <p>The count is ${yield* attach(countRef)}</p>
|
|
68
|
+
* `
|
|
69
|
+
* })
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
attach,
|
|
73
|
+
/**
|
|
74
|
+
* Used in place of an event handler callback, this function takes a queue to dispatch messages to,
|
|
75
|
+
* as well as a mapping function from the DOM event to the queue's expected event type
|
|
76
|
+
* ```ts
|
|
77
|
+
* const Counter = () => Effect.gen(function*() {
|
|
78
|
+
* [ countRef, countQueue ] = yield* CounterService // service made with makeReducer
|
|
79
|
+
*
|
|
80
|
+
* return html`
|
|
81
|
+
* <button
|
|
82
|
+
* @click=${queueMsg(countQueue, () => Increment())}
|
|
83
|
+
* > // Increment() is an action defined as part of the CounterService reducer
|
|
84
|
+
* The count is ${yield* attach(countRef)}
|
|
85
|
+
* </button>
|
|
86
|
+
* `
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
queueMsg
|
|
91
|
+
};
|
|
92
|
+
})
|
|
93
|
+
// dependencies: [Registry.layer]
|
|
94
|
+
}) {}
|
|
95
|
+
/**
|
|
96
|
+
* Creates a stream of the latest state value, and a queue to update the value.
|
|
97
|
+
* @param initialState The starting state value
|
|
98
|
+
* @param updateFn An effectful function that takes the old state, an update message, and returns a new state
|
|
99
|
+
* @returns A tuple of the stream of the current state value and a queue to dispatch update messages
|
|
100
|
+
*
|
|
101
|
+
* ```ts
|
|
102
|
+
* type Msg = Data.TaggedEnum<{
|
|
103
|
+
* Increment: {};
|
|
104
|
+
* Decrement: {};
|
|
105
|
+
* }>
|
|
106
|
+
* const { Increment, Decrement, $match } = Data.taggedEnum<Msg>()
|
|
107
|
+
* const counterReducer = (state: number, msg: Msg) => $match({
|
|
108
|
+
* Increment: () => Effect.succeed(state + 1),
|
|
109
|
+
* Decrement: () => Effect.succeed(state - 1)
|
|
110
|
+
* })
|
|
111
|
+
*
|
|
112
|
+
* // Inside an Effect
|
|
113
|
+
* const [ countStream, countQueue ] = yield* makeReducer(0, counterReducer)
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
exports.Effer = Effer;
|
|
117
|
+
const makeReducer = (initialState, updateFn) => _effect.Effect.gen(function* () {
|
|
118
|
+
const subRef = yield* _effect.SubscriptionRef.make(initialState);
|
|
119
|
+
const updateQueue = yield* _effect.Queue.unbounded();
|
|
120
|
+
yield* _effect.Effect.gen(function* () {
|
|
121
|
+
const msg = yield* updateQueue.take;
|
|
122
|
+
yield* _effect.SubscriptionRef.updateEffect(subRef, state => updateFn(state, msg));
|
|
123
|
+
}).pipe(_effect.Effect.forever, _effect.Effect.fork);
|
|
124
|
+
const dispatch = msg => _effect.Queue.unsafeOffer(updateQueue, msg);
|
|
125
|
+
return {
|
|
126
|
+
stream: subRef.changes,
|
|
127
|
+
dispatch
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
exports.makeReducer = makeReducer;
|
|
131
|
+
const makeState = initialState => _effect.Effect.gen(function* () {
|
|
132
|
+
const subRef = yield* _effect.SubscriptionRef.make(initialState);
|
|
133
|
+
const updateQueue = yield* _effect.Queue.unbounded();
|
|
134
|
+
yield* _effect.Effect.gen(function* () {
|
|
135
|
+
const updateFn = yield* updateQueue.take;
|
|
136
|
+
yield* _effect.SubscriptionRef.update(subRef, updateFn);
|
|
137
|
+
}).pipe(_effect.Effect.forever, _effect.Effect.fork);
|
|
138
|
+
const set = val => _effect.Queue.unsafeOffer(updateQueue, _ => val);
|
|
139
|
+
const update = updateFn => _effect.Queue.unsafeOffer(updateQueue, updateFn);
|
|
140
|
+
return {
|
|
141
|
+
stream: subRef.changes,
|
|
142
|
+
set,
|
|
143
|
+
update
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* Effer's service to interact with navigation. Provides the current URL object, a stream of the
|
|
148
|
+
* current app path, a method to get a query param from the URL, and a method to navigate the page.
|
|
149
|
+
*/
|
|
150
|
+
exports.makeState = makeState;
|
|
151
|
+
class NavService extends /*#__PURE__*/_effect.Context.Tag('NavService')() {
|
|
152
|
+
static Live = /*#__PURE__*/_effect.Layer.effect(NavService, /*#__PURE__*/_effect.Effect.gen(function* () {
|
|
153
|
+
const url = yield* _effect.Ref.make(new URL(window.navigation.currentEntry?.url));
|
|
154
|
+
const pathStream = _effect.Stream.fromEventListener(window.navigation, 'navigate').pipe(_effect.Stream.map(e => new URL(e.destination.url)), _effect.Stream.merge(_effect.Stream.make(new URL(window.navigation.currentEntry?.url))), _effect.Stream.tap(u => _effect.Ref.set(url, u)));
|
|
155
|
+
const getQueryParam = name => _effect.Effect.gen(function* () {
|
|
156
|
+
const result = (yield* _effect.Ref.get(url)).searchParams.get(name);
|
|
157
|
+
if (result === null) {
|
|
158
|
+
yield* _effect.Effect.fail(new _Cause.NoSuchElementException());
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
});
|
|
162
|
+
return {
|
|
163
|
+
/**
|
|
164
|
+
* The current URL object
|
|
165
|
+
*/
|
|
166
|
+
url,
|
|
167
|
+
/**
|
|
168
|
+
* A stream of the current app path ('/', '/actuator', etc.)
|
|
169
|
+
*/
|
|
170
|
+
pathStream,
|
|
171
|
+
/**
|
|
172
|
+
* Method used to navigate. Accepts a URL string and navigates the page
|
|
173
|
+
*/
|
|
174
|
+
navigate: window.navigation.navigate,
|
|
175
|
+
/**
|
|
176
|
+
* Get a value from the current URL's query params
|
|
177
|
+
*/
|
|
178
|
+
getQueryParam
|
|
179
|
+
};
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
exports.NavService = NavService;
|
|
183
|
+
const makeAsyncResult = effect => {
|
|
184
|
+
const {
|
|
185
|
+
Loading,
|
|
186
|
+
Success,
|
|
187
|
+
Failure,
|
|
188
|
+
$is,
|
|
189
|
+
$match
|
|
190
|
+
} = _effect.Data.taggedEnum();
|
|
191
|
+
const startStream = _effect.Stream.make(Loading());
|
|
192
|
+
const resultStream = _effect.Stream.asyncPush(emit => _effect.Effect.gen(function* () {
|
|
193
|
+
const result = yield* effect.pipe(_effect.Effect.map(data => Success({
|
|
194
|
+
data
|
|
195
|
+
})), _effect.Effect.mapError(error => Failure({
|
|
196
|
+
error
|
|
197
|
+
})), _effect.Effect.merge);
|
|
198
|
+
emit.single(result);
|
|
199
|
+
}));
|
|
200
|
+
return {
|
|
201
|
+
stream: _effect.Stream.concat(startStream, resultStream),
|
|
202
|
+
is: $is,
|
|
203
|
+
match: $match
|
|
204
|
+
};
|
|
205
|
+
};
|
|
206
|
+
exports.makeAsyncResult = makeAsyncResult;
|
|
207
|
+
const layer = exports.layer = /*#__PURE__*/Effer.Default.pipe(/*#__PURE__*/_effect.Layer.provideMerge(NavService.Live), /*#__PURE__*/_effect.Layer.provide(/*#__PURE__*/Nav.fromWindow(window)), /*#__PURE__*/_effect.Layer.provide(_id.GetRandomValues.CryptoRandom));
|
|
208
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["_effect","require","_Cause","_Channel","_Effect","_Predicate","_Stream","_litHtml","_asyncReplace","Nav","_interopRequireWildcard","_id","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","html","exports","_html","render","_render","AsyncReplaceDirective","_AsyncReplaceDirective","isQueue","val","hasProperty","Unify","ignoreSymbol","isStream","StreamTypeId","isSubscriptionRef","SubscriptionRef","SubscriptionRefTypeId","Effer","Effect","Service","effect","gen","attach","stream","isChannel","Stream","fromChannel","changes","isEffect","fromEffect","fromQueue","fromPubSub","pipe","toAsyncIterableEffect","andThen","iter","asyncReplace","queueMsg","offer","mapper","makeReducer","initialState","updateFn","subRef","make","updateQueue","Queue","unbounded","msg","take","updateEffect","state","forever","fork","dispatch","unsafeOffer","makeState","update","_","NavService","Context","Tag","Live","Layer","url","Ref","URL","window","navigation","currentEntry","pathStream","fromEventListener","map","destination","merge","tap","u","getQueryParam","name","result","searchParams","fail","NoSuchElementException","navigate","makeAsyncResult","Loading","Success","Failure","$is","$match","Data","taggedEnum","startStream","resultStream","asyncPush","emit","data","mapError","error","single","concat","is","match","layer","Default","provideMerge","provide","fromWindow","GetRandomValues","CryptoRandom"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Chunk, Context, Data, Effect, Layer, Queue, Ref, Stream, SubscriptionRef, Unify } from "effect";
|
|
2
|
+
import { NoSuchElementException } from "effect/Cause";
|
|
3
|
+
import { type Channel } from "effect/Channel";
|
|
4
|
+
import { type PubSub } from "effect/PubSub";
|
|
5
|
+
import { type TemplateResult as _TemplateResult } from "lit-html";
|
|
6
|
+
import type { DirectiveClass, DirectiveResult as _DirectiveResult } from "lit-html/directive.js";
|
|
7
|
+
import { AsyncReplaceDirective as _AsyncReplaceDirective } from "lit-html/directives/async-replace.js";
|
|
8
|
+
/**
|
|
9
|
+
* Create an HTML template result that can be rendered to the DOM
|
|
10
|
+
*/
|
|
11
|
+
export declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => _TemplateResult<1>;
|
|
12
|
+
/**
|
|
13
|
+
* Renders a template result to the container
|
|
14
|
+
*/
|
|
15
|
+
export declare const render: {
|
|
16
|
+
(value: unknown, container: import("lit-html").RenderRootNode, options?: import("lit-html").RenderOptions): import("lit-html").RootPart;
|
|
17
|
+
setSanitizer: (newSanitizer: import("lit-html").SanitizerFactory) => void;
|
|
18
|
+
createSanitizer: import("lit-html").SanitizerFactory;
|
|
19
|
+
_testOnlyClearSanitizerFactoryDoNotCallOrElse: () => void;
|
|
20
|
+
};
|
|
21
|
+
export type TemplateResult = _TemplateResult;
|
|
22
|
+
export type DirectiveResult<C extends DirectiveClass = DirectiveClass> = _DirectiveResult<C>;
|
|
23
|
+
export declare class AsyncReplaceDirective extends _AsyncReplaceDirective {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Types that can be attached to the DOM template using Effer's 'attach' method
|
|
27
|
+
*/
|
|
28
|
+
export type Attachable<A, E, R> = Channel<Chunk.Chunk<A>, unknown, E, unknown, unknown, unknown, R> | Effect.Effect<A, E, R> | SubscriptionRef.SubscriptionRef<A> | PubSub<A> | Queue.Queue<A> | Stream.Stream<A, E, R>;
|
|
29
|
+
declare const Effer_base: Effect.Service.Class<Effer, "Effer", {
|
|
30
|
+
readonly effect: Effect.Effect<{
|
|
31
|
+
/**
|
|
32
|
+
* Attaches any Attachable value to the template:
|
|
33
|
+
* ```ts
|
|
34
|
+
* const Counter = () => Effect.gen(function*() {
|
|
35
|
+
* [ countRef, countQueue ] = yield* CounterService // service made with makeReducer or makeState
|
|
36
|
+
*
|
|
37
|
+
* return html`
|
|
38
|
+
* <p>The count is ${yield* attach(countRef)}</p>
|
|
39
|
+
* `
|
|
40
|
+
* })
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
attach: <A, E = never, R = never>(val: Attachable<A, E, R>) => Effect.Effect<_DirectiveResult<typeof _AsyncReplaceDirective>, never, R>;
|
|
44
|
+
/**
|
|
45
|
+
* Used in place of an event handler callback, this function takes a queue to dispatch messages to,
|
|
46
|
+
* as well as a mapping function from the DOM event to the queue's expected event type
|
|
47
|
+
* ```ts
|
|
48
|
+
* const Counter = () => Effect.gen(function*() {
|
|
49
|
+
* [ countRef, countQueue ] = yield* CounterService // service made with makeReducer
|
|
50
|
+
*
|
|
51
|
+
* return html`
|
|
52
|
+
* <button
|
|
53
|
+
* @click=${queueMsg(countQueue, () => Increment())}
|
|
54
|
+
* > // Increment() is an action defined as part of the CounterService reducer
|
|
55
|
+
* The count is ${yield* attach(countRef)}
|
|
56
|
+
* </button>
|
|
57
|
+
* `
|
|
58
|
+
* })
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
queueMsg: <DOMEvent, Msg>(offer: (msg: Msg) => boolean, mapper?: (e: DOMEvent) => Msg) => ((msg: Msg) => boolean) | ((e: DOMEvent) => boolean);
|
|
62
|
+
}, never, never>;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* The Effer service provides methods for attaching Attachable values to the template and queueing events
|
|
66
|
+
*/
|
|
67
|
+
export declare class Effer extends Effer_base {
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Creates a stream of the latest state value, and a queue to update the value.
|
|
71
|
+
* @param initialState The starting state value
|
|
72
|
+
* @param updateFn An effectful function that takes the old state, an update message, and returns a new state
|
|
73
|
+
* @returns A tuple of the stream of the current state value and a queue to dispatch update messages
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* type Msg = Data.TaggedEnum<{
|
|
77
|
+
* Increment: {};
|
|
78
|
+
* Decrement: {};
|
|
79
|
+
* }>
|
|
80
|
+
* const { Increment, Decrement, $match } = Data.taggedEnum<Msg>()
|
|
81
|
+
* const counterReducer = (state: number, msg: Msg) => $match({
|
|
82
|
+
* Increment: () => Effect.succeed(state + 1),
|
|
83
|
+
* Decrement: () => Effect.succeed(state - 1)
|
|
84
|
+
* })
|
|
85
|
+
*
|
|
86
|
+
* // Inside an Effect
|
|
87
|
+
* const [ countStream, countQueue ] = yield* makeReducer(0, counterReducer)
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare const makeReducer: <A, M, E = never, R = never>(initialState: A, updateFn: (state: A, msg: M) => Effect.Effect<A, E, R>) => Effect.Effect<{
|
|
91
|
+
stream: Stream.Stream<A, never, never>;
|
|
92
|
+
dispatch: (msg: M) => boolean;
|
|
93
|
+
}, never, R>;
|
|
94
|
+
export declare const makeState: <A>(initialState: A) => Effect.Effect<{
|
|
95
|
+
readonly stream: Stream.Stream<A, never, never>;
|
|
96
|
+
readonly set: (val: A) => boolean;
|
|
97
|
+
readonly update: (updateFn: (oldValue: A) => A) => boolean;
|
|
98
|
+
}, never, never>;
|
|
99
|
+
declare const NavService_base: Context.TagClass<NavService, "NavService", {
|
|
100
|
+
url: Ref.Ref<URL>;
|
|
101
|
+
pathStream: Stream.Stream<URL>;
|
|
102
|
+
getQueryParam: (name: string) => Effect.Effect<string, NoSuchElementException, never>;
|
|
103
|
+
navigate: typeof window.navigation.navigate;
|
|
104
|
+
}>;
|
|
105
|
+
/**
|
|
106
|
+
* Effer's service to interact with navigation. Provides the current URL object, a stream of the
|
|
107
|
+
* current app path, a method to get a query param from the URL, and a method to navigate the page.
|
|
108
|
+
*/
|
|
109
|
+
export declare class NavService extends NavService_base {
|
|
110
|
+
static Live: Layer.Layer<NavService, never, never>;
|
|
111
|
+
}
|
|
112
|
+
export type RemoteData<T, E> = Data.TaggedEnum<{
|
|
113
|
+
Loading: {};
|
|
114
|
+
Success: {
|
|
115
|
+
readonly data: T;
|
|
116
|
+
};
|
|
117
|
+
Failure: {
|
|
118
|
+
readonly error: E;
|
|
119
|
+
};
|
|
120
|
+
}> & {};
|
|
121
|
+
export declare const makeAsyncResult: <A, E, R>(effect: Effect.Effect<A, E, R>) => {
|
|
122
|
+
stream: Stream.Stream<RemoteData<A, E>, never, R>;
|
|
123
|
+
is: <Tag extends "Loading" | "Success" | "Failure">(tag: Tag) => (u: unknown) => u is Extract<{
|
|
124
|
+
readonly _tag: "Loading";
|
|
125
|
+
}, {
|
|
126
|
+
readonly _tag: Tag;
|
|
127
|
+
}> | Extract<{
|
|
128
|
+
readonly _tag: "Success";
|
|
129
|
+
readonly data: A;
|
|
130
|
+
}, {
|
|
131
|
+
readonly _tag: Tag;
|
|
132
|
+
}> | Extract<{
|
|
133
|
+
readonly _tag: "Failure";
|
|
134
|
+
readonly error: E;
|
|
135
|
+
}, {
|
|
136
|
+
readonly _tag: Tag;
|
|
137
|
+
}>;
|
|
138
|
+
match: {
|
|
139
|
+
<const Cases extends {
|
|
140
|
+
readonly Loading: (args: {
|
|
141
|
+
readonly _tag: "Loading";
|
|
142
|
+
}) => any;
|
|
143
|
+
readonly Success: (args: {
|
|
144
|
+
readonly _tag: "Success";
|
|
145
|
+
readonly data: A;
|
|
146
|
+
}) => any;
|
|
147
|
+
readonly Failure: (args: {
|
|
148
|
+
readonly _tag: "Failure";
|
|
149
|
+
readonly error: E;
|
|
150
|
+
}) => any;
|
|
151
|
+
}>(cases: Cases & { [K in Exclude<keyof Cases, "Loading" | "Success" | "Failure">]: never; }): (value: RemoteData<A, E>) => Unify.Unify<ReturnType<Cases["Loading" | "Success" | "Failure"]>>;
|
|
152
|
+
<const Cases extends {
|
|
153
|
+
readonly Loading: (args: {
|
|
154
|
+
readonly _tag: "Loading";
|
|
155
|
+
}) => any;
|
|
156
|
+
readonly Success: (args: {
|
|
157
|
+
readonly _tag: "Success";
|
|
158
|
+
readonly data: A;
|
|
159
|
+
}) => any;
|
|
160
|
+
readonly Failure: (args: {
|
|
161
|
+
readonly _tag: "Failure";
|
|
162
|
+
readonly error: E;
|
|
163
|
+
}) => any;
|
|
164
|
+
}>(value: RemoteData<A, E>, cases: Cases & { [K in Exclude<keyof Cases, "Loading" | "Success" | "Failure">]: never; }): Unify.Unify<ReturnType<Cases["Loading" | "Success" | "Failure"]>>;
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
export declare const layer: Layer.Layer<Effer | NavService, never, never>;
|
|
168
|
+
export {};
|
|
169
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|