Skip to content

Commit 4bd21f5

Browse files
committed
PanelStack - openPanel & removePanel handlers exported
1 parent 3a77db9 commit 4bd21f5

File tree

10 files changed

+114
-196
lines changed

10 files changed

+114
-196
lines changed

NAMESPACE

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export(OL)
5858
export(OverflowList)
5959
export(Overlay)
6060
export(PanelStack)
61-
export(PanelStack2)
61+
export(PanelStack.shinyWrapper)
6262
export(Popover)
6363
export(Pre)
6464
export(ProgressBar)
@@ -91,6 +91,8 @@ export(Toaster)
9191
export(Tree)
9292
export(Tree.shinyInput)
9393
export(UL)
94+
export(closePanel)
95+
export(openPanel)
9496
export(reactOutput)
9597
export(renderReact)
9698
export(runExample)

R/components.R

Lines changed: 9 additions & 8 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",
@@ -375,17 +375,18 @@ OverflowList <- component("OverflowList")
375375
#' @example inst/examples/PanelStack2.R
376376
#' @inherit template params
377377
#' @param panels List of lists - each list contains `title` (string) and `content` (HTML)
378+
#' @param ns Namespace of given panel stack (required if there's more than 1 panel stack)
378379
#' @param size Numeric vector of length 2 - `c(width, height)`
379380
#' @export
380-
PanelStack2 <- component("PanelStack2")
381+
PanelStack <- component("PanelStack2")
381382

382-
#' @rdname PanelStack2
383+
#' @rdname PanelStack
383384
#' @export
384-
PanelStack <- function(panels, size = c(300, 250), ...) {
385+
PanelStack.shinyWrapper <- function(panels, ns = "ps", size = c(300, 250), ...) { # nolint
385386
shiny.react::reactElement(
386387
module = "@/shiny.blueprint",
387388
name = "PanelStack",
388-
props = shiny.react::asProps(panels = panels, size = size, ...),
389+
props = shiny.react::asProps(panels = panels, ns = ns, size = size, ...),
389390
deps = blueprintDependency()
390391
)
391392
}

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: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,31 @@ customComponents <- tagList(
4646
ui <- function(id) {
4747
tagList(
4848
customComponents,
49-
PanelStack2(
49+
PanelStack(
5050
className = "panel-stack",
5151
initialPanel = JS("createPanel(1)")
5252
),
53-
PanelStack(
53+
PanelStack.shinyWrapper(
5454
panels = list(
55-
list(title = "Panel 1", content = div("Content 1")),
56-
list(title = "Panel 2", content = div("Content 2")),
57-
list(title = "Panel 3", content = div("Content 3")),
58-
list(title = "Panel 4", content = div("Content 4")),
59-
list(title = "Panel 5", content = div("Content 5"))
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+
))
6074
)
6175
)
6276
)

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 (v2)", "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/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import MultiSelect from "./multiselect";
1212
import MultiSlider from "./multiSlider";
1313
import Tree from "./tree";
1414
import ResizeSensor from "./resizeSensor.js";
15-
import PanelStack from "./panelStack";
15+
import PanelStack, { panelStackHandlers } from "./panelStack";
1616

1717
import "./toaster";
1818

@@ -29,5 +29,6 @@ window.jsmodule = {
2929
Tree,
3030
ResizeSensor,
3131
PanelStack,
32+
panelStackHandlers,
3233
},
3334
};

js/src/panelStack.js

Lines changed: 28 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,67 @@
11
import * as React from "react";
22
import PropTypes from "prop-types";
3-
import { Button, PanelStack2, Classes } from "@blueprintjs/core";
3+
import { PanelStack2 } from "@blueprintjs/core";
44
import styles from "./PanelStack.module.css";
55

66
const PanelsType = PropTypes.arrayOf(
77
PropTypes.shape({
8+
id: PropTypes.string,
89
title: PropTypes.string,
910
content: PropTypes.node,
1011
})
1112
);
1213

13-
const NavigationButton = ({ text, onClick, direction }) => {
14-
const icon =
15-
direction === "left"
16-
? { icon: "chevron-left" }
17-
: { rightIcon: "chevron-right" };
18-
return React.createElement(Button, {
19-
className: Classes.PANEL_STACK_HEADER_BACK,
20-
minimal: true,
21-
onClick: onClick,
22-
small: true,
23-
text: text,
24-
...icon,
25-
});
26-
};
27-
NavigationButton.propTypes = {
28-
text: PropTypes.string,
29-
onClick: PropTypes.func,
30-
direction: PropTypes.string,
31-
};
14+
export const panelStackHandlers = {};
3215

33-
const Panel = ({ panels, index, title, openPanel, closePanel }) => {
34-
const nextIndex = index + 1;
35-
const prevIndex = index - 1;
36-
let prevButton, nextButton;
37-
if (panels[prevIndex]) {
38-
prevButton = React.createElement(NavigationButton, {
39-
text: panels[prevIndex].title,
40-
onClick: closePanel,
41-
direction: "left",
42-
});
43-
}
44-
if (panels[nextIndex]) {
45-
const nextTitle = panels[nextIndex].title;
46-
const openNext = () => {
47-
openPanel({
48-
renderPanel: Panel,
49-
props: { panels, index: nextIndex, title: nextTitle },
50-
});
51-
};
52-
nextButton = React.createElement(NavigationButton, {
53-
text: nextTitle,
54-
onClick: openNext,
55-
direction: "right",
56-
});
57-
}
58-
return React.createElement(
59-
React.Fragment,
60-
{},
61-
React.createElement(
62-
"div",
63-
{ className: "bp4-panel-stack-header" },
64-
React.createElement("span", {}, prevButton),
65-
React.createElement(
66-
"div",
67-
{ className: "bp4-heading bp4-text-overflow-ellipsis" },
68-
title
69-
),
70-
React.createElement(
71-
"span",
72-
{ style: { justifyContent: "end" } },
73-
nextButton
74-
)
75-
),
76-
React.createElement(
77-
"div",
78-
{ style: { padding: 10 } },
79-
panels[index].content
80-
)
81-
);
16+
const Panel = ({ content }) => {
17+
return React.createElement("div", { style: { padding: 10 } }, content);
8218
};
8319
Panel.propTypes = {
84-
panels: PanelsType,
85-
index: PropTypes.number,
86-
title: PropTypes.string,
87-
openPanel: PropTypes.func,
88-
closePanel: PropTypes.func,
20+
content: PropTypes.node,
8921
};
9022

91-
const PanelStack = ({ panels, size, ...propsRest }) => {
23+
const PanelStack = ({ panels, ns, size, ...propsRest }) => {
9224
const [stack, setStack] = React.useState([
9325
{
9426
renderPanel: Panel,
95-
props: { panels, index: 0, title: panels[0].title },
27+
title: panels[0].title,
28+
props: { content: panels[0].content },
9629
},
9730
]);
98-
const addToPanelStack = React.useCallback(
99-
(newPanel) => setStack((stack) => [...stack, newPanel]),
100-
[]
101-
);
102-
const removeFromPanelStack = React.useCallback(
103-
() => setStack((stack) => stack.slice(0, -1)),
104-
[]
105-
);
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]);
10648
return React.createElement(
10749
"div",
10850
{ style: { width: size[0], height: size[1] } },
10951
React.createElement(PanelStack2, {
11052
className: styles.panelStack,
11153
onOpen: addToPanelStack,
11254
onClose: removeFromPanelStack,
113-
showPanelHeader: false,
11455
stack: stack,
11556
...propsRest,
11657
})
11758
);
11859
};
11960
PanelStack.propTypes = {
12061
panels: PanelsType,
62+
ns: PropTypes.string,
12163
size: PropTypes.arrayOf(PropTypes.number),
12264
propsRest: PropTypes.object,
12365
};
66+
12467
export default PanelStack;

man/PanelStack.Rd

Lines changed: 31 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)