@zio.dev/zio-blocks 0.0.33 → 0.0.51
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/guides/compile-time-resource-safety-with-scope.md +16 -17
- package/guides/getting-started-with-mux.md +1507 -0
- package/guides/query-dsl-extending.md +161 -102
- package/guides/query-dsl-fluent-builder.md +217 -157
- package/guides/query-dsl-reified-optics.md +12 -10
- package/guides/query-dsl-sql.md +246 -165
- package/guides/telemetry-guide.md +1069 -0
- package/guides/zio-schema-migration.md +29 -22
- package/index.md +292 -50
- package/package.json +1 -1
- package/plans/config-follow-up-prs.md +188 -0
- package/plans/config-pr-assessment-roadmap.md +310 -0
- package/reference/MuxDataFlow.jsx +250 -0
- package/reference/async.md +651 -0
- package/reference/chunk.md +3533 -308
- package/reference/codegen/case-class.md +436 -0
- package/reference/codegen/emitter-config.md +383 -0
- package/reference/codegen/examples.md +664 -0
- package/reference/codegen/field.md +316 -0
- package/reference/codegen/index.md +317 -0
- package/reference/codegen/scala-emitter.md +392 -0
- package/reference/codegen/scala-file.md +276 -0
- package/reference/codegen/sealed-trait.md +408 -0
- package/reference/codegen/type-definition.md +340 -0
- package/reference/codegen/type-ref.md +201 -0
- package/reference/combinators.md +347 -117
- package/reference/config.md +158 -0
- package/reference/context.md +4 -4
- package/reference/datastar.md +346 -0
- package/reference/docs.md +1461 -345
- package/reference/endpoint/auth-type.md +146 -0
- package/reference/endpoint/endpoint.md +297 -0
- package/reference/endpoint/http-codec.md +249 -0
- package/reference/endpoint/index.md +825 -0
- package/reference/endpoint/path-codec.md +237 -0
- package/reference/endpoint/route-pattern.md +196 -0
- package/reference/endpoint/route-tree.md +111 -0
- package/reference/endpoint/segment-codec.md +212 -0
- package/reference/html.md +1120 -0
- package/reference/htmx/attribute-values.md +359 -0
- package/reference/htmx/hx-encoding.md +111 -0
- package/reference/htmx/hx-params.md +204 -0
- package/reference/htmx/hx-swap.md +276 -0
- package/reference/htmx/hx-sync.md +251 -0
- package/reference/htmx/hx-target.md +314 -0
- package/reference/htmx/hx-trigger.md +457 -0
- package/reference/htmx/hx-url-update.md +239 -0
- package/reference/htmx/index.md +855 -0
- package/reference/http-model/index.md +47 -0
- package/reference/http-model/model.md +1481 -0
- package/reference/http-model/schema.md +747 -0
- package/reference/maybe.md +826 -0
- package/reference/media-type.md +2 -2
- package/reference/mux.mdx +823 -0
- package/reference/openapi.md +1351 -0
- package/reference/resource-management/defer-handle.md +1 -1
- package/reference/resource-management/resource.md +31 -2
- package/reference/resource-management/scope.md +28 -12
- package/reference/resource-management/wire.md +3 -7
- package/reference/ringbuffer/MpmcDiagram.jsx +717 -0
- package/reference/ringbuffer/MpscDiagram.jsx +618 -0
- package/reference/ringbuffer/SpmcDiagram.jsx +680 -0
- package/reference/ringbuffer/SpscDiagram.jsx +677 -0
- package/reference/ringbuffer/advanced.mdx +109 -0
- package/reference/ringbuffer/index.mdx +145 -0
- package/reference/ringbuffer/mpmc.mdx +151 -0
- package/reference/ringbuffer/mpsc.mdx +132 -0
- package/reference/ringbuffer/spmc.mdx +108 -0
- package/reference/ringbuffer/spsc.mdx +344 -0
- package/reference/{allows.md → schema/allows.md} +4 -4
- package/reference/{binding-resolver.md → schema/binding-resolver.md} +1 -1
- package/reference/{binding.md → schema/binding.md} +2 -3
- package/reference/schema/built-in-codecs/avro.md +451 -0
- package/reference/schema/built-in-codecs/bson.md +480 -0
- package/reference/schema/built-in-codecs/csv.md +564 -0
- package/reference/schema/built-in-codecs/index.md +77 -0
- package/reference/schema/built-in-codecs/json/index.md +295 -0
- package/reference/schema/built-in-codecs/json/json-config.md +217 -0
- package/reference/{json-patch.md → schema/built-in-codecs/json/json-patch.md} +5 -5
- package/reference/{json-schema.md → schema/built-in-codecs/json/json-schema.md} +14 -47
- package/reference/schema/built-in-codecs/json/json-selection.md +322 -0
- package/reference/{json.md → schema/built-in-codecs/json/json.md} +32 -64
- package/reference/schema/built-in-codecs/messagepack.md +508 -0
- package/reference/schema/built-in-codecs/thrift.md +433 -0
- package/reference/schema/built-in-codecs/toon.md +1078 -0
- package/reference/{xml.md → schema/built-in-codecs/xml.md} +13 -9
- package/reference/schema/built-in-codecs/yaml.md +552 -0
- package/reference/{codec.md → schema/codec.md} +10 -10
- package/reference/{dynamic-optic.md → schema/dynamic-optic.md} +151 -5
- package/reference/{dynamic-schema.md → schema/dynamic-schema.md} +8 -8
- package/reference/schema/format.md +92 -0
- package/reference/schema/index.md +50 -0
- package/reference/schema/migration.md +297 -0
- package/reference/{modifier.md → schema/modifier.md} +58 -7
- package/reference/{optics.md → schema/optics.md} +2 -2
- package/reference/{patch.md → schema/patch.md} +1 -1
- package/{path-interpolator.md → reference/schema/path-interpolator.md} +165 -72
- package/reference/{schema-evolution → schema/schema-evolution}/as.md +8 -8
- package/reference/{schema-evolution → schema/schema-evolution}/index.md +2 -2
- package/reference/{schema-evolution → schema/schema-evolution}/into.md +8 -8
- package/reference/{schema-expr.md → schema/schema-expr.md} +110 -175
- package/reference/{schema.md → schema/schema.md} +12 -0
- package/reference/{structural-types.md → schema/structural-types.md} +1 -1
- package/reference/{type-class-derivation.md → schema/type-class-derivation.md} +63 -1
- package/reference/smithy.md +533 -0
- package/reference/sql/db-codec-deriver.md +71 -0
- package/reference/sql/db-codec.md +687 -0
- package/reference/sql/db-con.md +271 -0
- package/reference/sql/db-connection.md +153 -0
- package/reference/sql/db-param-writer.md +77 -0
- package/reference/sql/db-param.md +66 -0
- package/reference/sql/db-result-reader.md +146 -0
- package/reference/sql/db-tx.md +82 -0
- package/reference/sql/db-value.md +41 -0
- package/reference/sql/ddl.md +85 -0
- package/reference/sql/frag.md +254 -0
- package/reference/sql/index.md +341 -0
- package/reference/sql/repo.md +600 -0
- package/reference/sql/sql-dialect.md +73 -0
- package/reference/sql/sql-logger.md +62 -0
- package/reference/sql/sql-name-mapper.md +70 -0
- package/reference/sql/table-metadata.md +134 -0
- package/reference/sql/table.md +448 -0
- package/reference/sql/transactor-zio.md +399 -0
- package/reference/sql/transactor.md +353 -0
- package/reference/sql-zio.md +112 -0
- package/reference/streams/concurrent-operators.md +106 -0
- package/reference/streams/index.md +653 -0
- package/reference/streams/pipeline.md +718 -0
- package/reference/streams/reader.md +1284 -0
- package/reference/streams/scala-2-compatibility.md +55 -0
- package/reference/streams/sink.md +1426 -0
- package/reference/streams/stream.md +2526 -0
- package/reference/streams/writer.md +1045 -0
- package/reference/streams/zero-boxing.md +275 -0
- package/reference/telemetry.md +693 -0
- package/reference/typeid.md +5 -19
- package/sidebars.js +238 -43
- package/reference/formats.md +0 -694
- package/reference/http-model.md +0 -1716
- package/reference/streams.md +0 -989
- package/ringbuffer.md +0 -249
- /package/reference/{json-differ.md → schema/built-in-codecs/json/json-differ.md} +0 -0
- /package/reference/{dynamic-value.md → schema/dynamic-value.md} +0 -0
- /package/reference/{lazy.md → schema/lazy.md} +0 -0
- /package/reference/{reflect.md → schema/reflect.md} +0 -0
- /package/reference/{registers.md → schema/registers.md} +0 -0
- /package/reference/{schema-error.md → schema/schema-error.md} +0 -0
- /package/reference/{syntax.md → schema/syntax.md} +0 -0
- /package/reference/{validation.md → schema/validation.md} +0 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: attribute-values
|
|
3
|
+
title: Attribute Values and Infrastructure
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
This section documents supporting attribute value types and infrastructure for the HTMX DSL. These types handle specialized data encoding, configuration, and type-class infrastructure that enables extensibility.
|
|
7
|
+
|
|
8
|
+
## Attribute Value Types
|
|
9
|
+
|
|
10
|
+
These types enable specialized data encoding and configuration:
|
|
11
|
+
|
|
12
|
+
### HxVals — Custom Values
|
|
13
|
+
|
|
14
|
+
`HxVals` represents the `hx-vals` attribute, allowing you to send custom data alongside form parameters. It accepts both schema-backed values (automatically JSON-encoded) and raw JSON:
|
|
15
|
+
|
|
16
|
+
```scala
|
|
17
|
+
import zio.http.htmx._
|
|
18
|
+
import zio.blocks.schema._
|
|
19
|
+
import zio.blocks.schema.json.Json
|
|
20
|
+
|
|
21
|
+
// From a schema-backed value
|
|
22
|
+
case class Extra(userId: Int, role: String)
|
|
23
|
+
HxVals.from(Extra(123, "admin"))
|
|
24
|
+
|
|
25
|
+
// From raw JSON
|
|
26
|
+
HxVals.json(Json.Object(Chunk("userId" -> Json.Number(123))))
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Use `HxVals.from[T](value)` with an implicit `Schema[T]` to automatically encode any data type to JSON. First, set up a schema for your data type:
|
|
30
|
+
|
|
31
|
+
```scala
|
|
32
|
+
import zio.blocks.html._
|
|
33
|
+
import zio.http.htmx._
|
|
34
|
+
import zio.blocks.schema._
|
|
35
|
+
|
|
36
|
+
case class RequestContext(userId: Int, sessionId: String)
|
|
37
|
+
object RequestContext {
|
|
38
|
+
implicit val schema: Schema[RequestContext] = Schema.derived
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then use it in your form:
|
|
43
|
+
|
|
44
|
+
```scala
|
|
45
|
+
import zio.blocks.html._
|
|
46
|
+
import zio.http.htmx._
|
|
47
|
+
|
|
48
|
+
form(
|
|
49
|
+
hxPost := "/api/action",
|
|
50
|
+
hxVals := HxVals.from(RequestContext(42, "abc123")),
|
|
51
|
+
button("Submit")
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or use `HxVals.json(json)` when you already have JSON. Set up the imports first:
|
|
56
|
+
|
|
57
|
+
```scala
|
|
58
|
+
import zio.blocks.schema.json.Json
|
|
59
|
+
import zio.blocks.chunk.Chunk
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then construct the JSON:
|
|
63
|
+
|
|
64
|
+
```scala
|
|
65
|
+
import zio.blocks.html._
|
|
66
|
+
import zio.http.htmx._
|
|
67
|
+
import zio.blocks.schema.json.Json
|
|
68
|
+
import zio.blocks.chunk.Chunk
|
|
69
|
+
|
|
70
|
+
form(
|
|
71
|
+
hxPost := "/api/action",
|
|
72
|
+
hxVals := HxVals.json(Json.Object(Chunk("priority" -> Json.String("high")))),
|
|
73
|
+
button("Submit")
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### HxHeadersValue — Custom Headers
|
|
78
|
+
|
|
79
|
+
`HxHeadersValue` represents the `hx-headers` attribute, sending custom HTTP headers with HTMX requests. Like `HxVals`, it accepts schema-backed values or raw JSON:
|
|
80
|
+
|
|
81
|
+
```scala
|
|
82
|
+
import zio.http.htmx._
|
|
83
|
+
import zio.blocks.schema.json.Json
|
|
84
|
+
import zio.blocks.chunk.Chunk
|
|
85
|
+
|
|
86
|
+
// From raw JSON object
|
|
87
|
+
val example1 = HxHeadersValue.json(Json.Object(Chunk(
|
|
88
|
+
"X-Custom-Header" -> Json.String("value"),
|
|
89
|
+
"X-Request-ID" -> Json.String("12345")
|
|
90
|
+
)))
|
|
91
|
+
|
|
92
|
+
// From a schema-backed value
|
|
93
|
+
import zio.blocks.schema._
|
|
94
|
+
case class Headers(traceId: String)
|
|
95
|
+
object Headers {
|
|
96
|
+
implicit val schema: Schema[Headers] = Schema.derived
|
|
97
|
+
}
|
|
98
|
+
val example2 = HxHeadersValue.from(Headers("xyz789"))
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Add custom headers to all requests within an element:
|
|
102
|
+
|
|
103
|
+
```scala
|
|
104
|
+
import zio.blocks.html._
|
|
105
|
+
import zio.http.htmx._
|
|
106
|
+
import zio.blocks.schema.json.Json
|
|
107
|
+
import zio.blocks.chunk.Chunk
|
|
108
|
+
|
|
109
|
+
div(
|
|
110
|
+
hxHeaders := HxHeadersValue.json(Json.Object(Chunk(
|
|
111
|
+
"X-API-Key" -> Json.String("secret123"),
|
|
112
|
+
"X-Client-Version" -> Json.String("2.0")
|
|
113
|
+
))),
|
|
114
|
+
button(hxPost := "/action", "Request (with custom headers)")
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### HxSwapOob — Out-of-Bounds Swaps
|
|
119
|
+
|
|
120
|
+
`HxSwapOob` represents the `hx-swap-oob` attribute, enabling out-of-bounds swaps that update content outside the primary request target. This allows a single response to update multiple DOM regions simultaneously.
|
|
121
|
+
|
|
122
|
+
Use `HxSwapOob(true)` or `HxSwapOob(false)` for boolean flags:
|
|
123
|
+
|
|
124
|
+
```scala
|
|
125
|
+
import zio.blocks.html._
|
|
126
|
+
import zio.http.htmx._
|
|
127
|
+
|
|
128
|
+
div(
|
|
129
|
+
id := "status-badge",
|
|
130
|
+
hxSwapOob := HxSwapOob(true),
|
|
131
|
+
"Ready"
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or use `HxSwapOob.using(swap)` to specify a swap strategy:
|
|
136
|
+
|
|
137
|
+
```scala
|
|
138
|
+
import zio.blocks.html._
|
|
139
|
+
import zio.http.htmx._
|
|
140
|
+
|
|
141
|
+
div(
|
|
142
|
+
id := "notification",
|
|
143
|
+
hxSwapOob := HxSwapOob.using(HxSwap.BeforeEnd),
|
|
144
|
+
span("New notification")
|
|
145
|
+
)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Combine with a target selector:
|
|
149
|
+
|
|
150
|
+
```scala
|
|
151
|
+
import zio.blocks.html._
|
|
152
|
+
import zio.http.htmx._
|
|
153
|
+
|
|
154
|
+
div(
|
|
155
|
+
hxSwapOob := HxSwapOob.using(
|
|
156
|
+
HxSwap.InnerHTML,
|
|
157
|
+
HxTarget.css("#status")
|
|
158
|
+
),
|
|
159
|
+
"Updated Status"
|
|
160
|
+
)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### HxExtensions — HTMX Extensions
|
|
164
|
+
|
|
165
|
+
`HxExtensions` represents the `hx-ext` attribute, enabling HTMX extensions. Pass extension names as comma-separated values:
|
|
166
|
+
|
|
167
|
+
```scala
|
|
168
|
+
import zio.http.htmx._
|
|
169
|
+
|
|
170
|
+
// Enable multiple extensions
|
|
171
|
+
HxExtensions("json-enc", "class-tools")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Use in elements to opt in to extensions:
|
|
175
|
+
|
|
176
|
+
```scala
|
|
177
|
+
import zio.blocks.html._
|
|
178
|
+
import zio.http.htmx._
|
|
179
|
+
|
|
180
|
+
form(
|
|
181
|
+
hxPost := "/api/submit",
|
|
182
|
+
hxExt := HxExtensions("json-enc", "debug"),
|
|
183
|
+
button("Submit")
|
|
184
|
+
)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The `hxExt` attribute key provides a convenience builder to construct extensions:
|
|
188
|
+
|
|
189
|
+
```scala
|
|
190
|
+
import zio.blocks.html._
|
|
191
|
+
import zio.http.htmx._
|
|
192
|
+
|
|
193
|
+
form(
|
|
194
|
+
hxExt("json-enc", "class-tools"),
|
|
195
|
+
button("Submit")
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### HxAttributeNames — Attribute Disinheritance
|
|
200
|
+
|
|
201
|
+
`HxAttributeNames` represents the `hx-disinherit` attribute, preventing child elements from inheriting specific HTMX attributes from their ancestors. Pass attribute names as space-separated values:
|
|
202
|
+
|
|
203
|
+
```scala
|
|
204
|
+
import zio.http.htmx._
|
|
205
|
+
|
|
206
|
+
// Prevent inheriting these attributes
|
|
207
|
+
HxAttributeNames("hx-trigger", "hx-swap")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Use to override inherited attributes:
|
|
211
|
+
|
|
212
|
+
```scala
|
|
213
|
+
import zio.blocks.html._
|
|
214
|
+
import zio.http.htmx._
|
|
215
|
+
|
|
216
|
+
div(
|
|
217
|
+
hxPost := "/parent-action",
|
|
218
|
+
hxTrigger := HxTrigger.click,
|
|
219
|
+
button(
|
|
220
|
+
hxDisinherit := HxAttributeNames("hx-post", "hx-trigger"),
|
|
221
|
+
hxPost := "/child-action",
|
|
222
|
+
hxTrigger := HxTrigger.submit,
|
|
223
|
+
"Child (overrides parent)"
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The `hxDisinherit` attribute key provides a convenience builder:
|
|
229
|
+
|
|
230
|
+
```scala
|
|
231
|
+
import zio.blocks.html._
|
|
232
|
+
import zio.http.htmx._
|
|
233
|
+
|
|
234
|
+
div(
|
|
235
|
+
hxPost := "/parent-action",
|
|
236
|
+
button(
|
|
237
|
+
hxDisinherit("hx-post", "hx-trigger"),
|
|
238
|
+
hxPost := "/child-action",
|
|
239
|
+
"Child"
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Infrastructure Types
|
|
245
|
+
|
|
246
|
+
These types provide the internal machinery for the HTMX DSL:
|
|
247
|
+
|
|
248
|
+
### HtmxAttrKey — Typed Attribute Keys
|
|
249
|
+
|
|
250
|
+
`HtmxAttrKey[-A]` is the typed attribute key binding an attribute name to its expected value type. Unlike plain HTML attributes, HTMX attributes carry compile-time type information, preventing type mismatches.
|
|
251
|
+
|
|
252
|
+
The `HtmxAttributes` mixin provides predefined keys like `hxPost`, `hxSwap`, `hxTarget`, etc.; use these rather than constructing `HtmxAttrKey` directly. Each key enforces the correct value type:
|
|
253
|
+
|
|
254
|
+
```scala
|
|
255
|
+
import zio.blocks.html._
|
|
256
|
+
import zio.http.htmx._
|
|
257
|
+
|
|
258
|
+
// hxSwap expects HxSwap; this compiles
|
|
259
|
+
div(hxSwap := HxSwap.InnerHTML)
|
|
260
|
+
|
|
261
|
+
// hxTarget expects HxTarget; this compiles
|
|
262
|
+
div(hxTarget := HxTarget.This)
|
|
263
|
+
|
|
264
|
+
// hxPost expects UrlLike (String | Path | URL); this compiles
|
|
265
|
+
div(hxPost := "/api/endpoint")
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### ToHtmxValue — Type Class for Rendering
|
|
269
|
+
|
|
270
|
+
`ToHtmxValue[-A]` is the type class that renders HTMX domain values to attribute strings. It's automatically derived for types like `HxSwap`, `HxTarget`, `HxTrigger`, and basic primitives.
|
|
271
|
+
|
|
272
|
+
The module provides instances for common types out of the box:
|
|
273
|
+
|
|
274
|
+
- **Primitives:** `String`, `Boolean`, `Int`, `Long`, `Double` render to their string representations
|
|
275
|
+
- **Selectors:** `CssSelector` renders via its `render` method
|
|
276
|
+
- **URLs:** `Path` and `URL` render to encoded strings
|
|
277
|
+
- **HTMX domain types:** `HxSwap`, `HxTarget`, `HxTrigger`, `HxParams`, etc. render via their `render` methods
|
|
278
|
+
- **Schema-backed types:** `Schema[A]` instances enable `HxVals.from()` to encode any data to JSON
|
|
279
|
+
|
|
280
|
+
#### Extending with Custom Types
|
|
281
|
+
|
|
282
|
+
Define your own `ToHtmxValue` instance to make custom domain types work in the HTMX DSL:
|
|
283
|
+
|
|
284
|
+
```scala
|
|
285
|
+
import zio.http.htmx._
|
|
286
|
+
|
|
287
|
+
sealed trait Priority
|
|
288
|
+
object Priority {
|
|
289
|
+
case object Low extends Priority
|
|
290
|
+
case object Medium extends Priority
|
|
291
|
+
case object High extends Priority
|
|
292
|
+
|
|
293
|
+
implicit val toHtmxValue: ToHtmxValue[Priority] = new ToHtmxValue[Priority] {
|
|
294
|
+
def toHtmxValue(value: Priority): String = value match {
|
|
295
|
+
case Low => "low"
|
|
296
|
+
case Medium => "medium"
|
|
297
|
+
case High => "high"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Use `Priority` values directly in HTMX attributes through the `ToHtmxValue` type class:
|
|
304
|
+
|
|
305
|
+
```scala
|
|
306
|
+
import zio.blocks.html._
|
|
307
|
+
import zio.http.htmx._
|
|
308
|
+
|
|
309
|
+
button(
|
|
310
|
+
hxPost := "/api/task",
|
|
311
|
+
hxOn.click := Js(s"console.log('Priority: ${Priority.High.toString()}')"),
|
|
312
|
+
"Create High Priority Task"
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### Implicit Resolution
|
|
317
|
+
|
|
318
|
+
When you assign a value to an HTMX attribute, the type class is summoned implicitly:
|
|
319
|
+
|
|
320
|
+
```scala
|
|
321
|
+
import zio.blocks.html._
|
|
322
|
+
import zio.http.htmx._
|
|
323
|
+
|
|
324
|
+
// Implicit ToHtmxValue[HxSwap] is summoned
|
|
325
|
+
div(hxSwap := HxSwap.InnerHTML)
|
|
326
|
+
|
|
327
|
+
// Implicit ToHtmxValue[String] is summoned
|
|
328
|
+
div(hxPost := "/endpoint")
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
If you get an error like "No `ToHtmxValue` instance found for type X," implement the type class for your custom type as shown above.
|
|
332
|
+
|
|
333
|
+
## Integration
|
|
334
|
+
|
|
335
|
+
These types work together to provide a complete, extensible HTMX DSL. For example, a form might use multiple attribute value types:
|
|
336
|
+
|
|
337
|
+
```scala
|
|
338
|
+
import zio.blocks.html._
|
|
339
|
+
import zio.http.htmx._
|
|
340
|
+
import zio.blocks.schema.json.Json
|
|
341
|
+
import zio.blocks.chunk.Chunk
|
|
342
|
+
import scala.concurrent.duration._
|
|
343
|
+
|
|
344
|
+
form(
|
|
345
|
+
hxPost := "/api/submit",
|
|
346
|
+
hxTrigger := HxTrigger.submit,
|
|
347
|
+
hxTarget := HxTarget.closest("form"),
|
|
348
|
+
hxSwap := HxSwap.InnerHTML.settle(250.millis),
|
|
349
|
+
hxParams := HxParams.only("name", "email"),
|
|
350
|
+
hxEncoding := HxEncoding.Multipart,
|
|
351
|
+
hxHeaders := HxHeadersValue.json(Json.Object(Chunk(
|
|
352
|
+
"X-Request-ID" -> Json.String("12345")
|
|
353
|
+
))),
|
|
354
|
+
hxVals := HxVals.from(RequestContext(42, "session-abc")),
|
|
355
|
+
button("Submit")
|
|
356
|
+
)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Each attribute key is type-safe, and the `ToHtmxValue` type class ensures values render correctly to HTMX syntax.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: hx-encoding
|
|
3
|
+
title: HxEncoding
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`HxEncoding` represents the `hx-encoding` attribute, controlling how form data is encoded when sent in an HTMX request. The primary use case is file uploads, which require `multipart/form-data` encoding instead of the default URL-encoded form submission.
|
|
7
|
+
|
|
8
|
+
Use `HxEncoding.Multipart` to enable multipart form data encoding for requests that include file fields. Here is the core pattern:
|
|
9
|
+
|
|
10
|
+
```scala
|
|
11
|
+
import zio.http.htmx._
|
|
12
|
+
|
|
13
|
+
// Multipart encoding (for file uploads)
|
|
14
|
+
HxEncoding.Multipart
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Encoding Strategies
|
|
18
|
+
|
|
19
|
+
**`HxEncoding.Multipart`** sets the `hx-encoding` attribute to `multipart/form-data`, enabling file uploads and other multipart data:
|
|
20
|
+
|
|
21
|
+
```scala
|
|
22
|
+
import zio.blocks.html._
|
|
23
|
+
import zio.http.htmx._
|
|
24
|
+
|
|
25
|
+
form(
|
|
26
|
+
hxPost := "/upload",
|
|
27
|
+
hxEncoding := HxEncoding.Multipart,
|
|
28
|
+
input(name := "file", `type` := "file"),
|
|
29
|
+
input(name := "description"),
|
|
30
|
+
button("Upload")
|
|
31
|
+
)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
When you omit `hxEncoding`, HTMX uses the default encoding (URL-encoded form data), so there is no DSL value for the default case. This keeps the DSL focused on the special cases that deviate from the default.
|
|
35
|
+
|
|
36
|
+
## Common Patterns
|
|
37
|
+
|
|
38
|
+
Multipart encoding enables file uploads in HTMX forms. Here are practical usage patterns:
|
|
39
|
+
|
|
40
|
+
### File Upload with Metadata
|
|
41
|
+
|
|
42
|
+
Send a file along with additional form fields:
|
|
43
|
+
|
|
44
|
+
```scala
|
|
45
|
+
import zio.blocks.html._
|
|
46
|
+
import zio.http.htmx._
|
|
47
|
+
|
|
48
|
+
form(
|
|
49
|
+
hxPost := "/api/upload-document",
|
|
50
|
+
hxEncoding := HxEncoding.Multipart,
|
|
51
|
+
hxTarget := HxTarget.css("#upload-status"),
|
|
52
|
+
hxSwap := HxSwap.InnerHTML,
|
|
53
|
+
fieldset(
|
|
54
|
+
legend("Upload Document"),
|
|
55
|
+
input(
|
|
56
|
+
name := "file",
|
|
57
|
+
`type` := "file",
|
|
58
|
+
accept := ".pdf,.doc,.docx"
|
|
59
|
+
),
|
|
60
|
+
input(
|
|
61
|
+
name := "title",
|
|
62
|
+
placeholder := "Document Title"
|
|
63
|
+
),
|
|
64
|
+
textarea(name := "description", "Description"),
|
|
65
|
+
button("Upload")
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Profile Picture Upload
|
|
71
|
+
|
|
72
|
+
Update a profile picture with multipart encoding:
|
|
73
|
+
|
|
74
|
+
```scala
|
|
75
|
+
import zio.blocks.html._
|
|
76
|
+
import zio.http.htmx._
|
|
77
|
+
|
|
78
|
+
form(
|
|
79
|
+
hxPost := "/api/profile-picture",
|
|
80
|
+
hxEncoding := HxEncoding.Multipart,
|
|
81
|
+
hxTarget := HxTarget.css("#profile-pic"),
|
|
82
|
+
hxSwap := HxSwap.OuterHTML,
|
|
83
|
+
input(
|
|
84
|
+
name := "image",
|
|
85
|
+
`type` := "file",
|
|
86
|
+
accept := "image/*"
|
|
87
|
+
),
|
|
88
|
+
button("Update Picture")
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Integration with Other Request Control Attributes
|
|
93
|
+
|
|
94
|
+
`HxEncoding` works alongside `HxParams` to control both how data is encoded and which fields are sent:
|
|
95
|
+
|
|
96
|
+
```scala
|
|
97
|
+
import zio.blocks.html._
|
|
98
|
+
import zio.http.htmx._
|
|
99
|
+
|
|
100
|
+
form(
|
|
101
|
+
hxPost := "/upload",
|
|
102
|
+
hxEncoding := HxEncoding.Multipart,
|
|
103
|
+
hxParams := HxParams.only("file", "title"), // only send these fields
|
|
104
|
+
input(name := "file", `type` := "file"),
|
|
105
|
+
input(name := "title"),
|
|
106
|
+
input(name := "csrf_token"), // excluded by hxParams
|
|
107
|
+
button("Upload")
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The `ToHtmxValue[HxEncoding]` instance renders automatically, so `HxEncoding` values work seamlessly with the `hxEncoding` attribute key.
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: hx-params
|
|
3
|
+
title: HxParams
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
`HxParams` represents the `hx-params` attribute, controlling which form parameters are included in the HTMX request. Instead of sending all form fields, you can explicitly allow or forbid specific parameters through compile-safe domain types.
|
|
7
|
+
|
|
8
|
+
Use `HxParams.All` to include all parameters, `HxParams.None` to include none, or `HxParams.only()` and `HxParams.not()` to allow/forbid specific names. Here are the core patterns:
|
|
9
|
+
|
|
10
|
+
```scala
|
|
11
|
+
import zio.http.htmx._
|
|
12
|
+
|
|
13
|
+
// Include all parameters
|
|
14
|
+
HxParams.All
|
|
15
|
+
|
|
16
|
+
// Include no parameters
|
|
17
|
+
HxParams.None
|
|
18
|
+
|
|
19
|
+
// Include only specific parameters
|
|
20
|
+
HxParams.only("query", "page")
|
|
21
|
+
|
|
22
|
+
// Exclude specific parameters
|
|
23
|
+
HxParams.not("csrf_token", "session")
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Strategies
|
|
27
|
+
|
|
28
|
+
**`HxParams.All`** includes all form parameters in the request (the default HTMX behavior):
|
|
29
|
+
|
|
30
|
+
```scala
|
|
31
|
+
import zio.blocks.html._
|
|
32
|
+
import zio.http.htmx._
|
|
33
|
+
|
|
34
|
+
input(
|
|
35
|
+
hxPost := "/search",
|
|
36
|
+
hxParams := HxParams.All
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**`HxParams.None`** excludes all form parameters. The request body is empty:
|
|
41
|
+
|
|
42
|
+
```scala
|
|
43
|
+
import zio.blocks.html._
|
|
44
|
+
import zio.http.htmx._
|
|
45
|
+
|
|
46
|
+
button(
|
|
47
|
+
hxPost := "/ping",
|
|
48
|
+
hxParams := HxParams.None,
|
|
49
|
+
"Ping Server"
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**`HxParams.only(first, rest*)`** includes only the listed parameters by name:
|
|
54
|
+
|
|
55
|
+
```scala
|
|
56
|
+
import zio.blocks.html._
|
|
57
|
+
import zio.http.htmx._
|
|
58
|
+
|
|
59
|
+
input(
|
|
60
|
+
hxPost := "/search",
|
|
61
|
+
hxParams := HxParams.only("query", "page", "limit"),
|
|
62
|
+
placeholder := "Search..."
|
|
63
|
+
)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**`HxParams.not(first, rest*)`** excludes the listed parameters, sending all others:
|
|
67
|
+
|
|
68
|
+
```scala
|
|
69
|
+
import zio.blocks.html._
|
|
70
|
+
import zio.http.htmx._
|
|
71
|
+
|
|
72
|
+
form(
|
|
73
|
+
hxPost := "/submit",
|
|
74
|
+
hxParams := HxParams.not("csrf_token", "_method"),
|
|
75
|
+
input(name := "username"),
|
|
76
|
+
input(name := "csrf_token"),
|
|
77
|
+
button("Submit")
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Rendering & Parsing
|
|
82
|
+
|
|
83
|
+
**`render: String`** produces the literal `hx-params` attribute value string:
|
|
84
|
+
|
|
85
|
+
```scala
|
|
86
|
+
import zio.http.htmx._
|
|
87
|
+
|
|
88
|
+
HxParams.All.render // "*"
|
|
89
|
+
HxParams.None.render // "none"
|
|
90
|
+
HxParams.only("query", "page").render // "query,page"
|
|
91
|
+
HxParams.not("csrf_token", "session").render // "not csrf_token,session"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**`HxParams.parse(value: String): Either[String, HxParams]`** parses a rendered string back into a typed `HxParams`:
|
|
95
|
+
|
|
96
|
+
```scala
|
|
97
|
+
import zio.http.htmx._
|
|
98
|
+
|
|
99
|
+
HxParams.parse("*") // Right(HxParams.All)
|
|
100
|
+
HxParams.parse("none") // Right(HxParams.None)
|
|
101
|
+
HxParams.parse("query,page") // Right(HxParams.only("query", "page"))
|
|
102
|
+
HxParams.parse("not csrf,session") // Right(HxParams.not("csrf", "session"))
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Parse failures return a descriptive `Left`:
|
|
106
|
+
|
|
107
|
+
```scala
|
|
108
|
+
import zio.http.htmx._
|
|
109
|
+
|
|
110
|
+
HxParams.parse("") // Left("HTMX params list must be non-empty")
|
|
111
|
+
HxParams.parse("query,,page") // Left("HTMX params list cannot contain empty names")
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Common Patterns
|
|
115
|
+
|
|
116
|
+
`HxParams` is useful when you need fine-grained control over which form fields are sent to the server. Here are representative usage patterns:
|
|
117
|
+
|
|
118
|
+
### Search Without CSRF Token
|
|
119
|
+
|
|
120
|
+
Include only the search query parameter, excluding the CSRF token typically added by form handlers:
|
|
121
|
+
|
|
122
|
+
```scala
|
|
123
|
+
import zio.blocks.html._
|
|
124
|
+
import zio.http.htmx._
|
|
125
|
+
|
|
126
|
+
input(
|
|
127
|
+
name := "query",
|
|
128
|
+
hxPost := "/search",
|
|
129
|
+
hxParams := HxParams.only("query"),
|
|
130
|
+
placeholder := "Search..."
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Selective Parameter Submission
|
|
135
|
+
|
|
136
|
+
When a form has many fields but an HTMX request should only send a few:
|
|
137
|
+
|
|
138
|
+
```scala
|
|
139
|
+
import zio.blocks.html._
|
|
140
|
+
import zio.http.htmx._
|
|
141
|
+
|
|
142
|
+
form(
|
|
143
|
+
input(name := "firstName"),
|
|
144
|
+
input(name := "lastName"),
|
|
145
|
+
input(
|
|
146
|
+
name := "email",
|
|
147
|
+
hxPost := "/validate-email",
|
|
148
|
+
hxParams := HxParams.only("email"),
|
|
149
|
+
hxTarget := HxTarget.next(".error"),
|
|
150
|
+
placeholder := "Email"
|
|
151
|
+
),
|
|
152
|
+
div("Error message")
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Exclude Framework Parameters
|
|
157
|
+
|
|
158
|
+
Prevent sending framework-specific parameters (like Rails' `_method`, CSRF tokens) to the HTMX endpoint:
|
|
159
|
+
|
|
160
|
+
```scala
|
|
161
|
+
import zio.blocks.html._
|
|
162
|
+
import zio.http.htmx._
|
|
163
|
+
|
|
164
|
+
form(
|
|
165
|
+
hxPost := "/api/submit",
|
|
166
|
+
hxParams := HxParams.not("_method", "authenticity_token", "utf8"),
|
|
167
|
+
button("Submit")
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### No Parameter Request
|
|
172
|
+
|
|
173
|
+
Send a request without any form data, useful for server-side-only actions:
|
|
174
|
+
|
|
175
|
+
```scala
|
|
176
|
+
import zio.blocks.html._
|
|
177
|
+
import zio.http.htmx._
|
|
178
|
+
|
|
179
|
+
button(
|
|
180
|
+
hxPost := "/logout",
|
|
181
|
+
hxParams := HxParams.None,
|
|
182
|
+
"Logout"
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Integration with Request Control
|
|
187
|
+
|
|
188
|
+
`HxParams` works with other request-control attributes like `hxEncoding` and `hxSync`:
|
|
189
|
+
|
|
190
|
+
```scala
|
|
191
|
+
import zio.blocks.html._
|
|
192
|
+
import zio.http.htmx._
|
|
193
|
+
|
|
194
|
+
form(
|
|
195
|
+
hxPost := "/upload",
|
|
196
|
+
hxParams := HxParams.only("file", "description"),
|
|
197
|
+
hxEncoding := HxEncoding.Multipart,
|
|
198
|
+
input(name := "file", `type` := "file"),
|
|
199
|
+
input(name := "description"),
|
|
200
|
+
button("Upload")
|
|
201
|
+
)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
The `ToHtmxValue[HxParams]` instance renders automatically, so `HxParams` values work seamlessly with the `hxParams` attribute key.
|