@typed/template 0.6.0 → 0.8.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.
Files changed (96) hide show
  1. package/dist/cjs/ElementRef.js.map +1 -1
  2. package/dist/cjs/ElementSource.js.map +1 -1
  3. package/dist/cjs/Html.js +12 -2
  4. package/dist/cjs/Html.js.map +1 -1
  5. package/dist/cjs/Hydrate.js +15 -7
  6. package/dist/cjs/Hydrate.js.map +1 -1
  7. package/dist/cjs/Many.js.map +1 -1
  8. package/dist/cjs/Render.js +17 -7
  9. package/dist/cjs/Render.js.map +1 -1
  10. package/dist/cjs/RenderTemplate.js.map +1 -1
  11. package/dist/cjs/Test.js +10 -5
  12. package/dist/cjs/Test.js.map +1 -1
  13. package/dist/cjs/internal/hydrate.js +10 -5
  14. package/dist/cjs/internal/hydrate.js.map +1 -1
  15. package/dist/cjs/internal/parts.js.map +1 -1
  16. package/dist/cjs/internal/render.js +8 -5
  17. package/dist/cjs/internal/render.js.map +1 -1
  18. package/dist/cjs/internal/server.js +2 -6
  19. package/dist/cjs/internal/server.js.map +1 -1
  20. package/dist/dts/Directive.d.ts +13 -13
  21. package/dist/dts/Directive.d.ts.map +1 -1
  22. package/dist/dts/ElementRef.d.ts +2 -2
  23. package/dist/dts/ElementRef.d.ts.map +1 -1
  24. package/dist/dts/ElementSource.d.ts +4 -4
  25. package/dist/dts/ElementSource.d.ts.map +1 -1
  26. package/dist/dts/EventHandler.d.ts +11 -11
  27. package/dist/dts/EventHandler.d.ts.map +1 -1
  28. package/dist/dts/Html.d.ts +13 -3
  29. package/dist/dts/Html.d.ts.map +1 -1
  30. package/dist/dts/Hydrate.d.ts +12 -4
  31. package/dist/dts/Hydrate.d.ts.map +1 -1
  32. package/dist/dts/Many.d.ts +8 -8
  33. package/dist/dts/Many.d.ts.map +1 -1
  34. package/dist/dts/Part.d.ts +1 -1
  35. package/dist/dts/Part.d.ts.map +1 -1
  36. package/dist/dts/Placeholder.d.ts +6 -6
  37. package/dist/dts/Placeholder.d.ts.map +1 -1
  38. package/dist/dts/Platform.d.ts +1 -1
  39. package/dist/dts/Platform.d.ts.map +1 -1
  40. package/dist/dts/Render.d.ts +16 -5
  41. package/dist/dts/Render.d.ts.map +1 -1
  42. package/dist/dts/RenderTemplate.d.ts +2 -2
  43. package/dist/dts/RenderTemplate.d.ts.map +1 -1
  44. package/dist/dts/Renderable.d.ts +3 -3
  45. package/dist/dts/Renderable.d.ts.map +1 -1
  46. package/dist/dts/Test.d.ts +10 -14
  47. package/dist/dts/Test.d.ts.map +1 -1
  48. package/dist/dts/internal/EventSource.d.ts +1 -1
  49. package/dist/dts/internal/EventSource.d.ts.map +1 -1
  50. package/dist/dts/internal/hydrate.d.ts.map +1 -1
  51. package/dist/dts/internal/module-augmentation.d.ts +13 -13
  52. package/dist/dts/internal/module-augmentation.d.ts.map +1 -1
  53. package/dist/dts/internal/parts.d.ts +2 -2
  54. package/dist/dts/internal/parts.d.ts.map +1 -1
  55. package/dist/dts/internal/render.d.ts.map +1 -1
  56. package/dist/dts/internal/server.d.ts.map +1 -1
  57. package/dist/esm/ElementRef.js.map +1 -1
  58. package/dist/esm/ElementSource.js.map +1 -1
  59. package/dist/esm/Html.js +13 -2
  60. package/dist/esm/Html.js.map +1 -1
  61. package/dist/esm/Hydrate.js +11 -5
  62. package/dist/esm/Hydrate.js.map +1 -1
  63. package/dist/esm/Many.js.map +1 -1
  64. package/dist/esm/Render.js +13 -5
  65. package/dist/esm/Render.js.map +1 -1
  66. package/dist/esm/RenderTemplate.js.map +1 -1
  67. package/dist/esm/Test.js +12 -7
  68. package/dist/esm/Test.js.map +1 -1
  69. package/dist/esm/internal/hydrate.js +9 -6
  70. package/dist/esm/internal/hydrate.js.map +1 -1
  71. package/dist/esm/internal/parts.js.map +1 -1
  72. package/dist/esm/internal/render.js +7 -6
  73. package/dist/esm/internal/render.js.map +1 -1
  74. package/dist/esm/internal/server.js +2 -6
  75. package/dist/esm/internal/server.js.map +1 -1
  76. package/package.json +5 -5
  77. package/src/Directive.ts +19 -19
  78. package/src/ElementRef.ts +6 -6
  79. package/src/ElementSource.ts +16 -16
  80. package/src/EventHandler.ts +11 -11
  81. package/src/Html.ts +56 -37
  82. package/src/Hydrate.ts +41 -14
  83. package/src/Many.ts +26 -26
  84. package/src/Part.ts +1 -1
  85. package/src/Placeholder.ts +13 -13
  86. package/src/Platform.ts +3 -3
  87. package/src/Render.ts +52 -15
  88. package/src/RenderTemplate.ts +2 -6
  89. package/src/Renderable.ts +5 -5
  90. package/src/Test.ts +30 -20
  91. package/src/internal/EventSource.ts +1 -1
  92. package/src/internal/hydrate.ts +10 -11
  93. package/src/internal/module-augmentation.ts +15 -15
  94. package/src/internal/parts.ts +1 -1
  95. package/src/internal/render.ts +15 -16
  96. package/src/internal/server.ts +0 -2
package/src/Html.ts CHANGED
@@ -2,10 +2,12 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
 
5
+ import type { CurrentEnvironment } from "@typed/environment"
5
6
  import * as Fx from "@typed/fx/Fx"
6
7
  import * as Sink from "@typed/fx/Sink"
7
8
  import { TypeId } from "@typed/fx/TypeId"
8
9
  import * as Effect from "effect/Effect"
10
+ import * as Layer from "effect/Layer"
9
11
  import * as Option from "effect/Option"
10
12
  import { join } from "effect/ReadonlyArray"
11
13
  import type * as Scope from "effect/Scope"
@@ -18,7 +20,7 @@ import { partNodeToPart } from "./internal/server.js"
18
20
  import { TEXT_START, TYPED_END, TYPED_HOLE, TYPED_START } from "./Meta.js"
19
21
  import type { Placeholder } from "./Placeholder.js"
20
22
  import type { Renderable } from "./Renderable.js"
21
- import { RenderContext } from "./RenderContext.js"
23
+ import * as RenderContext from "./RenderContext.js"
22
24
  import { HtmlRenderEvent, isRenderEvent } from "./RenderEvent.js"
23
25
  import type { RenderEvent } from "./RenderEvent.js"
24
26
  import { RenderTemplate } from "./RenderTemplate.js"
@@ -30,13 +32,30 @@ const [padStart, padEnd] = [[TYPED_START], [TYPED_END]] as const
30
32
  /**
31
33
  * @since 1.0.0
32
34
  */
33
- export function renderToHtml<R, E>(
34
- fx: Fx.Fx<R, E, RenderEvent>
35
- ): Fx.Fx<Exclude<R, RenderTemplate> | RenderContext, E, string> {
35
+ export const serverLayer: Layer.Layer<RenderContext.RenderContext | RenderTemplate | CurrentEnvironment> = Layer
36
+ .provideMerge(
37
+ RenderTemplate.layer(RenderContext.RenderContext.with(renderHtml)),
38
+ RenderContext.server
39
+ )
40
+
41
+ /**
42
+ * @since 1.0.0
43
+ */
44
+ export const staticLayer: Layer.Layer<RenderContext.RenderContext | RenderTemplate | CurrentEnvironment> = Layer
45
+ .provideMerge(
46
+ RenderTemplate.layer(RenderContext.RenderContext.with(renderHtml)),
47
+ RenderContext.static
48
+ )
49
+
50
+ /**
51
+ * @since 1.0.0
52
+ */
53
+ export function renderToHtml<E, R>(
54
+ fx: Fx.Fx<RenderEvent, E, R>
55
+ ): Fx.Fx<string, E, R | RenderTemplate | RenderContext.RenderContext> {
36
56
  return Fx.fromFxEffect(
37
- RenderContext.with((ctx) =>
57
+ RenderContext.RenderContext.with((ctx) =>
38
58
  fx.pipe(
39
- Fx.provide(RenderTemplate.layer(renderHtml(ctx))),
40
59
  Fx.map(toHtml),
41
60
  (x) => ctx.environment === "static" ? x : Fx.padWith(x, padStart, padEnd)
42
61
  )
@@ -47,20 +66,20 @@ export function renderToHtml<R, E>(
47
66
  /**
48
67
  * @since 1.0.0
49
68
  */
50
- export function renderToHtmlString<R, E>(
51
- fx: Fx.Fx<R, E, RenderEvent>
52
- ): Effect.Effect<string, E, Exclude<R, RenderTemplate> | RenderContext> {
69
+ export function renderToHtmlString<E, R>(
70
+ fx: Fx.Fx<RenderEvent, E, R>
71
+ ): Effect.Effect<string, E, R | RenderTemplate | RenderContext.RenderContext> {
53
72
  return Effect.map(Fx.toReadonlyArray(renderToHtml(fx)), join(""))
54
73
  }
55
74
 
56
- function renderHtml(ctx: RenderContext) {
75
+ function renderHtml(ctx: RenderContext.RenderContext) {
57
76
  return <Values extends ReadonlyArray<Renderable<any, any>>>(
58
77
  templateStrings: TemplateStringsArray,
59
78
  values: Values
60
79
  ): Fx.Fx<
61
- Scope.Scope | Placeholder.Context<readonly [] extends Values ? never : Values[number]>,
80
+ RenderEvent,
62
81
  Placeholder.Error<Values[number]>,
63
- RenderEvent
82
+ Scope.Scope | Placeholder.Context<readonly [] extends Values ? never : Values[number]>
64
83
  > => {
65
84
  const isStatic = ctx.environment === "static"
66
85
  const entry = getServerEntry(templateStrings, ctx.templateCache, isStatic)
@@ -71,8 +90,8 @@ function renderHtml(ctx: RenderContext) {
71
90
  Fx.mergeOrdered(
72
91
  entry.chunks.map((chunk) =>
73
92
  renderChunk<
74
- Placeholder.Context<readonly [] extends Values ? never : Values[number]>,
75
- Placeholder.Error<Values[number]>
93
+ Placeholder.Error<Values[number]>,
94
+ Placeholder.Context<readonly [] extends Values ? never : Values[number]>
76
95
  >(chunk, values, isStatic)
77
96
  )
78
97
  ),
@@ -82,21 +101,21 @@ function renderHtml(ctx: RenderContext) {
82
101
  }
83
102
  }
84
103
 
85
- function renderChunk<R, E>(
104
+ function renderChunk<E, R>(
86
105
  chunk: HtmlChunk,
87
106
  values: ReadonlyArray<Renderable<any, any>>,
88
107
  isStatic: boolean
89
- ): Fx.Fx<R, E, RenderEvent> {
108
+ ): Fx.Fx<RenderEvent, E, R> {
90
109
  if (chunk._tag === "text") {
91
110
  return Fx.succeed(HtmlRenderEvent(chunk.value))
92
111
  } else if (chunk._tag === "part") {
93
- return renderPart<R, E>(chunk, values, isStatic)
112
+ return renderPart<E, R>(chunk, values, isStatic)
94
113
  } else {
95
- return renderSparsePart<R, E>(chunk, values) as Fx.Fx<R, E, RenderEvent>
114
+ return renderSparsePart<E, R>(chunk, values) as Fx.Fx<RenderEvent, E, R>
96
115
  }
97
116
  }
98
117
 
99
- function renderNode<R, E>(renderable: Renderable<any, any>, isStatic: boolean): Fx.Fx<R, E, RenderEvent> {
118
+ function renderNode<E, R>(renderable: Renderable<any, any>, isStatic: boolean): Fx.Fx<RenderEvent, E, R> {
100
119
  switch (typeof renderable) {
101
120
  case "string":
102
121
  case "number":
@@ -111,7 +130,7 @@ function renderNode<R, E>(renderable: Renderable<any, any>, isStatic: boolean):
111
130
  }
112
131
  }
113
132
 
114
- function renderObject<R, E>(renderable: object | null | undefined, isStatic: boolean) {
133
+ function renderObject<E, R>(renderable: object | null | undefined, isStatic: boolean) {
115
134
  if (renderable === null || renderable === undefined) {
116
135
  return isStatic ? Fx.empty : Fx.succeed(HtmlRenderEvent(TEXT_START))
117
136
  } else if (Array.isArray(renderable)) {
@@ -122,7 +141,7 @@ function renderObject<R, E>(renderable: object | null | undefined, isStatic: boo
122
141
  } else if (Effect.isEffect(renderable)) {
123
142
  return Fx.switchMap(
124
143
  Fx.fromEffect(renderable as Effect.Effect<Renderable, E, R>),
125
- (r) => renderNode<R, E>(r, isStatic)
144
+ (r) => renderNode<E, R>(r, isStatic)
126
145
  )
127
146
  } else if (isRenderEvent(renderable)) {
128
147
  return Fx.succeed(renderable)
@@ -131,17 +150,17 @@ function renderObject<R, E>(renderable: object | null | undefined, isStatic: boo
131
150
  }
132
151
  }
133
152
 
134
- function renderPart<R, E>(
153
+ function renderPart<E, R>(
135
154
  chunk: PartChunk,
136
155
  values: ReadonlyArray<Renderable<any, any>>,
137
156
  isStatic: boolean
138
- ): Fx.Fx<R, E, RenderEvent> {
157
+ ): Fx.Fx<RenderEvent, E, R> {
139
158
  const { node, render } = chunk
140
159
  const renderable: Renderable<any, any> = values[node.index]
141
160
 
142
161
  // Refs and events are not rendered into HTML
143
- if (isDirective<R, E>(renderable)) {
144
- return Fx.make((sink: Sink.Sink<never, E, RenderEvent>) => {
162
+ if (isDirective<E, R>(renderable)) {
163
+ return Fx.make<RenderEvent, E, R>((sink: Sink.Sink<RenderEvent, E>) => {
145
164
  const part = partNodeToPart(
146
165
  node,
147
166
  (value) => sink.onSuccess(HtmlRenderEvent(render(value)))
@@ -150,8 +169,8 @@ function renderPart<R, E>(
150
169
  return Effect.catchAllCause(renderable(part), sink.onFailure)
151
170
  })
152
171
  } else if (node._tag === "node") {
153
- if (isStatic) return renderNode<R, E>(renderable, isStatic)
154
- return Fx.append(renderNode<R, E>(renderable, isStatic), HtmlRenderEvent(TYPED_HOLE(node.index)))
172
+ if (isStatic) return renderNode<E, R>(renderable, isStatic)
173
+ return Fx.append(renderNode<E, R>(renderable, isStatic), HtmlRenderEvent(TYPED_HOLE(node.index)))
155
174
  } else if (node._tag === "properties") {
156
175
  if (renderable == null) return Fx.empty
157
176
  return Fx.map(
@@ -166,7 +185,7 @@ function renderPart<R, E>(
166
185
  } else {
167
186
  if (renderable === null) return Fx.succeed(HtmlRenderEvent(render(renderable)))
168
187
 
169
- const html = Fx.filterMap(Fx.take(unwrapRenderable<R, E>(renderable), 1), (value) => {
188
+ const html = Fx.filterMap(Fx.take(unwrapRenderable<E, R>(renderable), 1), (value) => {
170
189
  const s = render(value)
171
190
 
172
191
  return s ? Option.some(HtmlRenderEvent(s)) : Option.none()
@@ -180,10 +199,10 @@ function renderPart<R, E>(
180
199
  }
181
200
  }
182
201
 
183
- function renderSparsePart<R, E>(
202
+ function renderSparsePart<E, R>(
184
203
  chunk: SparsePartChunk,
185
204
  values: ReadonlyArray<Renderable<any, any>>
186
- ): Fx.Fx<R, E, RenderEvent> {
205
+ ): Fx.Fx<RenderEvent, E, R> {
187
206
  const { node, render } = chunk
188
207
 
189
208
  return Fx.map(
@@ -194,8 +213,8 @@ function renderSparsePart<R, E>(
194
213
 
195
214
  const renderable: Renderable<any, any> = (values as any)[node.index]
196
215
 
197
- if (isDirective<R, E>(renderable)) {
198
- return Fx.make<R, E, unknown>((sink: Sink.Sink<never, E, unknown>) =>
216
+ if (isDirective<E, R>(renderable)) {
217
+ return Fx.make<unknown, E, R>((sink: Sink.Sink<unknown, E>) =>
199
218
  Effect.catchAllCause(
200
219
  renderable(partNodeToPart(node, (value) => sink.onSuccess(value))),
201
220
  sink.onFailure
@@ -203,7 +222,7 @@ function renderSparsePart<R, E>(
203
222
  )
204
223
  }
205
224
 
206
- return unwrapRenderable<R, E>(renderable)
225
+ return unwrapRenderable<E, R>(renderable)
207
226
  })
208
227
  ),
209
228
  1
@@ -212,8 +231,8 @@ function renderSparsePart<R, E>(
212
231
  )
213
232
  }
214
233
 
215
- function takeOneIfNotRenderEvent<R, E, A>(fx: Fx.Fx<R, E, A>): Fx.Fx<R, E, A> {
216
- return Fx.make<R, E, A>((sink) =>
234
+ function takeOneIfNotRenderEvent<A, E, R>(fx: Fx.Fx<A, E, R>): Fx.Fx<A, E, R> {
235
+ return Fx.make<A, E, R>((sink) =>
217
236
  Sink.withEarlyExit(sink, (sink) =>
218
237
  fx.run(
219
238
  Sink.make(
@@ -227,7 +246,7 @@ function takeOneIfNotRenderEvent<R, E, A>(fx: Fx.Fx<R, E, A>): Fx.Fx<R, E, A> {
227
246
 
228
247
  function getServerEntry(
229
248
  templateStrings: TemplateStringsArray,
230
- templateCache: RenderContext["templateCache"],
249
+ templateCache: RenderContext.RenderContext["templateCache"],
231
250
  isStatic: boolean
232
251
  ): ServerEntry {
233
252
  const cached = templateCache.get(templateStrings)
@@ -249,7 +268,7 @@ function getServerEntry(
249
268
  }
250
269
  }
251
270
 
252
- function unwrapRenderable<R, E>(renderable: Renderable<any, any>): Fx.Fx<R, E, any> {
271
+ function unwrapRenderable<E, R>(renderable: Renderable<any, any>): Fx.Fx<any, E, R> {
253
272
  switch (typeof renderable) {
254
273
  case "undefined":
255
274
  case "object": {
package/src/Hydrate.ts CHANGED
@@ -4,7 +4,10 @@
4
4
 
5
5
  import * as Context from "@typed/context"
6
6
  import { Document } from "@typed/dom/Document"
7
+ import type { DomServices, DomServicesElementParams } from "@typed/dom/DomServices"
8
+ import type { GlobalThis } from "@typed/dom/GlobalThis"
7
9
  import { RootElement } from "@typed/dom/RootElement"
10
+ import type { CurrentEnvironment } from "@typed/environment"
8
11
  import * as Fx from "@typed/fx/Fx"
9
12
  import * as Effect from "effect/Effect"
10
13
  import * as Layer from "effect/Layer"
@@ -12,18 +15,47 @@ import { findRootParentChildNodes, hydrateTemplate } from "./internal/hydrate.js
12
15
  import { HydrateContext } from "./internal/HydrateContext.js"
13
16
  import { attachRoot } from "./internal/render.js"
14
17
  import type { ToRendered } from "./Render.js"
15
- import { RenderContext } from "./RenderContext.js"
18
+ import * as RenderContext from "./RenderContext.js"
16
19
  import { type RenderEvent } from "./RenderEvent.js"
17
20
  import { RenderTemplate } from "./RenderTemplate.js"
18
21
 
22
+ /**
23
+ * @since 1.0.0
24
+ */
25
+ export const hydrateLayer = (
26
+ window: Window & GlobalThis,
27
+ options?: DomServicesElementParams & { readonly skipRenderScheduling?: boolean }
28
+ ): Layer.Layer<
29
+ | RenderTemplate
30
+ | RenderContext.RenderContext
31
+ | CurrentEnvironment
32
+ | DomServices
33
+ > =>
34
+ Layer.provideMerge(
35
+ RenderTemplate.layer(Effect.contextWith((context: Context.Context<Document | RenderContext.RenderContext>) => {
36
+ const [document, ctx] = Context.getMany(
37
+ context,
38
+ Document,
39
+ RenderContext.RenderContext
40
+ )
41
+
42
+ return hydrateTemplate(document, ctx)
43
+ })),
44
+ RenderContext.dom(window, options)
45
+ )
46
+
19
47
  /**
20
48
  * @since 1.0.0
21
49
  */
22
50
  export function hydrate<R, E, T extends RenderEvent | null>(
23
- rendered: Fx.Fx<R, E, T>
24
- ): Fx.Fx<Exclude<R, RenderTemplate> | Document | RenderContext | RootElement, E, ToRendered<T>> {
51
+ rendered: Fx.Fx<T, E, R>
52
+ ): Fx.Fx<ToRendered<T>, E, R | RenderTemplate | RenderContext.RenderContext | RootElement> {
25
53
  return Fx.fromFxEffect(Effect.contextWith((context) => {
26
- const [document, renderContext, { rootElement }] = Context.getMany(context, Document, RenderContext, RootElement)
54
+ const [renderContext, { rootElement }] = Context.getMany(
55
+ context,
56
+ RenderContext.RenderContext,
57
+ RootElement
58
+ )
27
59
  const ctx: HydrateContext = {
28
60
  where: findRootParentChildNodes(rootElement),
29
61
  rootIndex: -1,
@@ -31,23 +63,18 @@ export function hydrate<R, E, T extends RenderEvent | null>(
31
63
  hydrate: true
32
64
  }
33
65
 
34
- const layer = Layer.provideMerge(
35
- HydrateContext.layer(ctx),
36
- RenderTemplate.layer(hydrateTemplate(document, renderContext))
37
- )
38
-
39
66
  return Fx.provide(
40
67
  Fx.mapEffect(rendered, (what) => attachRoot(renderContext.renderCache, rootElement, what)),
41
- layer
68
+ HydrateContext.layer(ctx)
42
69
  )
43
- })) as Fx.Fx<Exclude<R, RenderTemplate> | Document | RenderContext | RootElement, E, ToRendered<T>>
70
+ }))
44
71
  }
45
72
 
46
73
  /**
47
74
  * @since 1.0.0
48
75
  */
49
- export function hydrateLayer<R, E, T extends RenderEvent | null>(
50
- rendered: Fx.Fx<R, E, T>
51
- ) {
76
+ export function hydrateToLayer<R, E, T extends RenderEvent | null>(
77
+ rendered: Fx.Fx<T, E, R>
78
+ ): Layer.Layer<never, never, R | RenderTemplate | RenderContext.RenderContext | RootElement> {
52
79
  return Fx.drainLayer(Fx.switchMapCause(hydrate(rendered), (cause) => Fx.fromEffect(Effect.logError(cause))))
53
80
  }
package/src/Many.ts CHANGED
@@ -20,14 +20,14 @@ import { HtmlRenderEvent, type RenderEvent } from "./RenderEvent.js"
20
20
  /**
21
21
  * @since 1.0.0
22
22
  */
23
- export function many<R, E, A, B extends PropertyKey, R2, E2>(
24
- values: Fx.Fx<R, E, ReadonlyArray<A>>,
23
+ export function many<A, E, R, B extends PropertyKey, R2, E2>(
24
+ values: Fx.Fx<ReadonlyArray<A>, E, R>,
25
25
  getKey: (a: NoInfer<A>) => B,
26
- f: (a: RefSubject.RefSubject<never, never, NoInfer<A>>, key: B) => Fx.Fx<R2, E2, RenderEvent>
27
- ): Fx.Fx<R | R2 | Scope.Scope | RenderContext, E | E2, RenderEvent | ReadonlyArray<RenderEvent>> {
26
+ f: (a: RefSubject.RefSubject<NoInfer<A>>, key: B) => Fx.Fx<RenderEvent, E2, R2>
27
+ ): Fx.Fx<RenderEvent | ReadonlyArray<RenderEvent>, E | E2, R | R2 | Scope.Scope | RenderContext> {
28
28
  return Fx.fromFxEffect(
29
29
  Effect.contextWith(
30
- (context): Fx.Fx<R | R2 | RenderContext | Scope.Scope, E | E2, RenderEvent | ReadonlyArray<RenderEvent>> => {
30
+ (context): Fx.Fx<RenderEvent | ReadonlyArray<RenderEvent>, E | E2, R | R2 | RenderContext | Scope.Scope> => {
31
31
  const ctx = get(context, RenderContext)
32
32
  const hydrateContext = getOption(context, HydrateContext)
33
33
 
@@ -87,15 +87,15 @@ export const manyAsyncData: {
87
87
  matchers: {
88
88
  NoData: () => NoData
89
89
  Loading: (todo: TODO) => Loading
90
- Failure: (data: RefSubject.Computed<never, never, E1>, computed: TODO) => Failure
91
- Success: (value: RefSubject.Computed<never, never, A>, computed: TODO) => Success
90
+ Failure: (data: RefSubject.Computed<E1>, computed: TODO) => Failure
91
+ Success: (value: RefSubject.Computed<A>, computed: TODO) => Success
92
92
  }
93
- ): <R, E>(
94
- fx: Fx.Fx<R, E, AsyncData.AsyncData<ReadonlyArray<A>, E1>>
93
+ ): <E, R>(
94
+ fx: Fx.Fx<AsyncData.AsyncData<ReadonlyArray<A>, E1>, E, R>
95
95
  ) => Fx.Fx<
96
- R | Fx.Fx.Context<NoData | Loading | Failure | Success>,
96
+ Fx.Fx.Success<NoData | Loading | Failure | Success>,
97
97
  E | Fx.Fx.Error<NoData | Loading | Failure | Success>,
98
- Fx.Fx.Success<NoData | Loading | Failure | Success>
98
+ R | Fx.Fx.Context<NoData | Loading | Failure | Success>
99
99
  >
100
100
 
101
101
  <
@@ -109,18 +109,18 @@ export const manyAsyncData: {
109
109
  Failure extends Fx.Fx<any, any, any>,
110
110
  Success extends Fx.Fx<any, any, any>
111
111
  >(
112
- fx: Fx.Fx<R, E, AsyncData.AsyncData<ReadonlyArray<A>, E1>>,
112
+ fx: Fx.Fx<AsyncData.AsyncData<ReadonlyArray<A>, E1>, E, R>,
113
113
  getKey: (a: A) => B,
114
114
  matchers: {
115
115
  NoData: () => NoData
116
116
  Loading: (data: TODO) => Loading
117
- Failure: (data: RefSubject.Computed<never, never, E1>, computed: TODO) => Failure
118
- Success: (value: RefSubject.Computed<never, never, A>, computed: TODO) => Success
117
+ Failure: (data: RefSubject.Computed<E1>, computed: TODO) => Failure
118
+ Success: (value: RefSubject.Computed<A>, computed: TODO) => Success
119
119
  }
120
120
  ): Fx.Fx<
121
- R | Fx.Fx.Context<NoData | Loading | Failure | Success>,
121
+ Fx.Fx.Success<NoData | Loading | Failure | Success>,
122
122
  E | Fx.Fx.Error<NoData | Loading | Failure | Success>,
123
- Fx.Fx.Success<NoData | Loading | Failure | Success>
123
+ R | Fx.Fx.Context<NoData | Loading | Failure | Success>
124
124
  >
125
125
  } = dual(
126
126
  3,
@@ -130,23 +130,23 @@ export const manyAsyncData: {
130
130
  E1,
131
131
  A,
132
132
  B extends PropertyKey,
133
- NoData extends Fx.Fx<any, any, RenderEvent>,
134
- Loading extends Fx.Fx<any, any, RenderEvent>,
135
- Failure extends Fx.Fx<any, any, RenderEvent>,
136
- Success extends Fx.Fx<any, any, RenderEvent>
133
+ NoData extends Fx.Fx<RenderEvent, any, any>,
134
+ Loading extends Fx.Fx<RenderEvent, any, any>,
135
+ Failure extends Fx.Fx<RenderEvent, any, any>,
136
+ Success extends Fx.Fx<RenderEvent, any, any>
137
137
  >(
138
- fx: Fx.Fx<R, E, AsyncData.AsyncData<ReadonlyArray<A>, E1>>,
138
+ fx: Fx.Fx<AsyncData.AsyncData<ReadonlyArray<A>, E1>, E, R>,
139
139
  getKey: (a: A) => B,
140
140
  matchers: {
141
141
  NoData: NoData
142
- Loading: (data: RefSubject.Filtered<never, never, Progress>) => Loading
143
- Failure: (data: RefSubject.Computed<never, never, E1>) => Failure
144
- Success: (value: RefSubject.Computed<never, never, A>, key: B) => Success
142
+ Loading: (data: RefSubject.Filtered<Progress>) => Loading
143
+ Failure: (data: RefSubject.Computed<E1>) => Failure
144
+ Success: (value: RefSubject.Computed<A>, key: B) => Success
145
145
  }
146
146
  ): Fx.Fx<
147
- R | Fx.Fx.Context<NoData | Loading | Failure | Success>,
147
+ RenderEvent | ReadonlyArray<RenderEvent>,
148
148
  E | Fx.Fx.Error<NoData | Loading | Failure | Success>,
149
- RenderEvent | ReadonlyArray<RenderEvent>
149
+ R | Fx.Fx.Context<NoData | Loading | Failure | Success>
150
150
  > => {
151
151
  return RefAsyncData.matchAsyncData(fx, {
152
152
  NoData: matchers.NoData,
package/src/Part.ts CHANGED
@@ -80,7 +80,7 @@ export interface EventPart {
80
80
  readonly value: null
81
81
  readonly index: number
82
82
  readonly onCause: (cause: Cause<unknown>) => Effect<unknown>
83
- readonly addEventListener: (handler: EventHandler<never, never, Event>) => void
83
+ readonly addEventListener: (handler: EventHandler<Event>) => void
84
84
  }
85
85
 
86
86
  /**
@@ -21,7 +21,7 @@ export type PlaceholderTypeId = typeof PlaceholderTypeId
21
21
  /**
22
22
  * @since 1.0.0
23
23
  */
24
- export interface Placeholder<out R = never, out E = never, out A = unknown> {
24
+ export interface Placeholder<A = unknown, E = never, R = never> {
25
25
  readonly [PlaceholderTypeId]: {
26
26
  readonly _R: (_: never) => R
27
27
  readonly _E: (_: never) => E
@@ -37,32 +37,32 @@ export namespace Placeholder {
37
37
  * @since 1.0.0
38
38
  */
39
39
  export type Any<A = any> =
40
- | Placeholder<any, any, A>
41
- | Placeholder<any, never, A>
42
- | Placeholder<never, never, A>
43
- | Placeholder<never, any, A>
40
+ | Placeholder<A, any, any>
41
+ | Placeholder<A, never, any>
42
+ | Placeholder<A>
43
+ | Placeholder<A, any>
44
44
 
45
45
  /**
46
46
  * @since 1.0.0
47
47
  */
48
- export type Context<T> = [T] extends [never] ? never : T extends Placeholder<infer R, infer _E, infer _A> ? R : never
48
+ export type Context<T> = [T] extends [never] ? never : T extends Placeholder<infer _A, infer _E, infer R> ? R : never
49
49
  /**
50
50
  * @since 1.0.0
51
51
  */
52
- export type Error<T> = [T] extends [never] ? never : T extends Placeholder<infer _R, infer E, infer _A> ? E : never
52
+ export type Error<T> = [T] extends [never] ? never : T extends Placeholder<infer _A, infer E, infer _R> ? E : never
53
53
  /**
54
54
  * @since 1.0.0
55
55
  */
56
- export type Success<T> = [T] extends [never] ? never : T extends Placeholder<infer _R, infer _E, infer A> ? A : never
56
+ export type Success<T> = [T] extends [never] ? never : T extends Placeholder<infer A, infer _E, infer _R> ? A : never
57
57
 
58
58
  /**
59
59
  * @since 1.0.0
60
60
  */
61
- export function asRef<R = never, E = never, A = never>(
62
- placeholder: Placeholder<R, E, A> | Fx<R, E, A> | Effect.Effect<A, E, R> | A
63
- ): Effect.Effect<RefSubject.RefSubject<never, E, A>, never, R | Scope.Scope> {
64
- if (isFx<R, E, A>(placeholder) || Effect.isEffect(placeholder)) {
65
- return RefSubject.make(placeholder as Fx<R, E, A>)
61
+ export function asRef<A = never, E = never, R = never>(
62
+ placeholder: Placeholder<A, E, R> | Fx<A, E, R> | Effect.Effect<A, E, R> | A
63
+ ): Effect.Effect<RefSubject.RefSubject<A, E>, never, R | Scope.Scope> {
64
+ if (isFx<A, E, R>(placeholder) || Effect.isEffect(placeholder)) {
65
+ return RefSubject.make(placeholder as Fx<A, E, R>)
66
66
  } else {
67
67
  return RefSubject.of<A, E>(placeholder as A)
68
68
  }
package/src/Platform.ts CHANGED
@@ -20,10 +20,10 @@ const HYPHENATED_CONTENT_TYPE = { "content-type": HTML_CONTENT_TYPE }
20
20
  /**
21
21
  * @since 1.0.0
22
22
  */
23
- export function htmlResponse<R, E>(
24
- fx: Fx.Fx<R, E, RenderEvent>,
23
+ export function htmlResponse<E, R>(
24
+ fx: Fx.Fx<RenderEvent, E, R>,
25
25
  options?: HttpServer.response.Options
26
- ): Effect.Effect<HttpServer.response.ServerResponse, E, RenderContext.RenderContext | Exclude<R, RenderTemplate>> {
26
+ ): Effect.Effect<HttpServer.response.ServerResponse, E, R | RenderTemplate | RenderContext.RenderContext> {
27
27
  return Effect.contextWithEffect((ctx) =>
28
28
  HttpServer.response.stream(
29
29
  Stream.provideContext(Stream.encodeText(toStream(renderToHtml(fx))), ctx),
package/src/Render.ts CHANGED
@@ -4,13 +4,17 @@
4
4
 
5
5
  import * as Context from "@typed/context"
6
6
  import { Document } from "@typed/dom/Document"
7
+ import type { DomServices, DomServicesElementParams } from "@typed/dom/DomServices"
8
+ import type { GlobalThis } from "@typed/dom/GlobalThis"
7
9
  import { RootElement } from "@typed/dom/RootElement"
10
+ import type { CurrentEnvironment } from "@typed/environment"
8
11
  import * as Fx from "@typed/fx/Fx"
9
12
  import { type Rendered } from "@typed/wire"
10
- import type { Layer, Scope } from "effect"
13
+ import type { Scope } from "effect"
14
+ import { Layer } from "effect"
11
15
  import * as Effect from "effect/Effect"
12
16
  import { attachRoot, renderTemplate } from "./internal/render.js"
13
- import { RenderContext } from "./RenderContext.js"
17
+ import * as RenderContext from "./RenderContext.js"
14
18
  import { type RenderEvent } from "./RenderEvent.js"
15
19
  import { RenderTemplate } from "./RenderTemplate.js"
16
20
 
@@ -19,32 +23,65 @@ import { RenderTemplate } from "./RenderTemplate.js"
19
23
  */
20
24
  export type ToRendered<T extends RenderEvent | null> = T extends null ? Rendered | null : Rendered
21
25
 
26
+ /**
27
+ * @since 1.0.0
28
+ */
29
+ export const renderLayer = (
30
+ window: Window & GlobalThis,
31
+ options?: DomServicesElementParams & { readonly skipRenderScheduling?: boolean }
32
+ ): Layer.Layer<
33
+ | RenderTemplate
34
+ | RenderContext.RenderContext
35
+ | CurrentEnvironment
36
+ | DomServices
37
+ > =>
38
+ Layer.provideMerge(
39
+ RenderTemplate.layer(Effect.contextWith((context: Context.Context<Document | RenderContext.RenderContext>) => {
40
+ const [document, ctx] = Context.getMany(
41
+ context,
42
+ Document,
43
+ RenderContext.RenderContext
44
+ )
45
+
46
+ return renderTemplate(document, ctx)
47
+ })),
48
+ RenderContext.dom(window, options)
49
+ )
50
+
22
51
  /**
23
52
  * @since 1.0.0
24
53
  */
25
54
  export function render<R, E, T extends RenderEvent | null>(
26
- rendered: Fx.Fx<R, E, T>
27
- ): Fx.Fx<Exclude<R, RenderTemplate> | Document | RenderContext | RootElement, E, ToRendered<T>> {
55
+ rendered: Fx.Fx<T, E, R>
56
+ ): Fx.Fx<ToRendered<T>, E, R | RenderTemplate | RenderContext.RenderContext | RootElement> {
28
57
  return Fx.fromFxEffect(Effect.contextWith((context) => {
29
- const [document, ctx, { rootElement }] = Context.getMany(context, Document, RenderContext, RootElement)
30
-
31
- return Fx.provideService(
32
- Fx.mapEffect(rendered, (what) => attachRoot(ctx.renderCache, rootElement, what)),
33
- RenderTemplate,
34
- renderTemplate(document, ctx)
58
+ const [ctx, { rootElement }] = Context.getMany(
59
+ context,
60
+ RenderContext.RenderContext,
61
+ RootElement
35
62
  )
63
+
64
+ return Fx.mapEffect(rendered, (what) => attachRoot(ctx.renderCache, rootElement, what))
36
65
  }))
37
66
  }
38
67
 
39
68
  /**
40
69
  * @since 1.0.0
41
70
  */
42
- export function renderLayer<R, E, T extends RenderEvent | null>(
43
- rendered: Fx.Fx<R, E, T>
71
+ export function renderToLayer<R, E, T extends RenderEvent | null>(
72
+ rendered: Fx.Fx<T, E, R>,
73
+ window: Window & GlobalThis = globalThis.window,
74
+ options?: DomServicesElementParams & { readonly skipRenderScheduling?: boolean }
44
75
  ): Layer.Layer<
76
+ RenderTemplate | RenderContext.RenderContext | CurrentEnvironment | DomServices,
45
77
  never,
46
- never,
47
- Document | RenderContext | RootElement | Exclude<Exclude<R, RenderTemplate>, Scope.Scope>
78
+ Exclude<
79
+ Exclude<R, Scope.Scope>,
80
+ RenderTemplate | RenderContext.RenderContext | CurrentEnvironment | DomServices
81
+ >
48
82
  > {
49
- return Fx.drainLayer(Fx.switchMapCause(render(rendered), (e) => Fx.fromEffect(Effect.logError(e))))
83
+ return Layer.provideMerge(
84
+ Fx.drainLayer(Fx.switchMapCause(render(rendered), (e) => Fx.fromEffect(Effect.logError(e)))),
85
+ renderLayer(window, options)
86
+ )
50
87
  }
@@ -16,11 +16,7 @@ export interface RenderTemplate {
16
16
  <Values extends ReadonlyArray<Renderable<any, any>>>(
17
17
  templateStrings: TemplateStringsArray,
18
18
  values: Values
19
- ): Fx.Fx<
20
- Scope | Placeholder.Context<Values[number]>,
21
- Placeholder.Error<Values[number]>,
22
- RenderEvent
23
- >
19
+ ): Fx.Fx<RenderEvent, Placeholder.Error<Values[number]>, Scope | Placeholder.Context<Values[number]>>
24
20
  }
25
21
 
26
22
  /**
@@ -38,6 +34,6 @@ export const RenderTemplate: Context.Tagged<RenderTemplate, RenderTemplate> = Co
38
34
  export function html<const Values extends ReadonlyArray<Renderable<any, any>>>(
39
35
  template: TemplateStringsArray,
40
36
  ...values: Values
41
- ): Fx.Fx<RenderTemplate | Scope | Placeholder.Context<Values[number]>, Placeholder.Error<Values[number]>, RenderEvent> {
37
+ ): Fx.Fx<RenderEvent, Placeholder.Error<Values[number]>, RenderTemplate | Scope | Placeholder.Context<Values[number]>> {
42
38
  return Fx.fromFxEffect(RenderTemplate.with((render) => render(template, values)))
43
39
  }
package/src/Renderable.ts CHANGED
@@ -12,12 +12,12 @@ import type { RenderEvent } from "./RenderEvent.js"
12
12
  */
13
13
  export type Renderable<R = never, E = never> =
14
14
  | Renderable.Value
15
- | Placeholder<R, E, any>
16
- | { readonly [key: string]: Renderable<R, E> | Placeholder<R, E, any> | unknown } // TODO: Should we manage data attributes this way?
17
- | Placeholder<R, E, any>
15
+ | Placeholder<any, E, R>
16
+ | { readonly [key: string]: Renderable<E, R> | Placeholder<any, E, R> | unknown } // TODO: Should we manage data attributes this way?
17
+ | Placeholder<any, E, R>
18
18
  | Effect<any, E, R>
19
- | Fx<R, E, any>
20
- | ReadonlyArray<Renderable<R, E>>
19
+ | Fx<any, E, R>
20
+ | ReadonlyArray<Renderable<E, R>>
21
21
 
22
22
  /**
23
23
  * @since 1.0.0