@zio.dev/zio-blocks 0.0.51 → 0.0.55
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/adr/2026-07-18-data-migration.md +123 -0
- package/guides/async-getting-started.md +687 -0
- package/guides/compile-time-resource-safety-with-scope.md +6 -0
- package/guides/getting-started-with-mux.md +0 -112
- package/guides/query-dsl-extending.md +1 -1
- package/guides/query-dsl-fluent-builder.md +1 -1
- package/guides/query-dsl-reified-optics.md +1 -1
- package/guides/query-dsl-sql.md +395 -1
- package/guides/sql-checked-interpolation.md +173 -0
- package/guides/sql-transactions.md +286 -0
- package/guides/telemetry-guide.md +131 -70
- package/guides/zio-schema-migration.md +6 -6
- package/index.md +200 -583
- package/package.json +1 -1
- package/reference/async.md +1379 -531
- package/reference/chunk.md +3 -3
- package/reference/codegen/index.md +1 -1
- package/reference/combinators.md +4 -4
- package/reference/config/config-decoder.md +460 -0
- package/reference/config/config-source.md +489 -0
- package/reference/config/errors.md +278 -0
- package/reference/config/flags.md +369 -0
- package/reference/config/formats.md +314 -0
- package/reference/config/index.md +304 -0
- package/reference/config/rollout.md +336 -0
- package/reference/context.md +6 -49
- package/reference/data-migration.md +269 -0
- package/reference/datastar/attributes.md +302 -0
- package/reference/datastar/events.md +234 -0
- package/reference/datastar/index.md +256 -0
- package/reference/datastar/signals.md +230 -0
- package/reference/datastar/sse.md +295 -0
- package/reference/datastar.md +2 -2
- package/reference/docs.md +2 -2
- package/reference/endpoint/bulk-creation.md +96 -0
- package/reference/endpoint/index.md +9 -89
- package/reference/endpoint/path-codec.md +12 -24
- package/reference/endpoint/route-pattern.md +4 -6
- package/reference/endpoint/segment-codec.md +19 -32
- package/reference/html.md +313 -9
- package/reference/htmx/index.md +4 -52
- package/reference/htmx/response-headers.md +240 -0
- package/reference/http-model/headers.md +735 -0
- package/reference/http-model/index.md +3 -1
- package/reference/http-model/model.md +107 -71
- package/reference/http-model/schema-codecs.md +522 -0
- package/reference/http-model/schema.md +6 -3
- package/reference/http-model/server-sent-event.md +341 -0
- package/reference/jwt.md +195 -0
- package/reference/maybe.md +128 -11
- package/reference/media-type.md +2 -2
- package/reference/mux.md +254 -0
- package/reference/mux.mdx +7 -2
- package/reference/openapi.md +3 -3
- package/reference/projection.md +654 -0
- package/reference/resource-management/resource.md +2 -98
- package/reference/resource-management/scope.md +1 -209
- package/reference/resource-management/wire.md +4 -50
- package/reference/ringbuffer/advanced.mdx +1 -1
- package/reference/ringbuffer/index.mdx +3 -3
- package/reference/ringbuffer/mpmc.mdx +38 -4
- package/reference/ringbuffer/mpsc.mdx +36 -4
- package/reference/ringbuffer/spmc.mdx +1 -1
- package/reference/ringbuffer/spsc.mdx +87 -15
- package/reference/schema/allows.md +0 -96
- package/reference/schema/binding.md +2 -2
- package/reference/schema/built-in-codecs/avro.md +2 -2
- package/reference/schema/built-in-codecs/bson.md +50 -20
- package/reference/schema/built-in-codecs/csv.md +2 -2
- package/reference/schema/built-in-codecs/index.md +3 -3
- package/reference/schema/built-in-codecs/json/index.md +2 -2
- package/reference/schema/built-in-codecs/messagepack.md +3 -3
- package/reference/schema/built-in-codecs/thrift.md +2 -2
- package/reference/schema/built-in-codecs/toon.md +3 -3
- package/reference/schema/built-in-codecs/yaml.md +2 -2
- package/reference/schema/codec.md +11 -11
- package/reference/schema/dynamic-optic.md +48 -3
- package/reference/schema/dynamic-schema.md +3 -3
- package/reference/schema/index.md +2 -0
- package/reference/schema/path-interpolator.md +2 -0
- package/reference/schema/reflect-transformer.md +140 -0
- package/reference/schema/schema-evolution/as.md +4 -4
- package/reference/schema/schema-evolution/into.md +2 -2
- package/reference/schema/schema-expr.md +2 -2
- package/reference/schema/schema-search.md +263 -0
- package/reference/schema/schema.md +10 -2
- package/reference/schema/type-class-derivation.md +1 -1
- package/reference/smithy.md +502 -3
- package/reference/sql/db-codec-deriver.md +3 -3
- package/reference/sql/db-codec.md +22 -22
- package/reference/sql/db-con.md +4 -4
- package/reference/sql/db-connection.md +1 -1
- package/reference/sql/db-param.md +1 -1
- package/reference/sql/db-result-reader.md +4 -2
- package/reference/sql/db-tx.md +46 -14
- package/reference/sql/ddl.md +1 -1
- package/reference/sql/frag.md +44 -10
- package/reference/sql/index.md +7 -7
- package/reference/sql/repo.md +15 -15
- package/reference/sql/sql-dialect.md +1 -1
- package/reference/sql/sql-logger.md +1 -1
- package/reference/sql/sql-name-mapper.md +3 -3
- package/reference/sql/table-metadata.md +3 -3
- package/reference/sql/table.md +10 -10
- package/reference/sql/transactor-zio.md +1 -1
- package/reference/sql/transactor.md +21 -11
- package/reference/sql-zio.md +1 -1
- package/reference/streams/core/index.md +32 -0
- package/reference/streams/{pipeline.md → core/pipeline.md} +210 -74
- package/reference/streams/{sink.md → core/sink.md} +331 -353
- package/reference/streams/{stream.md → core/stream.md} +919 -209
- package/reference/streams/execution-and-compatibility/async-execution.md +822 -0
- package/reference/streams/execution-and-compatibility/index.md +35 -0
- package/reference/streams/execution-and-compatibility/platform-differences.md +297 -0
- package/reference/streams/execution-and-compatibility/scala-2-compatibility.md +88 -0
- package/reference/streams/execution-and-compatibility/zero-boxing.md +393 -0
- package/reference/streams/index.md +140 -67
- package/reference/streams/primitives/index.md +30 -0
- package/reference/streams/primitives/reader.md +1992 -0
- package/reference/streams/{writer.md → primitives/writer.md} +254 -98
- package/reference/telemetry/common/any-value.md +90 -0
- package/reference/telemetry/common/attribute-key.md +87 -0
- package/reference/telemetry/common/attributes.md +118 -0
- package/reference/telemetry/common/index.md +39 -0
- package/reference/telemetry/common/instrumentation-scope.md +24 -0
- package/reference/telemetry/common/resource.md +34 -0
- package/reference/telemetry/index.md +311 -0
- package/reference/telemetry/logging/index.md +197 -0
- package/reference/telemetry/logging/log-enrichment.md +72 -0
- package/reference/telemetry/logging/log-formatter.md +100 -0
- package/reference/telemetry/logging/log-record-processor.md +56 -0
- package/reference/telemetry/logging/log-record.md +44 -0
- package/reference/telemetry/logging/log-writer.md +64 -0
- package/reference/telemetry/logging/logger-provider.md +142 -0
- package/reference/telemetry/logging/logger.md +83 -0
- package/reference/telemetry/logging/severity.md +62 -0
- package/reference/telemetry/metrics/index.md +150 -0
- package/reference/telemetry/metrics/instruments.md +183 -0
- package/reference/telemetry/metrics/labeled-instruments.md +74 -0
- package/reference/telemetry/metrics/meter-provider.md +76 -0
- package/reference/telemetry/metrics/meter.md +98 -0
- package/reference/telemetry/metrics/metric-data.md +57 -0
- package/reference/telemetry/otel/custom-exporter.md +216 -0
- package/reference/telemetry/otel/index.md +212 -0
- package/reference/telemetry/tracing/index.md +155 -0
- package/reference/telemetry/tracing/sampler.md +89 -0
- package/reference/telemetry/tracing/span-builder.md +57 -0
- package/reference/telemetry/tracing/span-context.md +39 -0
- package/reference/telemetry/tracing/span-data.md +32 -0
- package/reference/telemetry/tracing/span-kind.md +55 -0
- package/reference/telemetry/tracing/span-processor.md +53 -0
- package/reference/telemetry/tracing/span-status.md +47 -0
- package/reference/telemetry/tracing/span.md +117 -0
- package/reference/telemetry/tracing/tracer-provider.md +91 -0
- package/reference/telemetry/tracing/tracer.md +52 -0
- package/reference/typeid.md +0 -64
- package/sidebars.js +150 -12
- package/undocumented-report.md +528 -270
- package/reference/config.md +0 -158
- package/reference/streams/concurrent-operators.md +0 -106
- package/reference/streams/reader.md +0 -1284
- package/reference/streams/scala-2-compatibility.md +0 -55
- package/reference/streams/zero-boxing.md +0 -275
- package/reference/telemetry.md +0 -693
package/reference/html.md
CHANGED
|
@@ -20,6 +20,18 @@ sealed trait Dom.Element extends Dom
|
|
|
20
20
|
case class Dom.Element.Generic(tag: String, attributes: Chunk[Dom.Attribute], children: Chunk[Dom]) extends Dom.Element
|
|
21
21
|
case class Dom.Element.Script(attributes: Chunk[Dom.Attribute], children: Chunk[Dom]) extends Dom.Element
|
|
22
22
|
case class Dom.Element.Style(attributes: Chunk[Dom.Attribute], children: Chunk[Dom]) extends Dom.Element
|
|
23
|
+
sealed trait Dom.Element.Void extends Dom // void elements (self-closing, no children)
|
|
24
|
+
case class Dom.Element.VoidGeneric(tag: String, attributes: Chunk[Dom.Attribute]) extends Dom.Element.Void
|
|
25
|
+
|
|
26
|
+
// Sealed content-model markers (implemented by dedicated element classes)
|
|
27
|
+
sealed trait Dom.Element.Li extends Dom.Element // <li>, child of ul/ol
|
|
28
|
+
sealed trait Dom.Element.Cell extends Dom.Element // <th> or <td>, child of tr
|
|
29
|
+
sealed trait Dom.Element.Th extends Dom.Element.Cell
|
|
30
|
+
sealed trait Dom.Element.Td extends Dom.Element.Cell
|
|
31
|
+
sealed trait Dom.Element.Tr extends Dom.Element // <tr>, child of table
|
|
32
|
+
sealed trait Dom.Element.SelectChild extends Dom.Element // <option> or <optgroup>, child of select
|
|
33
|
+
sealed trait Dom.Element.Opt extends Dom.Element.SelectChild
|
|
34
|
+
sealed trait Dom.Element.Optgroup extends Dom.Element.SelectChild
|
|
23
35
|
|
|
24
36
|
// Attribute variants
|
|
25
37
|
sealed trait Dom.Attribute
|
|
@@ -65,13 +77,13 @@ Template engines with runtime parsing add overhead and complexity:
|
|
|
65
77
|
Add to `build.sbt`:
|
|
66
78
|
|
|
67
79
|
```
|
|
68
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-html" % "0.0.
|
|
80
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-html" % "0.0.55"
|
|
69
81
|
```
|
|
70
82
|
|
|
71
83
|
For Scala.js projects, use `%%%`:
|
|
72
84
|
|
|
73
85
|
```
|
|
74
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-html" % "0.0.
|
|
86
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-html" % "0.0.55"
|
|
75
87
|
```
|
|
76
88
|
|
|
77
89
|
Supported Scala versions: 2.13.x and 3.x
|
|
@@ -88,7 +100,7 @@ The module is organized around five core subsystems that compose together:
|
|
|
88
100
|
┌─────────────────────────────────────────────────────┐
|
|
89
101
|
│ DSL Functions (div, p, span, ...) │
|
|
90
102
|
│ + Attribute Builders (id :=, className +=) │
|
|
91
|
-
│ └─> Produces:
|
|
103
|
+
│ └─> Produces: Generic / Void element nodes │
|
|
92
104
|
│ │
|
|
93
105
|
├─────────────────────────────────────────────────────┤
|
|
94
106
|
│ String Interpolators (html"", css"", js"") │
|
|
@@ -101,6 +113,7 @@ The module is organized around five core subsystems that compose together:
|
|
|
101
113
|
│ Dom ADT (sealed trait Dom) │
|
|
102
114
|
│ ├─> Dom.Text (HTML-escaped text content) │
|
|
103
115
|
│ ├─> Dom.Element (Generic, Script, Style) │
|
|
116
|
+
│ ├─> Dom.Element.Void (void/self-closing elements) │
|
|
104
117
|
│ ├─> Dom.Doctype (<!DOCTYPE html>) │
|
|
105
118
|
│ └─> Dom.Empty (renders to nothing) │
|
|
106
119
|
│ │
|
|
@@ -131,9 +144,9 @@ The module is organized around five core subsystems that compose together:
|
|
|
131
144
|
|
|
132
145
|
The `Dom` sealed trait is the core data model. Everything in the module works with or produces `Dom` nodes.
|
|
133
146
|
|
|
134
|
-
### The
|
|
147
|
+
### The Five Node Types
|
|
135
148
|
|
|
136
|
-
A `Dom` tree is composed of
|
|
149
|
+
A `Dom` tree is composed of five node types:
|
|
137
150
|
|
|
138
151
|
#### Dom.Text
|
|
139
152
|
|
|
@@ -447,9 +460,64 @@ val card = div(
|
|
|
447
460
|
))
|
|
448
461
|
```
|
|
449
462
|
|
|
450
|
-
### Void
|
|
463
|
+
### Dom.Element.Void
|
|
451
464
|
|
|
452
|
-
Void elements (
|
|
465
|
+
Void HTML elements (`br`, `hr`, `img`, `input`, `meta`, `link`, `area`, `base`, `col`, `embed`, `param`, `source`, `track`, `wbr`) are a **separate type** from `Dom.Element` — they extend `Dom.Element.Void` which extends `Dom` directly (not `Dom.Element`). This means they **structurally cannot have children** — passing a modifier like a string or another element to a void element factory is a **compile-time error**:
|
|
466
|
+
|
|
467
|
+
```scala
|
|
468
|
+
import zio.blocks.html._
|
|
469
|
+
|
|
470
|
+
img("oops") // ❌ does not compile — Void elements don't accept children
|
|
471
|
+
input(div("child")) // ❌ does not compile — Void elements don't accept children
|
|
472
|
+
// error:
|
|
473
|
+
// Found: ("oops" : String)
|
|
474
|
+
// Required: zio.blocks.html.Dom.Attribute
|
|
475
|
+
// error:
|
|
476
|
+
// Found: zio.blocks.html.Dom.Element
|
|
477
|
+
// Required: zio.blocks.html.Dom.Attribute
|
|
478
|
+
// error:
|
|
479
|
+
// Conflicting definitions:
|
|
480
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 17 and
|
|
481
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 20
|
|
482
|
+
//
|
|
483
|
+
// error:
|
|
484
|
+
// Conflicting definitions:
|
|
485
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 20 and
|
|
486
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 26
|
|
487
|
+
//
|
|
488
|
+
// error:
|
|
489
|
+
// Conflicting definitions:
|
|
490
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 26 and
|
|
491
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 29
|
|
492
|
+
//
|
|
493
|
+
// error:
|
|
494
|
+
// Conflicting definitions:
|
|
495
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 50 and
|
|
496
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 74
|
|
497
|
+
//
|
|
498
|
+
// error:
|
|
499
|
+
// Conflicting definitions:
|
|
500
|
+
// val link: zio.blocks.html.Dom.Element in object MdocApp at line 43 and
|
|
501
|
+
// val link: zio.blocks.html.Dom.Element in object MdocApp at line 76
|
|
502
|
+
//
|
|
503
|
+
// error:
|
|
504
|
+
// Conflicting definitions:
|
|
505
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 74 and
|
|
506
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 79
|
|
507
|
+
//
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Void elements only accept `Dom.Attribute` arguments:
|
|
511
|
+
|
|
512
|
+
```scala
|
|
513
|
+
import zio.blocks.html._
|
|
514
|
+
|
|
515
|
+
val image = img(src := "photo.jpg", alt := "A photo") // ✅ compiles — only attributes
|
|
516
|
+
val lineBreak = br // ✅ compiles — no args
|
|
517
|
+
val textField = input(`type` := "text", placeholder := "Enter text") // ✅ compiles
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Void elements render as self-closing tags:
|
|
453
521
|
|
|
454
522
|
```scala
|
|
455
523
|
import zio.blocks.html._
|
|
@@ -462,6 +530,150 @@ val voidElements = div(
|
|
|
462
530
|
)
|
|
463
531
|
```
|
|
464
532
|
|
|
533
|
+
## Typed Content Models
|
|
534
|
+
|
|
535
|
+
Several container elements enforce the HTML content model of their children at
|
|
536
|
+
compile time. Instead of accepting arbitrary modifiers, these factories only
|
|
537
|
+
accept attributes plus children whose type matches the content model:
|
|
538
|
+
|
|
539
|
+
| Factory | Accepted element children | Marker type |
|
|
540
|
+
|---|---|---|
|
|
541
|
+
| `ul(...)`, `ol(...)` | `<li>` | `Dom.Element.Li` |
|
|
542
|
+
| `tr(...)` | `<th>`, `<td>` | `Dom.Element.Cell` (`Th \| Td`) |
|
|
543
|
+
| `table(...)` | `<tr>` | `Dom.Element.Tr` |
|
|
544
|
+
| `select(...)` | `<option>`, `<optgroup>` | `Dom.Element.SelectChild` (`Opt \| Optgroup`) |
|
|
545
|
+
| `optgroup(...)` | `<option>` | `Dom.Element.Opt` |
|
|
546
|
+
|
|
547
|
+
Invalid children are rejected by the compiler:
|
|
548
|
+
|
|
549
|
+
```scala
|
|
550
|
+
import zio.blocks.html._
|
|
551
|
+
|
|
552
|
+
ul(div("not a list item")) // ❌ does not compile — ul only accepts Li children
|
|
553
|
+
tr(p("not a cell")) // ❌ does not compile — tr only accepts Th/Td cells
|
|
554
|
+
select(div("not an option")) // ❌ does not compile — select only accepts option/optgroup
|
|
555
|
+
// error:
|
|
556
|
+
// None of the overloaded alternatives of method ul in trait HtmlElements with types
|
|
557
|
+
// (children: Iterable[zio.blocks.html.Dom.Element.Li]):
|
|
558
|
+
// zio.blocks.html.Dom.Element
|
|
559
|
+
// (effect: zio.blocks.html.Dom.Attribute | zio.blocks.html.Dom.Element.Li, effects
|
|
560
|
+
// : (zio.blocks.html.Dom.Attribute | zio.blocks.html.Dom.Element.Li)*):
|
|
561
|
+
// zio.blocks.html.Dom.Element
|
|
562
|
+
// (): zio.blocks.html.Dom.Element
|
|
563
|
+
// match arguments (zio.blocks.html.Dom.Element)
|
|
564
|
+
// error:
|
|
565
|
+
// None of the overloaded alternatives of method tr in trait HtmlElements with types
|
|
566
|
+
// (children: Iterable[zio.blocks.html.Dom.Element.Cell]):
|
|
567
|
+
// zio.blocks.html.Dom.Element.Tr
|
|
568
|
+
// (effect: zio.blocks.html.Dom.Attribute | zio.blocks.html.Dom.Element.Cell,
|
|
569
|
+
// effects: (zio.blocks.html.Dom.Attribute | zio.blocks.html.Dom.Element.Cell)*)
|
|
570
|
+
// : zio.blocks.html.Dom.Element.Tr
|
|
571
|
+
// (): zio.blocks.html.Dom.Element.Tr
|
|
572
|
+
// match arguments (zio.blocks.html.Dom.Element)
|
|
573
|
+
// error:
|
|
574
|
+
// None of the overloaded alternatives of method select in trait HtmlElements with types
|
|
575
|
+
// (children: Iterable[zio.blocks.html.Dom.Element.SelectChild]):
|
|
576
|
+
// zio.blocks.html.Dom.Element
|
|
577
|
+
// (
|
|
578
|
+
// effect: zio.blocks.html.Dom.Attribute |
|
|
579
|
+
// zio.blocks.html.Dom.Element.SelectChild,
|
|
580
|
+
// effects: (zio.blocks.html.Dom.Attribute |
|
|
581
|
+
// zio.blocks.html.Dom.Element.SelectChild)*): zio.blocks.html.Dom.Element
|
|
582
|
+
// (): zio.blocks.html.Dom.Element
|
|
583
|
+
// match arguments (zio.blocks.html.Dom.Element)
|
|
584
|
+
// select(div("not an option")) // ❌ does not compile — select only accepts option/optgroup
|
|
585
|
+
// ^^^^^^
|
|
586
|
+
// error:
|
|
587
|
+
// Conflicting definitions:
|
|
588
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 17 and
|
|
589
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 20
|
|
590
|
+
//
|
|
591
|
+
// error:
|
|
592
|
+
// Conflicting definitions:
|
|
593
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 20 and
|
|
594
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 26
|
|
595
|
+
//
|
|
596
|
+
// error:
|
|
597
|
+
// Conflicting definitions:
|
|
598
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 26 and
|
|
599
|
+
// val tree: zio.blocks.html.Dom.Element in object MdocApp at line 29
|
|
600
|
+
//
|
|
601
|
+
// error:
|
|
602
|
+
// Conflicting definitions:
|
|
603
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 50 and
|
|
604
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 74
|
|
605
|
+
//
|
|
606
|
+
// error:
|
|
607
|
+
// Conflicting definitions:
|
|
608
|
+
// val link: zio.blocks.html.Dom.Element in object MdocApp at line 43 and
|
|
609
|
+
// val link: zio.blocks.html.Dom.Element in object MdocApp at line 76
|
|
610
|
+
//
|
|
611
|
+
// error:
|
|
612
|
+
// Conflicting definitions:
|
|
613
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 74 and
|
|
614
|
+
// val div1: zio.blocks.html.Dom.Element in object MdocApp at line 79
|
|
615
|
+
//
|
|
616
|
+
// error:
|
|
617
|
+
// Conflicting definitions:
|
|
618
|
+
// val image: zio.blocks.html.Dom.Element.Void in object MdocApp at line 38 and
|
|
619
|
+
// val image: zio.blocks.html.Dom.Element.Void in object MdocApp at line 103
|
|
620
|
+
//
|
|
621
|
+
// error:
|
|
622
|
+
// Conflicting definitions:
|
|
623
|
+
// val lineBreak: zio.blocks.html.Dom.Element.Void in object MdocApp at line 39 and
|
|
624
|
+
// val lineBreak: zio.blocks.html.Dom.Element.Void in object MdocApp at line 104
|
|
625
|
+
//
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Attributes are accepted alongside the constrained children:
|
|
629
|
+
|
|
630
|
+
```scala
|
|
631
|
+
import zio.blocks.html._
|
|
632
|
+
|
|
633
|
+
val list = ul(id := "menu", className := "nav", li("Home"), li("About"))
|
|
634
|
+
val row = tr(className := "header-row", th("Name"), td("Value"))
|
|
635
|
+
val picker = select(id := "color", name := "color", option("Red"), optgroup(option("Light"), option("Dark")))
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
Each factory has three forms: empty (`ul()`), mixed attributes and children
|
|
639
|
+
(`ul(id := "x", li("a"))`), and collections of children
|
|
640
|
+
(`ul(items.map(item => li(item)))`).
|
|
641
|
+
|
|
642
|
+
The typed factories produce elements carrying a sealed marker type (`Li`,
|
|
643
|
+
`Cell`, `Tr`, `SelectChild`, ...). The markers are sealed — their
|
|
644
|
+
implementations live inside the module — so a value typed `Dom.Element.Li` is
|
|
645
|
+
guaranteed to render as `<li>`; the DSL factories are the intended
|
|
646
|
+
construction path. Elements with permissive content models (`li`, `th`, `td`,
|
|
647
|
+
`option`) keep accepting any flow content through the regular modifier API.
|
|
648
|
+
|
|
649
|
+
:::note
|
|
650
|
+
`caption`, `colgroup`, `thead`, `tbody`, and `tfoot` do not have typed markers
|
|
651
|
+
yet, so tables containing them cannot be built with the `table(...)`
|
|
652
|
+
factory. Compose those tables with the `html""` interpolator or generic
|
|
653
|
+
elements.
|
|
654
|
+
:::
|
|
655
|
+
|
|
656
|
+
### Equality Across Element Classes
|
|
657
|
+
|
|
658
|
+
Element equality is structural (tag + attributes + children + text-escaping
|
|
659
|
+
semantics), independent of the concrete class. A factory-produced `li(...)`
|
|
660
|
+
equals the structurally identical `Generic("li", ...)`, and vice versa; equal
|
|
661
|
+
elements also have equal hash codes:
|
|
662
|
+
|
|
663
|
+
```scala
|
|
664
|
+
import zio.blocks.html._
|
|
665
|
+
import zio.blocks.chunk.Chunk
|
|
666
|
+
|
|
667
|
+
val fromFactory = li("a")
|
|
668
|
+
val generic = Dom.Element.Generic("li", Chunk.empty, Chunk(Dom.Text("a")))
|
|
669
|
+
fromFactory == generic // true — structural equality across classes
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
Elements that render differently are never equal, even with identical fields:
|
|
673
|
+
`script`/`style` render their children **unescaped** while `Generic` escapes
|
|
674
|
+
them, so a `Script` never equals an equally-shaped `Generic("script", ...)` —
|
|
675
|
+
equal elements always render identically.
|
|
676
|
+
|
|
465
677
|
## String Interpolators
|
|
466
678
|
|
|
467
679
|
The module provides four string interpolators: `html""`, `css""`, `js""`, and `selector""`. All offer compile-time safety (on Scala 3) and automatic escaping appropriate to their context.
|
|
@@ -622,8 +834,8 @@ Pseudo-classes match elements by their state, and pseudo-elements create dynamic
|
|
|
622
834
|
import zio.blocks.html._
|
|
623
835
|
|
|
624
836
|
val hoverSel = a.hover // a:hover
|
|
625
|
-
val firstChild = li.firstChild // li:first-child
|
|
626
|
-
val nthChild = tr.nthChild(2) // tr:nth-child(2)
|
|
837
|
+
val firstChild = li().firstChild // li:first-child
|
|
838
|
+
val nthChild = tr().nthChild(2) // tr:nth-child(2)
|
|
627
839
|
val before = div.before // div::before
|
|
628
840
|
val after = span.after // span::after
|
|
629
841
|
```
|
|
@@ -774,6 +986,98 @@ All `Css` subtypes support `.render()` for minified output and `.render(indent:
|
|
|
774
986
|
- `Css.Raw` — raw CSS string
|
|
775
987
|
- `Css.Comment` — CSS comment
|
|
776
988
|
|
|
989
|
+
### Typed Values: Lengths and Colors
|
|
990
|
+
|
|
991
|
+
A `Css.Declaration` takes its value as a `String`, so nothing stops `"10pixels"` or `"#gggggg"` from reaching a stylesheet. `CssLength` and `CssColor` are the typed alternatives: each validates on construction and renders itself, so an invalid value cannot be built rather than being caught downstream.
|
|
992
|
+
|
|
993
|
+
`CssLength` pairs a numeric value with a unit, and rejects units outside the CSS set — `px`, `em`, `rem`, `%`, `vh`, `vw`, `ch`, `ex`, `vmin`, `vmax`, `cm`, `mm`, `in`, `pt`, `pc`:
|
|
994
|
+
|
|
995
|
+
```scala
|
|
996
|
+
import zio.blocks.html._
|
|
997
|
+
import zio.blocks.html.CssLength._
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
The second import is what brings the numeric extension methods into scope. They live in `object CssLength` rather than the package, so `import zio.blocks.html._` alone gives you the `CssLength` constructor but not `300.px`.
|
|
1001
|
+
|
|
1002
|
+
Writing the constructor directly works, but the extension methods on `Int` and `Double` are shorter and produce the same value:
|
|
1003
|
+
|
|
1004
|
+
```scala
|
|
1005
|
+
CssLength(300.0, "px").render
|
|
1006
|
+
// res45: String = "300px"
|
|
1007
|
+
300.px.render
|
|
1008
|
+
// res46: String = "300px"
|
|
1009
|
+
1.5.rem.render
|
|
1010
|
+
// res47: String = "1.5rem"
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
`CssLengthIntOps` and `CssLengthDoubleOps` provide `px`, `em`, `rem`, `pct`, `vh`, and `vw` on numeric literals. `pct` is spelled out because `%` is not a legal method name:
|
|
1014
|
+
|
|
1015
|
+
```scala
|
|
1016
|
+
50.pct.render
|
|
1017
|
+
// res48: String = "50%"
|
|
1018
|
+
100.vh.render
|
|
1019
|
+
// res49: String = "100vh"
|
|
1020
|
+
```
|
|
1021
|
+
|
|
1022
|
+
A whole-number `Double` renders without its decimal point, so `2.0.em` and `2.em` produce identical CSS:
|
|
1023
|
+
|
|
1024
|
+
```scala
|
|
1025
|
+
2.0.em.render
|
|
1026
|
+
// res50: String = "2em"
|
|
1027
|
+
2.em.render
|
|
1028
|
+
// res51: String = "2em"
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
`CssColor` is a sealed ADT with five cases, covering the notations CSS accepts:
|
|
1032
|
+
|
|
1033
|
+
| Case | Constructor | Renders as |
|
|
1034
|
+
| ---------------------- | --------------------------------- | ----------------------- |
|
|
1035
|
+
| `CssColor.Hex` | `Hex(value)` / `Hex.unsafe(value)` | `#ff0000` |
|
|
1036
|
+
| `CssColor.Rgb` | `Rgb(r, g, b)` | `rgb(255,0,0)` |
|
|
1037
|
+
| `CssColor.Rgba` | `Rgba(r, g, b, a)` | `rgba(255,0,0,0.5)` |
|
|
1038
|
+
| `CssColor.Hsl` | `Hsl(h, s, l)` | `hsl(0,100%,50%)` |
|
|
1039
|
+
| `CssColor.Named` | `Named(name)` | `red` |
|
|
1040
|
+
|
|
1041
|
+
The numeric cases are plain case classes, so they need no validation step:
|
|
1042
|
+
|
|
1043
|
+
```scala
|
|
1044
|
+
CssColor.Rgb(255, 0, 0).render
|
|
1045
|
+
// res52: String = "rgb(255,0,0)"
|
|
1046
|
+
CssColor.Rgba(255, 0, 0, 0.5).render
|
|
1047
|
+
// res53: String = "rgba(255,0,0,0.5)"
|
|
1048
|
+
CssColor.Hsl(0, 100, 50).render
|
|
1049
|
+
// res54: String = "hsl(0,100%,50%)"
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
`Hsl` renders its saturation and lightness with percent signs while taking them as bare `Int`s, so pass `100` rather than `1.0` for full saturation.
|
|
1053
|
+
|
|
1054
|
+
`CssColor.Hex` and `CssColor.Named` are the two validated cases, and both return an `Option` from `CssColor.Hex.apply` rather than throwing:
|
|
1055
|
+
|
|
1056
|
+
```scala
|
|
1057
|
+
CssColor.Hex("ff0000")
|
|
1058
|
+
// res55: Option[CssColor] = Some(Hex("ff0000"))
|
|
1059
|
+
CssColor.Hex("gggggg")
|
|
1060
|
+
// res56: Option[CssColor] = None
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
A leading `#` is optional and the value is lowercased, so the same colour written four ways yields one representation:
|
|
1064
|
+
|
|
1065
|
+
```scala
|
|
1066
|
+
CssColor.Hex("#FF0000").map(_.render)
|
|
1067
|
+
// res57: Option[String] = Some("#ff0000")
|
|
1068
|
+
```
|
|
1069
|
+
|
|
1070
|
+
`CssColor.Hex.unsafe` skips validation for literals you know are well-formed. It returns a `CssColor` directly rather than an `Option`, which is what makes it convenient inside an interpolator — and what makes it unsuitable for anything user-supplied:
|
|
1071
|
+
|
|
1072
|
+
```scala
|
|
1073
|
+
CssColor.Hex.unsafe("ff0000").render
|
|
1074
|
+
// res58: String = "#ff0000"
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
:::warning[`unsafe` renders whatever it is given]
|
|
1078
|
+
`CssColor.Hex.unsafe` performs no checking, so `Hex.unsafe("not-a-color")` renders as `#not-a-color` and produces a stylesheet the browser silently ignores. Use it only for compile-time literals; route anything dynamic through `CssColor.Hex.apply` and handle the `None`.
|
|
1079
|
+
:::
|
|
1080
|
+
|
|
777
1081
|
### Declarations and Rules
|
|
778
1082
|
|
|
779
1083
|
A `Css.Declaration` is a property-value pair:
|
package/reference/htmx/index.md
CHANGED
|
@@ -52,10 +52,10 @@ Add the HTMX module to your project dependencies:
|
|
|
52
52
|
|
|
53
53
|
```scala
|
|
54
54
|
// JVM
|
|
55
|
-
libraryDependencies += "dev.zio" %% "zio-blocks-http-htmx" % "0.0.
|
|
55
|
+
libraryDependencies += "dev.zio" %% "zio-blocks-http-htmx" % "0.0.55"
|
|
56
56
|
|
|
57
57
|
// Scala.js
|
|
58
|
-
libraryDependencies += "dev.zio" %%% "zio-blocks-http-htmx" % "0.0.
|
|
58
|
+
libraryDependencies += "dev.zio" %%% "zio-blocks-http-htmx" % "0.0.55"
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Supported Scala versions: Scala 3.x. The module is cross-compiled for JVM and Scala.js.
|
|
@@ -210,7 +210,7 @@ import zio.http.htmx._
|
|
|
210
210
|
input(
|
|
211
211
|
hxPost := "/search",
|
|
212
212
|
hxTrigger := HxTrigger.input.filter(Js("event.target.value.length > 2")),
|
|
213
|
-
"Only POST if search has 3+ characters"
|
|
213
|
+
placeholder := "Only POST if search has 3+ characters"
|
|
214
214
|
)
|
|
215
215
|
```
|
|
216
216
|
|
|
@@ -228,7 +228,7 @@ The `Js` type is intentionally raw—do not build it from unsanitized user input
|
|
|
228
228
|
|
|
229
229
|
**With JavaScript:** Attributes that accept raw JavaScript expressions (`hxOn:*`, `hxTrigger.filter()`) accept the `Js` type, making it explicit that you're writing unescaped JavaScript code. This prevents accidental XSS while allowing intentional dynamic behavior.
|
|
230
230
|
|
|
231
|
-
**With headers:** The `zio.http.htmx.headers` submodule provides typed HTMX request/response headers (HX-Request, HX-Trigger, HX-Redirect, etc.), letting you inspect and build headers with the same type safety as attributes.
|
|
231
|
+
**With headers:** The [`zio.http.htmx.headers`](./response-headers.md) submodule provides typed HTMX request/response headers (HX-Request, HX-Trigger, HX-Redirect, etc.), letting you inspect and build headers with the same type safety as attributes.
|
|
232
232
|
|
|
233
233
|
**Extending with custom types:** Implement `ToHtmxValue[MyType]` to let your domain types render themselves in the DSL. For example, a custom `enum Status { Active, Inactive }` defines `implicit val statusToHtmx: ToHtmxValue[Status] = ...` and renders directly in HTMX attributes.
|
|
234
234
|
|
|
@@ -252,22 +252,6 @@ cd zio-blocks
|
|
|
252
252
|
Demonstrates fundamental HTMX attribute construction: triggering requests (hxPost, hxGet), swapping strategies (InnerHTML, OuterHTML), and target selection (This, closest, find). Shows how the typed DSL ensures correct HTMX syntax at compile time. Here is the source code:
|
|
253
253
|
|
|
254
254
|
```scala title="zio-blocks-htmx-examples/src/main/scala/zioBlocksHtmx/BasicUsage.scala"
|
|
255
|
-
/*
|
|
256
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
257
|
-
*
|
|
258
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
259
|
-
* you may not use this file except in compliance with the License.
|
|
260
|
-
* You may obtain a copy of the License at
|
|
261
|
-
*
|
|
262
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
263
|
-
*
|
|
264
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
265
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
266
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
267
|
-
* See the License for the specific language governing permissions and
|
|
268
|
-
* limitations under the License.
|
|
269
|
-
*/
|
|
270
|
-
|
|
271
255
|
package zioBlocksHtmx
|
|
272
256
|
|
|
273
257
|
import zio.blocks.html._
|
|
@@ -409,22 +393,6 @@ sbt "zio-blocks-htmx-examples/runMain zioBlocksHtmx.BasicUsage"
|
|
|
409
393
|
Demonstrates complex HTMX interactions: combining multiple triggers, chaining modifiers, controlling request queuing, animation with transitions, and JavaScript-based filtering. Shows how modifiers compose to create sophisticated client-side behaviors. Here is the source code:
|
|
410
394
|
|
|
411
395
|
```scala title="zio-blocks-htmx-examples/src/main/scala/zioBlocksHtmx/AdvancedPatterns.scala"
|
|
412
|
-
/*
|
|
413
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
414
|
-
*
|
|
415
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
416
|
-
* you may not use this file except in compliance with the License.
|
|
417
|
-
* You may obtain a copy of the License at
|
|
418
|
-
*
|
|
419
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
420
|
-
*
|
|
421
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
422
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
423
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
424
|
-
* See the License for the specific language governing permissions and
|
|
425
|
-
* limitations under the License.
|
|
426
|
-
*/
|
|
427
|
-
|
|
428
396
|
package zioBlocksHtmx
|
|
429
397
|
|
|
430
398
|
import zio.blocks.html._
|
|
@@ -629,22 +597,6 @@ sbt "zio-blocks-htmx-examples/runMain zioBlocksHtmx.AdvancedPatterns"
|
|
|
629
597
|
A realistic e-commerce search and filtering interface combining multiple HTMX attributes: debounced search input, live category filtering, paginated results, out-of-band notifications, and dynamic UI updates. Demonstrates how types compose to create a type-safe, interactive UI. Here is the source code:
|
|
630
598
|
|
|
631
599
|
```scala title="zio-blocks-htmx-examples/src/main/scala/zioBlocksHtmx/CompleteExample.scala"
|
|
632
|
-
/*
|
|
633
|
-
* Copyright 2024-2026 John A. De Goes and the ZIO Contributors
|
|
634
|
-
*
|
|
635
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
636
|
-
* you may not use this file except in compliance with the License.
|
|
637
|
-
* You may obtain a copy of the License at
|
|
638
|
-
*
|
|
639
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
640
|
-
*
|
|
641
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
642
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
643
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
644
|
-
* See the License for the specific language governing permissions and
|
|
645
|
-
* limitations under the License.
|
|
646
|
-
*/
|
|
647
|
-
|
|
648
600
|
package zioBlocksHtmx
|
|
649
601
|
|
|
650
602
|
import zio.blocks.html._
|