diff --git a/news/changelog-1.9.md b/news/changelog-1.9.md index 3061fc3e0c..222b84e60a 100644 --- a/news/changelog-1.9.md +++ b/news/changelog-1.9.md @@ -163,4 +163,5 @@ All changes included in 1.9: - ([#13890](https://github.com/quarto-dev/quarto-cli/issues/13890)): Fix render failure when using `embed-resources: true` with input path through a symlinked directory. The cleanup now resolves symlinks before comparing paths. - ([#13907](https://github.com/quarto-dev/quarto-cli/issues/13907)): Ignore AI assistant configuration files (`CLAUDE.md`, `AGENTS.md`) when scanning for project input files and in extension templates, similar to how `README.md` is handled. - ([#13935](https://github.com/quarto-dev/quarto-cli/issues/13935)): Fix `quarto install`, `quarto update`, and `quarto uninstall` interactive tool selection. +- ([#13992](https://github.com/quarto-dev/quarto-cli/issues/13992)): Fix crash when rendering div with both cross-reference ID and conditional visibility to PDF. - ([#13998](https://github.com/quarto-dev/quarto-cli/issues/13998)): Fix YAML validation error with CR-only line terminators (old Mac format). Documents using `\r` line endings no longer fail with "Expected YAML front matter to contain at least 2 lines". diff --git a/src/resources/filters/customnodes/content-hidden.lua b/src/resources/filters/customnodes/content-hidden.lua index 341e938a66..fe38b12b53 100644 --- a/src/resources/filters/customnodes/content-hidden.lua +++ b/src/resources/filters/customnodes/content-hidden.lua @@ -59,8 +59,18 @@ _quarto.ast.add_handler({ local visible = is_visible(node) if visible then local el = node.node - clearHiddenVisibleAttributes(el) - return el.content + -- Handle case where slot content was transformed (e.g., Div → FloatRefTarget → Table) + if is_regular_node(el, "Div") then + -- Defensive: parse() already stripped visibility attrs (lines 46-47), so this is + -- typically a no-op. Kept as safety net in case future code adds attrs between + -- parse and render. See issue #13992 investigation for AST trace evidence. + clearHiddenVisibleAttributes(el) + return el.content + else + -- Slot was transformed to another type (Table, etc.) + -- Return the rendered element wrapped in Blocks + return pandoc.Blocks({el}) + end else return {} end diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-figure.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-figure.qmd new file mode 100644 index 0000000000..cb3cc27cf3 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-figure.qmd @@ -0,0 +1,31 @@ +--- +title: "Conditional visibility with figure (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Figure content visible', 'fig-cond', '\\begin{figure}', 'Figure~\\ref\{fig-cond\}'] + - [] + html: + ensureHtmlElements: + - [] + - ['#fig-cond'] + ensureFileRegexMatches: + - [] + - ['Figure content visible'] + typst: + ensureTypstFileRegexMatches: + - ['#figure', 'Figure content visible', '#ref\('] + - [] + native: default +--- + +See @fig-cond for conditional figure. + +::: {#fig-cond .content-visible unless-format="html"} +![]({{< placeholder 300 >}}) + +Figure content visible +::: diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-listing.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-listing.qmd new file mode 100644 index 0000000000..0457a3b5e3 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-listing.qmd @@ -0,0 +1,32 @@ +--- +title: "Conditional visibility with listing (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Listing content visible', 'lst-cond', '\\begin{codelisting}', 'Listing~\\ref\{lst-cond\}'] + - [] + html: + ensureHtmlElements: + - [] + - ['#lst-cond'] + ensureFileRegexMatches: + - [] + - ['Listing content visible'] + typst: + ensureTypstFileRegexMatches: + - ['Listing content visible', '#ref\('] + - [] + native: default +--- + +See @lst-cond for conditional listing. + +::: {#lst-cond .content-visible unless-format="html"} +```python +# Listing content visible +print("hello") +``` +::: diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-nested-callout.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-nested-callout.qmd new file mode 100644 index 0000000000..3fb4f72291 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-nested-callout.qmd @@ -0,0 +1,30 @@ +--- +title: "Conditional visibility with nested callout (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Nested callout visible', 'tcolorbox', 'quarto-callout-note'] + - [] + html: + ensureHtmlElements: + - [] + - ['div.callout'] + ensureFileRegexMatches: + - [] + - ['Nested callout visible'] + typst: + ensureTypstFileRegexMatches: + - ['Nested callout visible', '#callout'] + - [] +--- + +This tests a callout nested inside a conditional visibility div. + +::: {.content-visible unless-format="html"} +::: {.callout-note} +Nested callout visible. +::: +::: diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-nested-tabset.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-nested-tabset.qmd new file mode 100644 index 0000000000..15084cb484 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-nested-tabset.qmd @@ -0,0 +1,31 @@ +--- +title: "Conditional visibility with nested tabset (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - [] + - ['Nested tabset visible', 'Tab A'] + html: + ensureHtmlElements: + - ['div.panel-tabset'] + - [] + ensureFileRegexMatches: + - ['Nested tabset visible', 'Tab A'] + - [] + typst: + ensureTypstFileRegexMatches: + - [] + - ['Nested tabset visible', 'Tab A'] +--- + +This tests a tabset nested inside a conditional visibility div. + +::: {.content-visible when-format="html"} +::: {.panel-tabset} +### Tab A +Nested tabset visible. +::: +::: diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-plain.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-plain.qmd new file mode 100644 index 0000000000..55f721644a --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-plain.qmd @@ -0,0 +1,25 @@ +--- +title: "Conditional visibility with plain div (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Plain div content visible'] + - [] + html: + ensureFileRegexMatches: + - [] + - ['Plain div content visible'] + typst: + ensureTypstFileRegexMatches: + - ['Plain div content visible'] + - [] +--- + +This tests the baseline case of a plain div with `.content-visible`. + +::: {.content-visible unless-format="html"} +Plain div content visible. +::: diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-proof.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-proof.qmd new file mode 100644 index 0000000000..6c1b98a8a7 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-proof.qmd @@ -0,0 +1,25 @@ +--- +title: "Conditional visibility with proof (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Proof content visible', '\\begin{proof}', '\\end{proof}'] + - [] + html: + ensureFileRegexMatches: + - [] + - ['Proof content visible'] + typst: + ensureTypstFileRegexMatches: + - ['#emph\[Proof\]\. Proof content visible'] + - [] +--- + +This tests a proof div with `.proof` class and `.content-visible`. + +::: {.proof .content-visible unless-format="html"} +Proof content visible. +::: diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-table.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-table.qmd new file mode 100644 index 0000000000..29bec204e4 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-table.qmd @@ -0,0 +1,39 @@ +--- +title: "Crossref table with conditional visibility (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Type 1', 'Type 2', 'Item 1', 'Item 2', 'tbl-mytypes'] + - [] + html: + ensureHtmlElements: + - [] + - ['#tbl-mytypes', 'table'] + ensureFileRegexMatches: + - [] + - ['Type 1', 'Type 2', 'Item 1', 'Item 2'] + typst: + ensureTypstFileRegexMatches: + - ['#ref\(', 'Type 1', 'Type 2', 'Item 1', 'Item 2'] + - [] + native: default +--- + +This tests that a table div with both a cross-reference ID and conditional visibility renders correctly. + +See @tbl-mytypes for the table. + +::: {#tbl-mytypes .content-visible unless-format="html"} + +| Type 1 | Type 2 | +| ------ | ------ | +| Item 1 | Item 2 | + +: Test table caption + +::: + +The table above should appear in PDF and Typst but not HTML. diff --git a/tests/docs/smoke-all/2026/02/04/issue-13992-theorem.qmd b/tests/docs/smoke-all/2026/02/04/issue-13992-theorem.qmd new file mode 100644 index 0000000000..59989bd7b2 --- /dev/null +++ b/tests/docs/smoke-all/2026/02/04/issue-13992-theorem.qmd @@ -0,0 +1,30 @@ +--- +title: "Conditional visibility with theorem (#13992)" +keep-tex: true +keep-typ: true +_quarto: + tests: + pdf: + ensureLatexFileRegexMatches: + - ['Theorem content visible', 'thm-cond', '\\begin\{theorem\}'] + - [] + html: + ensureHtmlElements: + - [] + - ['#thm-cond'] + ensureFileRegexMatches: + - [] + - ['Theorem content visible'] + typst: + ensureTypstFileRegexMatches: + - ['Theorem content visible', '#ref\(', '#theorem'] + - [] +--- + +See @thm-cond for conditional theorem. + +::: {#thm-cond .content-visible unless-format="html"} +## Test Theorem + +Theorem content visible. +:::