Skip to content

Commit 241b03d

Browse files
authored
Merge pull request #63 from Appsilon/improve-panel-stack
PanelStack API improved
2 parents bf2b5e3 + ed4ad1a commit 241b03d

File tree

11 files changed

+267
-94
lines changed

11 files changed

+267
-94
lines changed

NAMESPACE

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export(NumericInput.shinyInput)
5757
export(OL)
5858
export(OverflowList)
5959
export(Overlay)
60-
export(PanelStack2)
60+
export(PanelStack)
61+
export(PanelStack.shinyWrapper)
6162
export(Popover)
6263
export(Pre)
6364
export(ProgressBar)
@@ -90,6 +91,8 @@ export(Toaster)
9091
export(Tree)
9192
export(Tree.shinyInput)
9293
export(UL)
94+
export(closePanel)
95+
export(openPanel)
9396
export(reactOutput)
9497
export(renderReact)
9598
export(runExample)

R/components.R

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ select <- function(name) {
8585
checkmate::assert_string(noResults)
8686
items <- unique(items)
8787
items <- purrr::map(items, function(item) {
88-
if (is.null(item$key)) {
89-
item$key <- paste0(item$text, "-", item$label)
90-
}
91-
item
88+
if (is.null(item$key)) {
89+
item$key <- paste0(item$text, "-", item$label)
90+
}
91+
item
9292
})
9393
shiny.react::reactElement(
9494
module = "@/shiny.blueprint",
@@ -368,14 +368,28 @@ NonIdealState <- component("NonIdealState")
368368
#' @export
369369
OverflowList <- component("OverflowList")
370370

371-
#' Panel stack (v2)
371+
#' Panel stack
372372
#'
373373
#' Documentation: <https://blueprintjs.com/docs/#core/components/panel-stack2>
374374
#'
375-
#' @example inst/examples/PanelStack2.R
375+
#' @example inst/examples/PanelStack.R
376376
#' @inherit template params
377377
#' @export
378-
PanelStack2 <- component("PanelStack2")
378+
PanelStack <- component("PanelStack2")
379+
380+
#' @rdname PanelStack
381+
#' @param panels List of lists - each list contains `title` (string) and `content` (HTML)
382+
#' @param ns Namespace of given panel stack (required if there's more than 1 panel stack)
383+
#' @param size Numeric vector of length 2 - `c(width, height)`
384+
#' @export
385+
PanelStack.shinyWrapper <- function(panels, ns = "ps", size = c(300, 250), ...) { # nolint
386+
shiny.react::reactElement(
387+
module = "@/shiny.blueprint",
388+
name = "PanelStack",
389+
props = shiny.react::asProps(panels = panels, ns = ns, size = size, ...),
390+
deps = blueprintDependency()
391+
)
392+
}
379393

380394
#' Progress bar
381395
#'

R/handlers.R

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
handlersObject <- function(ns) {
2+
paste0("window.jsmodule['@/shiny.blueprint'].panelStackHandlers['", ns, "']")
3+
}
4+
5+
#' @rdname PanelStack
6+
#' @param panelId Id of the panel to be closed
7+
#' @export
8+
openPanel <- function(panelId, ns = "ps") {
9+
JS(paste0(
10+
"() => ", handlersObject(ns), ".openPanel('", panelId, "')"
11+
))
12+
}
13+
14+
#' @rdname PanelStack
15+
#' @export
16+
closePanel <- function(ns = "ps") {
17+
JS("() => ", handlersObject(ns), ".closePanel()")
18+
}

inst/examples/PanelStack2.R renamed to inst/examples/PanelStack.R

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,32 @@ customComponents <- tagList(
4646
ui <- function(id) {
4747
tagList(
4848
customComponents,
49-
PanelStack2(
49+
PanelStack(
5050
className = "panel-stack",
5151
initialPanel = JS("createPanel(1)")
52+
),
53+
PanelStack.shinyWrapper(
54+
panels = list(
55+
list(id = "panel1", title = "Panel 1", content = div(
56+
class = "panel",
57+
Button(text = "Open 2", onClick = openPanel("panel2")),
58+
Button(text = "Open 4", onClick = openPanel("panel4"))
59+
)),
60+
list(id = "panel2", title = "Panel 2", content = div(
61+
class = "panel",
62+
Button(text = "Open 3", onClick = openPanel("panel3")),
63+
Button(text = "Close", onClick = closePanel())
64+
)),
65+
list(id = "panel3", title = "Panel 3", content = div(
66+
class = "panel",
67+
Button(text = "Open 4", onClick = openPanel("panel4")),
68+
Button(text = "Close", onClick = closePanel())
69+
)),
70+
list(id = "panel4", title = "Panel 4", content = div(
71+
class = "panel",
72+
Button(text = "Close", onClick = closePanel())
73+
))
74+
)
5275
)
5376
)
5477
}

inst/examples/showcase/app.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ sections <- list(
2424
item("Navbar", "Navbar"),
2525
item("Non-ideal state", "NonIdealState"),
2626
item("Overflow list", "OverflowList"),
27-
item("Panel stack (v2)", "PanelStack2"),
27+
item("Panel stack", "PanelStack"),
2828
item("Progress bar", "ProgressBar"),
2929
item("Resize sensor", "ResizeSensor"),
3030
item("Spinner", "Spinner"),

inst/www/blueprint.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/src/PanelStack.module.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.panelStack {
2+
border: 1px solid lightgrey;
3+
height: 100%;
4+
width: 100%;
5+
}

js/src/index.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ import "@blueprintjs/select/lib/css/blueprint-select.css";
55
import * as BlueprintSelect from "@blueprintjs/select";
66
import * as Blueprint from "@blueprintjs/core";
77

8-
import * as Inputs from './inputs';
9-
import Suggest from './suggest';
10-
import Select from './select';
11-
import MultiSelect from './multiselect';
12-
import MultiSlider from './multiSlider';
13-
import Tree from './tree';
8+
import * as Inputs from "./inputs";
9+
import Suggest from "./suggest";
10+
import Select from "./select";
11+
import MultiSelect from "./multiselect";
12+
import MultiSlider from "./multiSlider";
13+
import Tree from "./tree";
1414
import ResizeSensor from "./resizeSensor.js";
15+
import PanelStack, { panelStackHandlers } from "./panelStack";
1516

16-
import './toaster';
17+
import "./toaster";
1718

1819
window.jsmodule = {
1920
...window.jsmodule,
@@ -27,5 +28,7 @@ window.jsmodule = {
2728
MultiSlider,
2829
Tree,
2930
ResizeSensor,
31+
PanelStack,
32+
panelStackHandlers,
3033
},
3134
};

js/src/panelStack.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import * as React from "react";
2+
import PropTypes from "prop-types";
3+
import { PanelStack2 } from "@blueprintjs/core";
4+
import styles from "./PanelStack.module.css";
5+
6+
const PanelsType = PropTypes.arrayOf(
7+
PropTypes.shape({
8+
id: PropTypes.string,
9+
title: PropTypes.string,
10+
content: PropTypes.node,
11+
})
12+
);
13+
14+
export const panelStackHandlers = {};
15+
16+
const Panel = ({ content }) => {
17+
return React.createElement("div", { style: { padding: 10 } }, content);
18+
};
19+
Panel.propTypes = {
20+
content: PropTypes.node,
21+
};
22+
23+
const PanelStack = ({ panels, ns, size, ...propsRest }) => {
24+
const [stack, setStack] = React.useState([
25+
{
26+
renderPanel: Panel,
27+
title: panels[0].title,
28+
props: { content: panels[0].content },
29+
},
30+
]);
31+
const addToPanelStack = (newPanel) =>
32+
setStack((stack) => [...stack, newPanel]);
33+
const removeFromPanelStack = () => setStack((stack) => stack.slice(0, -1));
34+
React.useEffect(() => {
35+
panelStackHandlers[ns] = {
36+
openPanel: (panelId) => {
37+
const { title, content } = panels.find(({ id }) => id == panelId);
38+
addToPanelStack({
39+
renderPanel: Panel,
40+
title,
41+
props: { content },
42+
});
43+
},
44+
closePanel: removeFromPanelStack,
45+
};
46+
return () => delete panelStackHandlers[ns];
47+
}, [panels]);
48+
return React.createElement(
49+
"div",
50+
{ style: { width: size[0], height: size[1] } },
51+
React.createElement(PanelStack2, {
52+
className: styles.panelStack,
53+
onOpen: addToPanelStack,
54+
onClose: removeFromPanelStack,
55+
stack: stack,
56+
...propsRest,
57+
})
58+
);
59+
};
60+
PanelStack.propTypes = {
61+
panels: PanelsType,
62+
ns: PropTypes.string,
63+
size: PropTypes.arrayOf(PropTypes.number),
64+
propsRest: PropTypes.object,
65+
};
66+
67+
export default PanelStack;

man/PanelStack.Rd

Lines changed: 116 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)