Skip to content

Commit

Permalink
Improve panelset code chunk behavior in Quarto (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
gadenbuie authored May 18, 2024
1 parent 4f3f922 commit d38a04d
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 112 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
^cran-comments\.md$
^CRAN-SUBMISSION$
^_extensions$
^\.luarc\.json$
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Suggests:
Config/testthat/edition: 3
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
RoxygenNote: 7.3.1
Collate:
'animate.R'
'banner.R'
Expand Down
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
```
````

Unlike in R Markdown, where you always need to place panelset chunks in a
`::: {.panelset}` div, in Quarto, panelset code chunks automatically create
their own panelsets with two tabs (code and output). Use the
`::: {.panelset}` syntax to add more than one panelset code chunk to the same
panelset (#196).

* Nested **panelsets** are now supported (#194)! In xaringan slides and when
using the hand-rolled panelset syntax, you can now nest panelsets within
panelsets. In R Markdown or Quarto documents, panelsets chunks can be nested
Expand Down
5 changes: 5 additions & 0 deletions docs/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
```
````

Unlike in R Markdown, where you always need to place panelset chunks in a
`::: {.panelset}` div, in Quarto panelset code chunks automatically create
their own panelsets. You can still use the `::: {.panelset}` syntax to add
additional panels to the same panelset ([#196](https://github.com/gadenbuie/xaringanExtra/issues/196)).

* Nested **panelsets** are now supported ([#194](https://github.com/gadenbuie/xaringanExtra/issues/194))! In xaringan slides and when
using the hand-rolled panelset syntax, you can now nest panelsets within
panelsets. In R Markdown or Quarto documents, panelsets chunks can be nested
Expand Down
13 changes: 11 additions & 2 deletions docs/panelset/libs/panelset/panelset.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@
* @returns {HTMLElement} - The new panelset element.
*/
const initPanelSet = panelset => {
let panels = Array.from(panelset.querySelectorAll(':scope > .panel'))
let panels = Array.from(panelset.querySelectorAll(':scope > .panel, :scope > .cell > .panel'))

const pandocSectionSelector = ':is(section, .section)[class*="level"]'
if (!panels.length) {
Expand Down Expand Up @@ -693,7 +693,16 @@
// initialize panels
document
.querySelectorAll('[data-panelset="true"]')
.forEach(el => el.classList.add('panelset'))
.forEach(el => {
const isCell = el.classList.contains('cell')
const hasParentPanelset = el.parentElement.classList.contains('panelset')
if (!isCell || !hasParentPanelset) {
// We let `data-panelset="true"` create a new panelset, unless it's on
// a code cell that's already inside a panelset, in which case the
// panels will be folded into the parent panelset.
el.classList.add('panelset')
}
})

const panelsets = { atomic: [], nested: [] }
Array.from(document.querySelectorAll('.panelset')).forEach(el => {
Expand Down
13 changes: 11 additions & 2 deletions docs/panelset/rmarkdown.html
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,7 @@
* @returns {HTMLElement} - The new panelset element.
*/
const initPanelSet = panelset => {
let panels = Array.from(panelset.querySelectorAll(':scope > .panel'))
let panels = Array.from(panelset.querySelectorAll(':scope > .panel, :scope > .cell > .panel'))

const pandocSectionSelector = ':is(section, .section)[class*="level"]'
if (!panels.length) {
Expand Down Expand Up @@ -1158,7 +1158,16 @@
// initialize panels
document
.querySelectorAll('[data-panelset="true"]')
.forEach(el => el.classList.add('panelset'))
.forEach(el => {
const isCell = el.classList.contains('cell')
const hasParentPanelset = el.parentElement.classList.contains('panelset')
if (!isCell || !hasParentPanelset) {
// We let `data-panelset="true"` create a new panelset, unless it's on
// a code cell that's already inside a panelset, in which case the
// panels will be folded into the parent panelset.
el.classList.add('panelset')
}
})

const panelsets = { atomic: [], nested: [] }
Array.from(document.querySelectorAll('.panelset')).forEach(el => {
Expand Down
13 changes: 6 additions & 7 deletions docs/tile-view/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -547,13 +547,12 @@


```
*## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
*## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
*## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
*## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## [ reached 'max' / getOption("max.print") -- omitted 2 rows ]
```

Question: what does `highlight.output = c(TRUE, FALSE)` mean? (Hint: think about R's recycling of vectors)
Expand Down
13 changes: 11 additions & 2 deletions inst/panelset/panelset.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@
* @returns {HTMLElement} - The new panelset element.
*/
const initPanelSet = panelset => {
let panels = Array.from(panelset.querySelectorAll(':scope > .panel'))
let panels = Array.from(panelset.querySelectorAll(':scope > .panel, :scope > .cell > .panel'))

const pandocSectionSelector = ':is(section, .section)[class*="level"]'
if (!panels.length) {
Expand Down Expand Up @@ -693,7 +693,16 @@
// initialize panels
document
.querySelectorAll('[data-panelset="true"]')
.forEach(el => el.classList.add('panelset'))
.forEach(el => {
const isCell = el.classList.contains('cell')
const hasParentPanelset = el.parentElement.classList.contains('panelset')
if (!isCell || !hasParentPanelset) {
// We let `data-panelset="true"` create a new panelset, unless it's on
// a code cell that's already inside a panelset, in which case the
// panels will be folded into the parent panelset.
el.classList.add('panelset')
}
})

const panelsets = { atomic: [], nested: [] }
Array.from(document.querySelectorAll('.panelset')).forEach(el => {
Expand Down
2 changes: 2 additions & 0 deletions make.R
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#! /usr/bin/env Rscript

devtools::document()
devtools::install(dependencies = FALSE)

Expand Down
69 changes: 69 additions & 0 deletions tests/testthat/_snaps/panelset.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,72 @@
Output
--panel-tab-foreground:var(--text-mild);--panel-tab-background:unset;--panel-tab-active-foreground:var(--text-dark);--panel-tab-active-background:var(--text-lightest);--panel-tab-active-border-color:var(--purple);--panel-tab-hover-background:#fafafa;--panel-tab-hover-border-color:var(--text-lightest);--panel-tabs-separator-color:var(--text-mild);--panel-tab-inactive-opacity:1;

# panelset knitr chunks with plots

Code
cat(render_slide_text(paste("```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)", "```", "",
"```{r plot, panelset = TRUE}", "hist(precip)", "```", sep = "\n")))
Output
.panel[.panel-name[Code]
``` r
hist(precip)
```
]
.panel[.panel-name[Output]
![](slides_files/figure-html/plot-1.png)<!-- -->
]

# panelset knitr chunks with custom tab names

Code
cat(render_slide_text(paste("```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)", "```", "",
"```{r plot, panelset = c(source = 'Hist', output = 'Plot')}", "hist(precip)",
"```", sep = "\n")))
Output
.panel[.panel-name[Hist]
``` r
hist(precip)
```
]
.panel[.panel-name[Plot]
![](slides_files/figure-html/plot-1.png)<!-- -->
]

# panelset knitr chunks with mutiple outputs

Code
cat(render_slide_text(paste("```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)", "```", "",
"```{r panelset = TRUE}", "print(\"Oak is strong and also gives shade.\")",
"print(\"The lake sparkled in the red hot sun.\")", "```", sep = "\n")))
Output
.panel[.panel-name[Code]
``` r
print("Oak is strong and also gives shade.")
print("The lake sparkled in the red hot sun.")
```
]
.panel[.panel-name[Output]
```
## [1] "Oak is strong and also gives shade."
## [1] "The lake sparkled in the red hot sun."
```
]

141 changes: 43 additions & 98 deletions tests/testthat/test-panelset.R
Original file line number Diff line number Diff line change
Expand Up @@ -110,114 +110,59 @@ extract_slides_text <- function(path) {
}

test_that("panelset knitr chunks with plots", {
rmd <- paste(
"```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)",
"```",
"",
"```{r plot, panelset = TRUE}",
"hist(precip)",
"```",
sep = "\n"
)
out <- render_slide_text(rmd)

expect_equal(
out,
paste(
c(
".panel[.panel-name[Code]",
"",
"```r",
"hist(precip)",
"```",
"",
"]",
"",
".panel[.panel-name[Output]",
"",
"![](slides_files/figure-html/plot-1.png)&lt;!-- --&gt;",
"",
"]"
),
collapse = "\n"
expect_snapshot(
cat(
render_slide_text(
paste(
"```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)",
"```",
"",
"```{r plot, panelset = TRUE}",
"hist(precip)",
"```",
sep = "\n"
)
)
)
)
})

test_that("panelset knitr chunks with custom tab names", {
rmd <- paste(
"```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)",
"```",
"",
"```{r plot, panelset = c(source = 'Hist', output = 'Plot')}",
"hist(precip)",
"```",
sep = "\n"
)
out <- render_slide_text(rmd)

expect_equal(
out,
paste(
c(
".panel[.panel-name[Hist]",
"",
"```r",
"hist(precip)",
"```",
"",
"]",
"",
".panel[.panel-name[Plot]",
"",
"![](slides_files/figure-html/plot-1.png)&lt;!-- --&gt;",
"",
"]"
),
collapse = "\n"
expect_snapshot(
cat(
render_slide_text(
paste(
"```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)",
"```",
"",
"```{r plot, panelset = c(source = 'Hist', output = 'Plot')}",
"hist(precip)",
"```",
sep = "\n"
)
)
)
)
})

test_that("panelset knitr chunks with mutiple outputs", {
rmd <- paste(
"```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)",
"```",
"",
"```{r panelset = TRUE}",
'print("Oak is strong and also gives shade.")',
'print("The lake sparkled in the red hot sun.")',
"```",
sep = "\n"
)
out <- render_slide_text(rmd)

expect_equal(
out,
paste(
c(
".panel[.panel-name[Code]",
"",
"```r",
"print(\"Oak is strong and also gives shade.\")",
"print(\"The lake sparkled in the red hot sun.\")",
"```",
"",
"]",
"",
".panel[.panel-name[Output]",
"",
"```",
"## [1] \"Oak is strong and also gives shade.\"",
"## [1] \"The lake sparkled in the red hot sun.\"",
"```",
"",
"]"
),
collapse = "\n"
expect_snapshot(
cat(
render_slide_text(
paste(
"```{r echo=FALSE}",
"xaringanExtra::use_panelset(in_xaringan = TRUE)",
"```",
"",
"```{r panelset = TRUE}",
'print("Oak is strong and also gives shade.")',
'print("The lake sparkled in the red hot sun.")',
"```",
sep = "\n"
)
)
)
)
})

0 comments on commit d38a04d

Please sign in to comment.