summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPgBiel <9021226+PgBiel@users.noreply.github.com>2025-06-10 11:41:16 -0300
committerGitHub <noreply@github.com>2025-06-10 14:41:16 +0000
commit7c7b962b98a09c1baabdd03ff4ccad8f6d817b37 (patch)
treec44c9b82e3c7ec7bf8feb44cedeae9fa71a107cb /tests
parenta18ca3481da17a4de1cc7f9890f0c61efb480655 (diff)
Table multiple headers and subheaders (#6168)
Diffstat (limited to 'tests')
-rw-r--r--tests/ref/grid-footer-non-repeatable-unbreakable.pngbin0 -> 365 bytes
-rw-r--r--tests/ref/grid-footer-repeatable-unbreakable.pngbin0 -> 340 bytes
-rw-r--r--tests/ref/grid-header-and-large-auto-contiguous.pngbin0 -> 894 bytes
-rw-r--r--tests/ref/grid-header-and-rowspan-contiguous-1.pngbin0 -> 815 bytes
-rw-r--r--tests/ref/grid-header-and-rowspan-contiguous-2.pngbin0 -> 815 bytes
-rw-r--r--tests/ref/grid-header-multiple.pngbin0 -> 214 bytes
-rw-r--r--tests/ref/grid-header-non-repeating-orphan-prevention.pngbin0 -> 453 bytes
-rw-r--r--tests/ref/grid-header-not-at-first-row-two-columns.pngbin0 -> 176 bytes
-rw-r--r--tests/ref/grid-header-not-at-first-row.pngbin0 -> 176 bytes
-rw-r--r--tests/ref/grid-header-not-at-the-top.pngbin0 -> 605 bytes
-rw-r--r--tests/ref/grid-header-replace-doesnt-fit.pngbin0 -> 559 bytes
-rw-r--r--tests/ref/grid-header-replace-orphan.pngbin0 -> 559 bytes
-rw-r--r--tests/ref/grid-header-replace.pngbin0 -> 692 bytes
-rw-r--r--tests/ref/grid-header-skip.pngbin0 -> 432 bytes
-rw-r--r--tests/ref/grid-header-too-large-non-repeating-orphan.pngbin0 -> 372 bytes
-rw-r--r--tests/ref/grid-header-too-large-repeating-orphan-not-at-first-row.pngbin0 -> 398 bytes
-rw-r--r--tests/ref/grid-header-too-large-repeating-orphan-with-footer.pngbin0 -> 576 bytes
-rw-r--r--tests/ref/grid-header-too-large-repeating-orphan.pngbin0 -> 321 bytes
-rw-r--r--tests/ref/grid-subheaders-alone-no-orphan-prevention.pngbin0 -> 254 bytes
-rw-r--r--tests/ref/grid-subheaders-alone-with-footer-no-orphan-prevention.pngbin0 -> 378 bytes
-rw-r--r--tests/ref/grid-subheaders-alone-with-footer.pngbin0 -> 319 bytes
-rw-r--r--tests/ref/grid-subheaders-alone-with-gutter-and-footer-no-orphan-prevention.pngbin0 -> 382 bytes
-rw-r--r--tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.pngbin0 -> 254 bytes
-rw-r--r--tests/ref/grid-subheaders-alone.pngbin0 -> 256 bytes
-rw-r--r--tests/ref/grid-subheaders-basic-non-consecutive-with-footer.pngbin0 -> 279 bytes
-rw-r--r--tests/ref/grid-subheaders-basic-non-consecutive.pngbin0 -> 256 bytes
-rw-r--r--tests/ref/grid-subheaders-basic-replace.pngbin0 -> 321 bytes
-rw-r--r--tests/ref/grid-subheaders-basic-with-footer.pngbin0 -> 256 bytes
-rw-r--r--tests/ref/grid-subheaders-basic.pngbin0 -> 210 bytes
-rw-r--r--tests/ref/grid-subheaders-colorful.pngbin0 -> 11005 bytes
-rw-r--r--tests/ref/grid-subheaders-demo.pngbin0 -> 5064 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-row-right-after-with-footer.pngbin0 -> 1207 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-row-right-after.pngbin0 -> 1127 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-row-with-footer.pngbin0 -> 1345 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-row.pngbin0 -> 1173 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-rowspan-gutter.pngbin0 -> 1560 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-rowspan-right-after.pngbin0 -> 1421 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-rowspan-with-footer.pngbin0 -> 1190 bytes
-rw-r--r--tests/ref/grid-subheaders-multi-page-rowspan.pngbin0 -> 1048 bytes
-rw-r--r--tests/ref/grid-subheaders-non-repeat-replace.pngbin0 -> 878 bytes
-rw-r--r--tests/ref/grid-subheaders-non-repeat.pngbin0 -> 614 bytes
-rw-r--r--tests/ref/grid-subheaders-non-repeating-header-before-multi-page-row.pngbin0 -> 410 bytes
-rw-r--r--tests/ref/grid-subheaders-non-repeating-orphan-prevention.pngbin0 -> 347 bytes
-rw-r--r--tests/ref/grid-subheaders-non-repeating-replace-didnt-fit-once.pngbin0 -> 895 bytes
-rw-r--r--tests/ref/grid-subheaders-non-repeating-replace-orphan.pngbin0 -> 964 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-gutter.pngbin0 -> 503 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-non-consecutive.pngbin0 -> 599 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-didnt-fit-once.pngbin0 -> 877 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-double-orphan.pngbin0 -> 950 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-child.pngbin0 -> 806 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-gutter.pngbin0 -> 758 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-gutter.pngbin0 -> 782 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-multiple-levels.pngbin0 -> 877 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-orphan.pngbin0 -> 939 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-short-lived.pngbin0 -> 795 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-with-footer-orphan.pngbin0 -> 961 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace-with-footer.pngbin0 -> 992 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-replace.pngbin0 -> 953 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-short-lived-also-replaces.pngbin0 -> 899 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat-with-footer.pngbin0 -> 584 bytes
-rw-r--r--tests/ref/grid-subheaders-repeat.pngbin0 -> 472 bytes
-rw-r--r--tests/ref/grid-subheaders-repeating-orphan-prevention.pngbin0 -> 347 bytes
-rw-r--r--tests/ref/grid-subheaders-short-lived-no-orphan-prevention.pngbin0 -> 287 bytes
-rw-r--r--tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-auto.pngbin0 -> 460 bytes
-rw-r--r--tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-relative.pngbin0 -> 542 bytes
-rw-r--r--tests/ref/grid-subheaders-too-large-repeating-orphan-before-auto.pngbin0 -> 525 bytes
-rw-r--r--tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.pngbin0 -> 437 bytes
-rw-r--r--tests/ref/html/multi-header-inside-table.html69
-rw-r--r--tests/ref/html/multi-header-table.html49
-rw-r--r--tests/ref/issue-5359-column-override-stays-inside-header.pngbin0 -> 674 bytes
-rw-r--r--tests/suite/layout/grid/footers.typ23
-rw-r--r--tests/suite/layout/grid/headers.typ171
-rw-r--r--tests/suite/layout/grid/html.typ75
-rw-r--r--tests/suite/layout/grid/subheaders.typ602
74 files changed, 981 insertions, 8 deletions
diff --git a/tests/ref/grid-footer-non-repeatable-unbreakable.png b/tests/ref/grid-footer-non-repeatable-unbreakable.png
new file mode 100644
index 00000000..59d72201
--- /dev/null
+++ b/tests/ref/grid-footer-non-repeatable-unbreakable.png
Binary files differ
diff --git a/tests/ref/grid-footer-repeatable-unbreakable.png b/tests/ref/grid-footer-repeatable-unbreakable.png
new file mode 100644
index 00000000..0fa30f77
--- /dev/null
+++ b/tests/ref/grid-footer-repeatable-unbreakable.png
Binary files differ
diff --git a/tests/ref/grid-header-and-large-auto-contiguous.png b/tests/ref/grid-header-and-large-auto-contiguous.png
new file mode 100644
index 00000000..2dbaba23
--- /dev/null
+++ b/tests/ref/grid-header-and-large-auto-contiguous.png
Binary files differ
diff --git a/tests/ref/grid-header-and-rowspan-contiguous-1.png b/tests/ref/grid-header-and-rowspan-contiguous-1.png
new file mode 100644
index 00000000..7cf2cb9c
--- /dev/null
+++ b/tests/ref/grid-header-and-rowspan-contiguous-1.png
Binary files differ
diff --git a/tests/ref/grid-header-and-rowspan-contiguous-2.png b/tests/ref/grid-header-and-rowspan-contiguous-2.png
new file mode 100644
index 00000000..29bc411d
--- /dev/null
+++ b/tests/ref/grid-header-and-rowspan-contiguous-2.png
Binary files differ
diff --git a/tests/ref/grid-header-multiple.png b/tests/ref/grid-header-multiple.png
new file mode 100644
index 00000000..199cc051
--- /dev/null
+++ b/tests/ref/grid-header-multiple.png
Binary files differ
diff --git a/tests/ref/grid-header-non-repeating-orphan-prevention.png b/tests/ref/grid-header-non-repeating-orphan-prevention.png
new file mode 100644
index 00000000..d0dbc597
--- /dev/null
+++ b/tests/ref/grid-header-non-repeating-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-header-not-at-first-row-two-columns.png b/tests/ref/grid-header-not-at-first-row-two-columns.png
new file mode 100644
index 00000000..21ee5f93
--- /dev/null
+++ b/tests/ref/grid-header-not-at-first-row-two-columns.png
Binary files differ
diff --git a/tests/ref/grid-header-not-at-first-row.png b/tests/ref/grid-header-not-at-first-row.png
new file mode 100644
index 00000000..21ee5f93
--- /dev/null
+++ b/tests/ref/grid-header-not-at-first-row.png
Binary files differ
diff --git a/tests/ref/grid-header-not-at-the-top.png b/tests/ref/grid-header-not-at-the-top.png
new file mode 100644
index 00000000..96f9adcd
--- /dev/null
+++ b/tests/ref/grid-header-not-at-the-top.png
Binary files differ
diff --git a/tests/ref/grid-header-replace-doesnt-fit.png b/tests/ref/grid-header-replace-doesnt-fit.png
new file mode 100644
index 00000000..a06ce0e9
--- /dev/null
+++ b/tests/ref/grid-header-replace-doesnt-fit.png
Binary files differ
diff --git a/tests/ref/grid-header-replace-orphan.png b/tests/ref/grid-header-replace-orphan.png
new file mode 100644
index 00000000..9d116169
--- /dev/null
+++ b/tests/ref/grid-header-replace-orphan.png
Binary files differ
diff --git a/tests/ref/grid-header-replace.png b/tests/ref/grid-header-replace.png
new file mode 100644
index 00000000..dafecd7f
--- /dev/null
+++ b/tests/ref/grid-header-replace.png
Binary files differ
diff --git a/tests/ref/grid-header-skip.png b/tests/ref/grid-header-skip.png
new file mode 100644
index 00000000..9c4f294d
--- /dev/null
+++ b/tests/ref/grid-header-skip.png
Binary files differ
diff --git a/tests/ref/grid-header-too-large-non-repeating-orphan.png b/tests/ref/grid-header-too-large-non-repeating-orphan.png
new file mode 100644
index 00000000..a4e7843b
--- /dev/null
+++ b/tests/ref/grid-header-too-large-non-repeating-orphan.png
Binary files differ
diff --git a/tests/ref/grid-header-too-large-repeating-orphan-not-at-first-row.png b/tests/ref/grid-header-too-large-repeating-orphan-not-at-first-row.png
new file mode 100644
index 00000000..754509f3
--- /dev/null
+++ b/tests/ref/grid-header-too-large-repeating-orphan-not-at-first-row.png
Binary files differ
diff --git a/tests/ref/grid-header-too-large-repeating-orphan-with-footer.png b/tests/ref/grid-header-too-large-repeating-orphan-with-footer.png
new file mode 100644
index 00000000..8fff7726
--- /dev/null
+++ b/tests/ref/grid-header-too-large-repeating-orphan-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-header-too-large-repeating-orphan.png b/tests/ref/grid-header-too-large-repeating-orphan.png
new file mode 100644
index 00000000..76d54c34
--- /dev/null
+++ b/tests/ref/grid-header-too-large-repeating-orphan.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-alone-no-orphan-prevention.png b/tests/ref/grid-subheaders-alone-no-orphan-prevention.png
new file mode 100644
index 00000000..17bf3fe4
--- /dev/null
+++ b/tests/ref/grid-subheaders-alone-no-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-alone-with-footer-no-orphan-prevention.png b/tests/ref/grid-subheaders-alone-with-footer-no-orphan-prevention.png
new file mode 100644
index 00000000..9b083f37
--- /dev/null
+++ b/tests/ref/grid-subheaders-alone-with-footer-no-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-alone-with-footer.png b/tests/ref/grid-subheaders-alone-with-footer.png
new file mode 100644
index 00000000..41bf88bc
--- /dev/null
+++ b/tests/ref/grid-subheaders-alone-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-alone-with-gutter-and-footer-no-orphan-prevention.png b/tests/ref/grid-subheaders-alone-with-gutter-and-footer-no-orphan-prevention.png
new file mode 100644
index 00000000..7d6cc45e
--- /dev/null
+++ b/tests/ref/grid-subheaders-alone-with-gutter-and-footer-no-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.png b/tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.png
new file mode 100644
index 00000000..17bf3fe4
--- /dev/null
+++ b/tests/ref/grid-subheaders-alone-with-gutter-no-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-alone.png b/tests/ref/grid-subheaders-alone.png
new file mode 100644
index 00000000..0e05dda8
--- /dev/null
+++ b/tests/ref/grid-subheaders-alone.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-basic-non-consecutive-with-footer.png b/tests/ref/grid-subheaders-basic-non-consecutive-with-footer.png
new file mode 100644
index 00000000..6f2a57be
--- /dev/null
+++ b/tests/ref/grid-subheaders-basic-non-consecutive-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-basic-non-consecutive.png b/tests/ref/grid-subheaders-basic-non-consecutive.png
new file mode 100644
index 00000000..9f3f8440
--- /dev/null
+++ b/tests/ref/grid-subheaders-basic-non-consecutive.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-basic-replace.png b/tests/ref/grid-subheaders-basic-replace.png
new file mode 100644
index 00000000..2b3baa37
--- /dev/null
+++ b/tests/ref/grid-subheaders-basic-replace.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-basic-with-footer.png b/tests/ref/grid-subheaders-basic-with-footer.png
new file mode 100644
index 00000000..52165614
--- /dev/null
+++ b/tests/ref/grid-subheaders-basic-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-basic.png b/tests/ref/grid-subheaders-basic.png
new file mode 100644
index 00000000..5a646807
--- /dev/null
+++ b/tests/ref/grid-subheaders-basic.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-colorful.png b/tests/ref/grid-subheaders-colorful.png
new file mode 100644
index 00000000..38bb4ad8
--- /dev/null
+++ b/tests/ref/grid-subheaders-colorful.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-demo.png b/tests/ref/grid-subheaders-demo.png
new file mode 100644
index 00000000..ec1cd998
--- /dev/null
+++ b/tests/ref/grid-subheaders-demo.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-row-right-after-with-footer.png b/tests/ref/grid-subheaders-multi-page-row-right-after-with-footer.png
new file mode 100644
index 00000000..119a2c22
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-row-right-after-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-row-right-after.png b/tests/ref/grid-subheaders-multi-page-row-right-after.png
new file mode 100644
index 00000000..c9e30869
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-row-right-after.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-row-with-footer.png b/tests/ref/grid-subheaders-multi-page-row-with-footer.png
new file mode 100644
index 00000000..a440eac4
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-row-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-row.png b/tests/ref/grid-subheaders-multi-page-row.png
new file mode 100644
index 00000000..637ca3fb
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-row.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-rowspan-gutter.png b/tests/ref/grid-subheaders-multi-page-rowspan-gutter.png
new file mode 100644
index 00000000..53beeb02
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-rowspan-gutter.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-rowspan-right-after.png b/tests/ref/grid-subheaders-multi-page-rowspan-right-after.png
new file mode 100644
index 00000000..5fe1eacf
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-rowspan-right-after.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-rowspan-with-footer.png b/tests/ref/grid-subheaders-multi-page-rowspan-with-footer.png
new file mode 100644
index 00000000..b9104667
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-rowspan-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-multi-page-rowspan.png b/tests/ref/grid-subheaders-multi-page-rowspan.png
new file mode 100644
index 00000000..342b0569
--- /dev/null
+++ b/tests/ref/grid-subheaders-multi-page-rowspan.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-non-repeat-replace.png b/tests/ref/grid-subheaders-non-repeat-replace.png
new file mode 100644
index 00000000..e9c254b4
--- /dev/null
+++ b/tests/ref/grid-subheaders-non-repeat-replace.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-non-repeat.png b/tests/ref/grid-subheaders-non-repeat.png
new file mode 100644
index 00000000..030f1baa
--- /dev/null
+++ b/tests/ref/grid-subheaders-non-repeat.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-non-repeating-header-before-multi-page-row.png b/tests/ref/grid-subheaders-non-repeating-header-before-multi-page-row.png
new file mode 100644
index 00000000..3db97f78
--- /dev/null
+++ b/tests/ref/grid-subheaders-non-repeating-header-before-multi-page-row.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-non-repeating-orphan-prevention.png b/tests/ref/grid-subheaders-non-repeating-orphan-prevention.png
new file mode 100644
index 00000000..0f37c5d1
--- /dev/null
+++ b/tests/ref/grid-subheaders-non-repeating-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-non-repeating-replace-didnt-fit-once.png b/tests/ref/grid-subheaders-non-repeating-replace-didnt-fit-once.png
new file mode 100644
index 00000000..6685125a
--- /dev/null
+++ b/tests/ref/grid-subheaders-non-repeating-replace-didnt-fit-once.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-non-repeating-replace-orphan.png b/tests/ref/grid-subheaders-non-repeating-replace-orphan.png
new file mode 100644
index 00000000..ffa465c4
--- /dev/null
+++ b/tests/ref/grid-subheaders-non-repeating-replace-orphan.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-gutter.png b/tests/ref/grid-subheaders-repeat-gutter.png
new file mode 100644
index 00000000..f8f7380e
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-gutter.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-non-consecutive.png b/tests/ref/grid-subheaders-repeat-non-consecutive.png
new file mode 100644
index 00000000..2e0fe236
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-non-consecutive.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-didnt-fit-once.png b/tests/ref/grid-subheaders-repeat-replace-didnt-fit-once.png
new file mode 100644
index 00000000..df984bd6
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-didnt-fit-once.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-double-orphan.png b/tests/ref/grid-subheaders-repeat-replace-double-orphan.png
new file mode 100644
index 00000000..e340e681
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-double-orphan.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-child.png b/tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-child.png
new file mode 100644
index 00000000..80f9b12b
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-child.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-gutter.png b/tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-gutter.png
new file mode 100644
index 00000000..38521e44
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-gutter-orphan-at-gutter.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-gutter.png b/tests/ref/grid-subheaders-repeat-replace-gutter.png
new file mode 100644
index 00000000..e87e3b5b
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-gutter.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-multiple-levels.png b/tests/ref/grid-subheaders-repeat-replace-multiple-levels.png
new file mode 100644
index 00000000..d6f691e4
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-multiple-levels.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-orphan.png b/tests/ref/grid-subheaders-repeat-replace-orphan.png
new file mode 100644
index 00000000..c28e9d4f
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-orphan.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-short-lived.png b/tests/ref/grid-subheaders-repeat-replace-short-lived.png
new file mode 100644
index 00000000..d041888c
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-short-lived.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-with-footer-orphan.png b/tests/ref/grid-subheaders-repeat-replace-with-footer-orphan.png
new file mode 100644
index 00000000..b50fae71
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-with-footer-orphan.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace-with-footer.png b/tests/ref/grid-subheaders-repeat-replace-with-footer.png
new file mode 100644
index 00000000..7191bfb6
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-replace.png b/tests/ref/grid-subheaders-repeat-replace.png
new file mode 100644
index 00000000..9fe72940
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-replace.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-short-lived-also-replaces.png b/tests/ref/grid-subheaders-repeat-short-lived-also-replaces.png
new file mode 100644
index 00000000..788837c7
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-short-lived-also-replaces.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat-with-footer.png b/tests/ref/grid-subheaders-repeat-with-footer.png
new file mode 100644
index 00000000..39f8465e
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat-with-footer.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeat.png b/tests/ref/grid-subheaders-repeat.png
new file mode 100644
index 00000000..c57ed769
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeat.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-repeating-orphan-prevention.png b/tests/ref/grid-subheaders-repeating-orphan-prevention.png
new file mode 100644
index 00000000..0f37c5d1
--- /dev/null
+++ b/tests/ref/grid-subheaders-repeating-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-short-lived-no-orphan-prevention.png b/tests/ref/grid-subheaders-short-lived-no-orphan-prevention.png
new file mode 100644
index 00000000..56067052
--- /dev/null
+++ b/tests/ref/grid-subheaders-short-lived-no-orphan-prevention.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-auto.png b/tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-auto.png
new file mode 100644
index 00000000..c7d632ad
--- /dev/null
+++ b/tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-auto.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-relative.png b/tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-relative.png
new file mode 100644
index 00000000..324787b2
--- /dev/null
+++ b/tests/ref/grid-subheaders-too-large-non-repeating-orphan-before-relative.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-too-large-repeating-orphan-before-auto.png b/tests/ref/grid-subheaders-too-large-repeating-orphan-before-auto.png
new file mode 100644
index 00000000..de77beb2
--- /dev/null
+++ b/tests/ref/grid-subheaders-too-large-repeating-orphan-before-auto.png
Binary files differ
diff --git a/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png b/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png
new file mode 100644
index 00000000..dfcac850
--- /dev/null
+++ b/tests/ref/grid-subheaders-too-large-repeating-orphan-before-relative.png
Binary files differ
diff --git a/tests/ref/html/multi-header-inside-table.html b/tests/ref/html/multi-header-inside-table.html
new file mode 100644
index 00000000..a4a61a69
--- /dev/null
+++ b/tests/ref/html/multi-header-inside-table.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ </head>
+ <body>
+ <table>
+ <thead>
+ <tr>
+ <th>First</th>
+ <th>Header</th>
+ </tr>
+ <tr>
+ <th>Second</th>
+ <th>Header</th>
+ </tr>
+ <tr>
+ <th>Level 2</th>
+ <th>Header</th>
+ </tr>
+ <tr>
+ <th>Level 3</th>
+ <th>Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Body</td>
+ <td>Cells</td>
+ </tr>
+ <tr>
+ <td>Yet</td>
+ <td>More</td>
+ </tr>
+ <tr>
+ <th>Level 2</th>
+ <th>Header Inside</th>
+ </tr>
+ <tr>
+ <th>Level 3</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>Even</td>
+ <td>More</td>
+ </tr>
+ <tr>
+ <td>Body</td>
+ <td>Cells</td>
+ </tr>
+ <tr>
+ <th>One Last Header</th>
+ <th>For Good Measure</th>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>Footer</td>
+ <td>Row</td>
+ </tr>
+ <tr>
+ <td>Ending</td>
+ <td>Table</td>
+ </tr>
+ </tfoot>
+ </table>
+ </body>
+</html>
diff --git a/tests/ref/html/multi-header-table.html b/tests/ref/html/multi-header-table.html
new file mode 100644
index 00000000..8a34ac17
--- /dev/null
+++ b/tests/ref/html/multi-header-table.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ </head>
+ <body>
+ <table>
+ <thead>
+ <tr>
+ <th>First</th>
+ <th>Header</th>
+ </tr>
+ <tr>
+ <th>Second</th>
+ <th>Header</th>
+ </tr>
+ <tr>
+ <th>Level 2</th>
+ <th>Header</th>
+ </tr>
+ <tr>
+ <th>Level 3</th>
+ <th>Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Body</td>
+ <td>Cells</td>
+ </tr>
+ <tr>
+ <td>Yet</td>
+ <td>More</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>Footer</td>
+ <td>Row</td>
+ </tr>
+ <tr>
+ <td>Ending</td>
+ <td>Table</td>
+ </tr>
+ </tfoot>
+ </table>
+ </body>
+</html>
diff --git a/tests/ref/issue-5359-column-override-stays-inside-header.png b/tests/ref/issue-5359-column-override-stays-inside-header.png
new file mode 100644
index 00000000..8339a409
--- /dev/null
+++ b/tests/ref/issue-5359-column-override-stays-inside-header.png
Binary files differ
diff --git a/tests/suite/layout/grid/footers.typ b/tests/suite/layout/grid/footers.typ
index f7f1deb0..c0b03f50 100644
--- a/tests/suite/layout/grid/footers.typ
+++ b/tests/suite/layout/grid/footers.typ
@@ -389,6 +389,29 @@
table.footer[a][b][c]
)
+--- grid-footer-repeatable-unbreakable ---
+#set page(height: 8em, width: auto)
+#table(
+ [h],
+ table.footer(
+ [a],
+ [b],
+ [c],
+ )
+)
+
+--- grid-footer-non-repeatable-unbreakable ---
+#set page(height: 8em, width: auto)
+#table(
+ [h],
+ table.footer(
+ [a],
+ [b],
+ [c],
+ repeat: false,
+ )
+)
+
--- grid-footer-stroke-edge-cases ---
// Test footer stroke priority edge case
#set page(height: 10em)
diff --git a/tests/suite/layout/grid/headers.typ b/tests/suite/layout/grid/headers.typ
index 229bce61..ea222ee8 100644
--- a/tests/suite/layout/grid/headers.typ
+++ b/tests/suite/layout/grid/headers.typ
@@ -118,30 +118,81 @@
)
--- grid-header-not-at-first-row ---
-// Error: 3:3-3:19 header must start at the first row
-// Hint: 3:3-3:19 remove any rows before the header
#grid(
[a],
grid.header([b])
)
--- grid-header-not-at-first-row-two-columns ---
-// Error: 4:3-4:19 header must start at the first row
-// Hint: 4:3-4:19 remove any rows before the header
#grid(
columns: 2,
[a],
grid.header([b])
)
---- grow-header-multiple ---
-// Error: 3:3-3:19 cannot have more than one header
+--- grid-header-multiple ---
#grid(
grid.header([a]),
grid.header([b]),
[a],
)
+--- grid-header-skip ---
+#grid(
+ columns: 2,
+ [x], [y],
+ grid.header([a]),
+ grid.header([b]),
+ grid.cell(x: 1)[c], [d],
+ grid.header([e]),
+ [f], grid.cell(x: 1)[g]
+)
+
+--- grid-header-too-large-non-repeating-orphan ---
+#set page(height: 8em)
+#grid(
+ grid.header(
+ [a\ ] * 5,
+ repeat: false,
+ ),
+ [b]
+)
+
+--- grid-header-too-large-repeating-orphan ---
+#set page(height: 8em)
+#grid(
+ grid.header(
+ [a\ ] * 5,
+ repeat: true,
+ ),
+ [b]
+)
+
+--- grid-header-too-large-repeating-orphan-with-footer ---
+#set page(height: 8em)
+#grid(
+ grid.header(
+ [a\ ] * 5,
+ repeat: true,
+ ),
+ [b],
+ grid.footer(
+ [c],
+ repeat: true,
+ )
+)
+
+--- grid-header-too-large-repeating-orphan-not-at-first-row ---
+#set page(height: 8em)
+#grid(
+ [b],
+ grid.header(
+ [a\ ] * 5,
+ repeat: true,
+ ),
+ [c],
+)
+
--- table-header-in-grid ---
// Error: 2:3-2:20 cannot use `table.header` as a grid header
// Hint: 2:3-2:20 use `grid.header` instead
@@ -228,6 +279,51 @@
table.cell(rowspan: 3, lines(15))
)
+--- grid-header-and-rowspan-contiguous-1 ---
+// Block should occupy all space
+#set page(height: 15em)
+
+#table(
+ rows: (auto, 2.5em, 2em, auto),
+ gutter: 3pt,
+ inset: 0pt,
+ table.header(
+ [*H*],
+ [*W*]
+ ),
+ table.cell(rowspan: 3, block(height: 2.5em + 2em + 20em, width: 100%, fill: red))
+)
+
+--- grid-header-and-rowspan-contiguous-2 ---
+// Block should occupy all space
+#set page(height: 15em)
+
+#table(
+ rows: (auto, 2.5em, 10em, 5em, auto),
+ gutter: 3pt,
+ inset: 0pt,
+ table.header(
+ [*H*],
+ [*W*]
+ ),
+ table.cell(rowspan: 3, block(height: 2.5em + 2em + 20em, width: 100%, fill: red))
+)
+
+--- grid-header-and-large-auto-contiguous ---
+// Block should occupy all space
+#set page(height: 15em)
+
+#table(
+ rows: (auto, 4.5em, auto),
+ gutter: 3pt,
+ inset: 0pt,
+ table.header(
+ [*H*],
+ [*W*]
+ ),
+ block(height: 2.5em + 2em + 20em, width: 100%, fill: red)
+)
+
--- grid-header-lack-of-space ---
// Test lack of space for header + text.
#set page(height: 8em)
@@ -255,6 +351,17 @@
..([Test], [Test], [Test]) * 20
)
+--- grid-header-non-repeating-orphan-prevention ---
+#set page(height: 5em)
+#v(2em)
+#grid(
+ grid.header(repeat: false)[*Abc*],
+ [a],
+ [b],
+ [c],
+ [d]
+)
+
--- grid-header-empty ---
// Empty header should just be a repeated blank row
#set page(height: 12em)
@@ -339,6 +446,56 @@
[a\ b]
)
+--- grid-header-not-at-the-top ---
+#set page(height: 5em)
+#v(2em)
+#grid(
+ [a],
+ [b],
+ grid.header[*Abc*],
+ [d],
+ [e],
+ [f],
+)
+
+--- grid-header-replace ---
+#set page(height: 5em)
+#v(1.5em)
+#grid(
+ grid.header[*Abc*],
+ [a],
+ [b],
+ grid.header[*Def*],
+ [d],
+ [e],
+ [f],
+)
+
+--- grid-header-replace-orphan ---
+#set page(height: 5em)
+#grid(
+ grid.header[*Abc*],
+ [a],
+ [b],
+ grid.header[*Def*],
+ [d],
+ [e],
+ [f],
+)
+
+--- grid-header-replace-doesnt-fit ---
+#set page(height: 5em)
+#v(0.8em)
+#grid(
+ grid.header[*Abc*],
+ [a],
+ [b],
+ grid.header[*Def*],
+ [d],
+ [e],
+ [f],
+)
+
--- grid-header-stroke-edge-cases ---
// Test header stroke priority edge case (last header row removed)
#set page(height: 8em)
@@ -463,8 +620,6 @@
#table(
columns: 3,
[Outside],
- // Error: 1:3-4:4 header must start at the first row
- // Hint: 1:3-4:4 remove any rows before the header
table.header(
[A], table.cell(x: 1)[B], [C],
table.cell(x: 1)[D],
diff --git a/tests/suite/layout/grid/html.typ b/tests/suite/layout/grid/html.typ
index 10345cb0..cf98d4bc 100644
--- a/tests/suite/layout/grid/html.typ
+++ b/tests/suite/layout/grid/html.typ
@@ -57,3 +57,78 @@
[d], [e], [f],
[g], [h], [i]
)
+
+--- multi-header-table html ---
+#table(
+ columns: 2,
+
+ table.header(
+ [First], [Header]
+ ),
+ table.header(
+ [Second], [Header]
+ ),
+ table.header(
+ [Level 2], [Header],
+ level: 2,
+ ),
+ table.header(
+ [Level 3], [Header],
+ level: 3,
+ ),
+
+ [Body], [Cells],
+ [Yet], [More],
+
+ table.footer(
+ [Footer], [Row],
+ [Ending], [Table],
+ ),
+)
+
+--- multi-header-inside-table html ---
+#table(
+ columns: 2,
+
+ table.header(
+ [First], [Header]
+ ),
+ table.header(
+ [Second], [Header]
+ ),
+ table.header(
+ [Level 2], [Header],
+ level: 2,
+ ),
+ table.header(
+ [Level 3], [Header],
+ level: 3,
+ ),
+
+ [Body], [Cells],
+ [Yet], [More],
+
+ table.header(
+ [Level 2], [Header Inside],
+ level: 2,
+ ),
+ table.header(
+ [Level 3],
+ level: 3,
+ ),
+
+ [Even], [More],
+ [Body], [Cells],
+
+ table.header(
+ [One Last Header],
+ [For Good Measure],
+ repeat: false,
+ level: 4,
+ ),
+
+ table.footer(
+ [Footer], [Row],
+ [Ending], [Table],
+ ),
+)
diff --git a/tests/suite/layout/grid/subheaders.typ b/tests/suite/layout/grid/subheaders.typ
new file mode 100644
index 00000000..56bed6a5
--- /dev/null
+++ b/tests/suite/layout/grid/subheaders.typ
@@ -0,0 +1,602 @@
+--- grid-subheaders-demo ---
+#set page(height: 15.2em)
+#table(
+ columns: 2,
+ align: center,
+ table.header(
+ table.cell(colspan: 2)[*Regional User Data*],
+ ),
+ table.header(
+ level: 2,
+ table.cell(colspan: 2)[*Germany*],
+ [*Username*], [*Joined*]
+ ),
+ [john123], [2024],
+ [rob8], [2025],
+ [joe1], [2025],
+ [joe2], [2025],
+ [martha], [2025],
+ [pear], [2025],
+ table.header(
+ level: 2,
+ table.cell(colspan: 2)[*United States*],
+ [*Username*], [*Joined*]
+ ),
+ [cool4], [2023],
+ [roger], [2023],
+ [bigfan55], [2022]
+)
+
+--- grid-subheaders-colorful ---
+#set page(width: auto, height: 12em)
+#let rows(n) = {
+ range(n).map(i => ([John \##i], table.cell(stroke: green)[123], table.cell(stroke: blue)[456], [789], [?], table.hline(start: 4, end: 5, stroke: red))).flatten()
+}
+#table(
+ columns: 5,
+ align: center + horizon,
+ table.header(
+ table.cell(colspan: 5)[*Cool Zone*],
+ ),
+ table.header(
+ level: 2,
+ table.cell(stroke: red)[*Name*], table.cell(stroke: aqua)[*Number*], [*Data 1*], [*Data 2*], [*Etc*],
+ table.hline(start: 2, end: 3, stroke: yellow)
+ ),
+ ..rows(2),
+ table.header(
+ level: 2,
+ table.cell(stroke: red)[*New Name*], table.cell(stroke: aqua, colspan: 4)[*Other Data*],
+ table.hline(start: 2, end: 3, stroke: yellow)
+ ),
+ ..rows(3)
+)
+
+--- grid-subheaders-basic ---
+#grid(
+ grid.header([a]),
+ grid.header(level: 2, [b]),
+ [c]
+)
+
+--- grid-subheaders-basic-non-consecutive ---
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+)
+
+--- grid-subheaders-basic-replace ---
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.header(level: 2, [c]),
+ [z],
+)
+
+--- grid-subheaders-basic-with-footer ---
+#grid(
+ grid.header([a]),
+ grid.header(level: 2, [b]),
+ [c],
+ grid.footer([d])
+)
+
+--- grid-subheaders-basic-non-consecutive-with-footer ---
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.footer([f])
+)
+
+--- grid-subheaders-repeat ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ grid.header(level: 2, [b]),
+ ..([c],) * 10,
+)
+
+--- grid-subheaders-repeat-non-consecutive ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 10,
+)
+
+--- grid-subheaders-repeat-with-footer ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [m],
+ grid.header(level: 2, [b]),
+ ..([c],) * 10,
+ grid.footer([f])
+)
+
+--- grid-subheaders-repeat-gutter ---
+// Gutter below the header is also repeated
+#set page(height: 8em)
+#grid(
+ inset: (bottom: 0.5pt),
+ stroke: (bottom: 1pt),
+ gutter: (1pt, 6pt, 1pt),
+ grid.header([a]),
+ grid.header(level: 2, [b]),
+ ..([c],) * 10,
+)
+
+--- grid-subheaders-repeat-replace ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 10,
+ grid.header(level: 2, [c]),
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-repeat-replace-multiple-levels ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ grid.header(level: 3, [c]),
+ ..([y],) * 10,
+ grid.header(level: 2, [d]),
+ ..([z],) * 6,
+)
+
+--- grid-subheaders-repeat-replace-gutter ---
+#set page(height: 8em)
+#grid(
+ gutter: 3pt,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 8,
+ grid.header(level: 2, [c]),
+ ..([z],) * 4,
+)
+
+--- grid-subheaders-repeat-replace-orphan ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 12,
+ grid.header(level: 2, [c]),
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-repeat-replace-double-orphan ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 11,
+ grid.header(level: 2, [c]),
+ grid.header(level: 3, [d]),
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-repeat-replace-gutter-orphan-at-child ---
+#set page(height: 8em)
+#grid(
+ gutter: 3pt,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 9,
+ grid.header(level: 2, [c]),
+ [z \ z],
+ ..([z],) * 3,
+)
+
+--- grid-subheaders-repeat-replace-gutter-orphan-at-gutter ---
+#set page(height: 8em)
+#grid(
+ gutter: 3pt,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 9,
+ box(height: 3pt),
+ grid.header(level: 2, [c]),
+ ..([z],) * 4,
+)
+
+--- grid-subheaders-repeat-replace-didnt-fit-once ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 10,
+ grid.header(level: 2, [c\ c\ c]),
+ ..([z],) * 4,
+)
+
+--- grid-subheaders-repeat-replace-with-footer ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ grid.header(level: 3, [c]),
+ ..([y],) * 10,
+ grid.header(level: 2, [d]),
+ ..([z],) * 6,
+ grid.footer([f])
+)
+
+--- grid-subheaders-repeat-replace-with-footer-orphan ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 10,
+ grid.header(level: 2, [c]),
+ ..([z],) * 10,
+ grid.footer([f])
+)
+
+--- grid-subheaders-repeat-replace-short-lived ---
+// No orphan prevention for short-lived headers
+// (followed by replacing headers).
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ grid.header(level: 2, [b]),
+ grid.header(level: 2, [c]),
+ grid.header(level: 2, [d]),
+ grid.header(level: 2, [e]),
+ grid.header(level: 2, [f]),
+ grid.header(level: 2, [g]),
+ grid.header(level: 2, [h]),
+ grid.header(level: 2, [i]),
+ grid.header(level: 2, [j]),
+ grid.header(level: 3, [k]),
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-repeat-short-lived-also-replaces ---
+// Short-lived subheaders must still replace their conflicting predecessors.
+#set page(height: 8em)
+#grid(
+ // This has to go
+ grid.header(level: 3, [a]),
+ [w],
+ grid.header(level: 2, [b]),
+ grid.header(level: 2, [c]),
+ grid.header(level: 2, [d]),
+ grid.header(level: 2, [e]),
+ grid.header(level: 2, [f]),
+ grid.header(level: 2, [g]),
+ grid.header(level: 2, [h]),
+ grid.header(level: 2, [i]),
+ grid.header(level: 2, [j]),
+ grid.header(level: 3, [k]),
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-multi-page-row ---
+#set page(height: 8em)
+#grid(
+ columns: 2,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.header(level: 3, [c]),
+ [a], [b],
+ grid.cell(
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [y],
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-non-repeat ---
+#set page(height: 8em)
+#grid(
+ grid.header(repeat: false, [a]),
+ [x],
+ grid.header(level: 2, repeat: false, [b]),
+ ..([y],) * 10,
+)
+
+--- grid-subheaders-non-repeat-replace ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ grid.header(level: 3, [c]),
+ ..([y],) * 9,
+ grid.header(level: 2, repeat: false, [d]),
+ ..([z],) * 6,
+)
+
+--- grid-subheaders-non-repeating-replace-orphan ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 12,
+ grid.header(level: 2, repeat: false, [c]),
+ ..([z],) * 10,
+)
+
+--- grid-subheaders-non-repeating-replace-didnt-fit-once ---
+#set page(height: 8em)
+#grid(
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ ..([y],) * 10,
+ grid.header(level: 2, repeat: false, [c\ c\ c]),
+ ..([z],) * 4,
+)
+
+--- grid-subheaders-multi-page-rowspan ---
+#set page(height: 8em)
+#grid(
+ columns: 2,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.header(level: 3, [c]),
+ [z], [z],
+ grid.cell(
+ rowspan: 5,
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [cell],
+ [cell]
+)
+
+--- grid-subheaders-multi-page-row-right-after ---
+#set page(height: 8em)
+#grid(
+ columns: 1,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ grid.header(level: 3, [c]),
+ grid.cell(
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [done.],
+ [done.]
+)
+
+--- grid-subheaders-multi-page-rowspan-right-after ---
+#set page(height: 8em)
+#grid(
+ columns: 2,
+ grid.header([a]),
+ [x], [y],
+ grid.header(level: 2, [b]),
+ grid.header(level: 3, [c]),
+ grid.cell(
+ rowspan: 5,
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [cell],
+ [cell],
+ grid.cell(x: 0)[done.],
+ grid.cell(x: 0)[done.]
+)
+
+--- grid-subheaders-multi-page-row-with-footer ---
+#set page(height: 8em)
+#grid(
+ columns: 2,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.header(level: 3, [c]),
+ [a], [b],
+ grid.cell(
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [y],
+ ..([z],) * 10,
+ grid.footer([f])
+)
+
+--- grid-subheaders-multi-page-rowspan-with-footer ---
+#set page(height: 8em)
+#grid(
+ columns: 2,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.header(level: 3, [c]),
+ [z], [z],
+ grid.cell(
+ rowspan: 5,
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [cell],
+ [cell],
+ grid.footer([f])
+)
+
+--- grid-subheaders-multi-page-row-right-after-with-footer ---
+#set page(height: 8em)
+#grid(
+ columns: 1,
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ grid.header(level: 3, [c]),
+ grid.cell(
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [done.],
+ [done.],
+ grid.footer([f])
+)
+
+--- grid-subheaders-multi-page-rowspan-gutter ---
+#set page(height: 9em)
+#grid(
+ columns: 2,
+ column-gutter: 4pt,
+ row-gutter: (0pt, 4pt, 8pt, 4pt),
+ inset: (bottom: 0.5pt),
+ stroke: (bottom: 1pt),
+ grid.header([a]),
+ [x],
+ grid.header(level: 2, [b]),
+ [y],
+ grid.header(level: 3, [c]),
+ [z], [z],
+ grid.cell(
+ rowspan: 5,
+ block(fill: red, width: 1.5em, height: 6.4em)
+ ),
+ [cell],
+ [cell],
+ [a\ b],
+ grid.cell(x: 0)[end],
+)
+
+--- grid-subheaders-non-repeating-header-before-multi-page-row ---
+#set page(height: 6em)
+#grid(
+ grid.header(repeat: false, [h]),
+ [row #colbreak() row]
+)
+
+
+--- grid-subheaders-short-lived-no-orphan-prevention ---
+// No orphan prevention for short-lived headers.
+#set page(height: 8em)
+#v(5em)
+#grid(
+ grid.header(level: 2, [b]),
+ grid.header(level: 2, [c]),
+ [d]
+)
+
+--- grid-subheaders-repeating-orphan-prevention ---
+#set page(height: 8em)
+#v(4.5em)
+#grid(
+ grid.header(repeat: true, level: 2, [L2]),
+ grid.header(repeat: true, level: 4, [L4]),
+ [a]
+)
+
+--- grid-subheaders-non-repeating-orphan-prevention ---
+#set page(height: 8em)
+#v(4.5em)
+#grid(
+ grid.header(repeat: false, level: 2, [L2]),
+ grid.header(repeat: false, level: 4, [L4]),
+ [a]
+)
+
+--- grid-subheaders-alone ---
+#table(
+ table.header([a]),
+ table.header(level: 2, [b]),
+)
+
+--- grid-subheaders-alone-no-orphan-prevention ---
+#set page(height: 5.3em)
+#v(2em)
+#grid(
+ grid.header([L1]),
+ grid.header(level: 2, [L2]),
+)
+
+--- grid-subheaders-alone-with-gutter-no-orphan-prevention ---
+#set page(height: 5.3em)
+#v(2em)
+#grid(
+ gutter: 3pt,
+ grid.header([L1]),
+ grid.header(level: 2, [L2]),
+)
+
+--- grid-subheaders-alone-with-footer ---
+#table(
+ table.header([a]),
+ table.header(level: 2, [b]),
+ table.footer([c])
+)
+
+--- grid-subheaders-alone-with-footer-no-orphan-prevention ---
+#set page(height: 5.3em)
+#table(
+ table.header([L1]),
+ table.header(level: 2, [L2]),
+ table.footer([a])
+)
+
+--- grid-subheaders-alone-with-gutter-and-footer-no-orphan-prevention ---
+#set page(height: 5.5em)
+#table(
+ gutter: 4pt,
+ table.header([L1]),
+ table.header(level: 2, [L2]),
+ table.footer([a])
+)
+
+--- grid-subheaders-too-large-non-repeating-orphan-before-auto ---
+#set page(height: 8em)
+#grid(
+ grid.header([1]),
+ grid.header([a\ ] * 2, level: 2, repeat: false),
+ grid.header([2], level: 3),
+ [b\ b\ b],
+)
+
+--- grid-subheaders-too-large-repeating-orphan-before-auto ---
+#set page(height: 8em)
+#grid(
+ grid.header([1]),
+ grid.header([a\ ] * 2, level: 2, repeat: true),
+ grid.header([2], level: 3),
+ rect(width: 10pt, height: 3em, fill: red),
+)
+
+--- grid-subheaders-too-large-repeating-orphan-before-relative ---
+#set page(height: 8em)
+#grid(
+ rows: (auto, auto, auto, 3em),
+ grid.header([1]),
+ grid.header([a\ ] * 2, level: 2, repeat: true),
+ grid.header([2], level: 3),
+ rect(width: 10pt, height: 3em, fill: red),
+)
+
+--- grid-subheaders-too-large-non-repeating-orphan-before-relative ---
+#set page(height: 8em)
+#grid(
+ rows: (auto, auto, auto, 3em),
+ grid.header([1]),
+ grid.header([a\ ] * 2, level: 2, repeat: false),
+ grid.header([2], level: 3),
+ rect(width: 10pt, height: 3em, fill: red),
+)