Skip to content

Commit 3a77db9

Browse files
committed
PanelStack API improved
1 parent dd8314c commit 3a77db9

File tree

8 files changed

+178
-8
lines changed

8 files changed

+178
-8
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export(NumericInput.shinyInput)
5757
export(OL)
5858
export(OverflowList)
5959
export(Overlay)
60+
export(PanelStack)
6061
export(PanelStack2)
6162
export(Popover)
6263
export(Pre)

R/components.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,22 @@ OverflowList <- component("OverflowList")
374374
#'
375375
#' @example inst/examples/PanelStack2.R
376376
#' @inherit template params
377+
#' @param panels List of lists - each list contains `title` (string) and `content` (HTML)
378+
#' @param size Numeric vector of length 2 - `c(width, height)`
377379
#' @export
378380
PanelStack2 <- component("PanelStack2")
379381

382+
#' @rdname PanelStack2
383+
#' @export
384+
PanelStack <- function(panels, size = c(300, 250), ...) {
385+
shiny.react::reactElement(
386+
module = "@/shiny.blueprint",
387+
name = "PanelStack",
388+
props = shiny.react::asProps(panels = panels, size = size, ...),
389+
deps = blueprintDependency()
390+
)
391+
}
392+
380393
#' Progress bar
381394
#'
382395
#' Documentation: <https://blueprintjs.com/docs/#core/components/progress-bar>

inst/examples/PanelStack2.R

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ ui <- function(id) {
4949
PanelStack2(
5050
className = "panel-stack",
5151
initialPanel = JS("createPanel(1)")
52+
),
53+
PanelStack(
54+
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"))
60+
)
5261
)
5362
)
5463
}

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: 9 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 from "./panelStack";
1516

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

1819
window.jsmodule = {
1920
...window.jsmodule,
@@ -27,5 +28,6 @@ window.jsmodule = {
2728
MultiSlider,
2829
Tree,
2930
ResizeSensor,
31+
PanelStack,
3032
},
3133
};

js/src/panelStack.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import * as React from "react";
2+
import PropTypes from "prop-types";
3+
import { Button, PanelStack2, Classes } from "@blueprintjs/core";
4+
import styles from "./PanelStack.module.css";
5+
6+
const PanelsType = PropTypes.arrayOf(
7+
PropTypes.shape({
8+
title: PropTypes.string,
9+
content: PropTypes.node,
10+
})
11+
);
12+
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+
};
32+
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+
);
82+
};
83+
Panel.propTypes = {
84+
panels: PanelsType,
85+
index: PropTypes.number,
86+
title: PropTypes.string,
87+
openPanel: PropTypes.func,
88+
closePanel: PropTypes.func,
89+
};
90+
91+
const PanelStack = ({ panels, size, ...propsRest }) => {
92+
const [stack, setStack] = React.useState([
93+
{
94+
renderPanel: Panel,
95+
props: { panels, index: 0, title: panels[0].title },
96+
},
97+
]);
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+
);
106+
return React.createElement(
107+
"div",
108+
{ style: { width: size[0], height: size[1] } },
109+
React.createElement(PanelStack2, {
110+
className: styles.panelStack,
111+
onOpen: addToPanelStack,
112+
onClose: removeFromPanelStack,
113+
showPanelHeader: false,
114+
stack: stack,
115+
...propsRest,
116+
})
117+
);
118+
};
119+
PanelStack.propTypes = {
120+
panels: PanelsType,
121+
size: PropTypes.arrayOf(PropTypes.number),
122+
propsRest: PropTypes.object,
123+
};
124+
export default PanelStack;

man/PanelStack2.Rd

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