Skip to content

Commit a65ee3a

Browse files
authored
Merge pull request #61 from Appsilon/tree-shiny-input
`Tree.shinyInput` added
2 parents d8c6005 + 45ee782 commit a65ee3a

File tree

14 files changed

+291
-61
lines changed

14 files changed

+291
-61
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export(TextArea)
8787
export(TextArea.shinyInput)
8888
export(Toaster)
8989
export(Tree)
90+
export(Tree.shinyInput)
9091
export(UL)
9192
export(reactOutput)
9293
export(renderReact)

R/components.R

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ input <- function(name, defaultValue) {
4848
}
4949
}
5050

51+
tree <- function(name) {
52+
function(inputId, data, ...) {
53+
shiny.react::reactElement(
54+
module = "@/shiny.blueprint",
55+
name = name,
56+
props = shiny.react::asProps(inputId = inputId, data = data, ...),
57+
deps = blueprintDependency()
58+
)
59+
}
60+
}
61+
5162
select <- function(name) {
5263
function(
5364
inputId,
@@ -433,10 +444,18 @@ Text <- component("Text")
433444
#' Documentation: <https://blueprintjs.com/docs/#core/components/tree>
434445
#'
435446
#' @example inst/examples/Tree.R
436-
#' @inherit template params
447+
#' @param inputId The `input` slot that will be used to access the value.
448+
#' @param data A list of nodes data. Params:
449+
#' required: `label`.
450+
#' optional: `childNodes`, `icon`, `hasCaret`, `isExpanded`, `disabled`, `secondaryLabel`
451+
#' @param ... Component props and children. See the official Blueprint docs for details.
437452
#' @export
438453
Tree <- component("Tree")
439454

455+
#' @rdname Tree
456+
#' @export
457+
Tree.shinyInput <- tree("Tree") # nolint
458+
440459
#' Form group
441460
#'
442461
#' Documentation: <https://blueprintjs.com/docs/#core/components/form-group>

inst/examples/Tree.R

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,34 @@ ui <- function(id) {
6565
tagList(
6666
reactOutput(ns("tree")),
6767
Divider(),
68-
reactOutput(ns("info"))
68+
reactOutput(ns("info")),
69+
Divider(),
70+
Tree.shinyInput(
71+
inputId = ns("selected_nodes"),
72+
data = list(
73+
list(
74+
label = "1",
75+
isExpanded = TRUE,
76+
childNodes = list(
77+
list(
78+
label = "1.1",
79+
childNodes = list(list(label = "1.1.1"))
80+
),
81+
list(label = "1.2")
82+
)
83+
),
84+
list(
85+
label = "2",
86+
childNodes = list(
87+
list(label = "2.1")
88+
)
89+
),
90+
list(label = "3", hasCaret = TRUE)
91+
)
92+
),
93+
Divider(),
94+
tags$span("Hold ", tags$b("shift ⬆"), " to select multiple nodes."),
95+
reactOutput(ns("selected_nodes_list")),
6996
)
7097
}
7198

@@ -100,6 +127,10 @@ server <- function(id) {
100127
tags$li("Selected (label): ", input$click$label)
101128
)
102129
})
130+
131+
output$selected_nodes_list <- renderReact({
132+
UL(lapply(input$selected_nodes, function(node) tags$li(node)))
133+
})
103134
})
104135
}
105136

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.

inst/www/blueprint.min.js.LICENSE.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,12 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
4747
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
4848
PERFORMANCE OF THIS SOFTWARE.
4949
***************************************************************************** */
50+
51+
/**
52+
* @license
53+
* Lodash <https://lodash.com/>
54+
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
55+
* Released under MIT license <https://lodash.com/license>
56+
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
57+
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
58+
*/

js/src/index.js

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@ 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.jsx';
9-
import * as Suggests from './suggest.js';
10-
import * as Selects from './select.js';
11-
import * as MultiSelect from './multiselect.js';
12-
import * as MultiSlider from './multiSlider.js';
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';
1314

14-
import './toaster.js';
15+
import './toaster';
1516

1617
window.jsmodule = {
1718
...window.jsmodule,
1819
'@blueprintjs/core': Blueprint,
1920
'@blueprintjs/select': BlueprintSelect,
2021
'@/shiny.blueprint': {
2122
...Inputs,
22-
...Suggests,
23-
...Selects,
24-
...MultiSelect,
25-
...MultiSlider,
23+
Suggest,
24+
Select,
25+
MultiSelect,
26+
MultiSlider,
27+
Tree,
2628
},
2729
};
File renamed without changes.

js/src/multiSlider.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const propTypes = {
77
values: PropTypes.array,
88
};
99

10-
export const MultiSlider = ({ inputId, values, ...propsRest }) => {
10+
const MultiSlider = ({ inputId, values, ...propsRest }) => {
1111
const [state, setState] = React.useState(values.map(({ value }) => value));
1212

1313
React.useEffect(() => Shiny.setInputValue(inputId, state), []);
@@ -33,3 +33,4 @@ export const MultiSlider = ({ inputId, values, ...propsRest }) => {
3333
};
3434

3535
MultiSlider.propTypes = propTypes;
36+
export default MultiSlider;

js/src/multiselect.js

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import React from 'react';
2-
import PropTypes from 'prop-types';
3-
import { MenuItem } from '@blueprintjs/core';
4-
import { MultiSelect2 } from '@blueprintjs/select';
5-
import { highlightText } from './utils/highlight-text.js';
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import { MenuItem } from "@blueprintjs/core";
4+
import { MultiSelect2 } from "@blueprintjs/select";
5+
import { highlightText } from "./utils/highlight-text";
66

77
const filterItem = (query, item) => {
88
return item.text.toLowerCase().indexOf(query.toLowerCase()) >= 0;
@@ -17,8 +17,13 @@ const propTypes = {
1717
popoverProps: PropTypes.object,
1818
};
1919

20-
export const MultiSelect = ({ items, selected, inputId, popoverProps, ...propsRest }) => {
21-
20+
const MultiSelect = ({
21+
items,
22+
selected,
23+
inputId,
24+
popoverProps,
25+
...propsRest
26+
}) => {
2227
const [selectedItems, setSelectedItems] = React.useState(
2328
items.filter((item) => selected.includes(item.text))
2429
);
@@ -50,25 +55,31 @@ export const MultiSelect = ({ items, selected, inputId, popoverProps, ...propsRe
5055
[selectedItems]
5156
);
5257

53-
const handleItemRemove = React.useCallback((removedItem) => {
54-
deselectItem(removedItem);
55-
}, [deselectItem]);
58+
const handleItemRemove = React.useCallback(
59+
(removedItem) => {
60+
deselectItem(removedItem);
61+
},
62+
[deselectItem]
63+
);
5664

57-
const handleItemSelect = React.useCallback((newItem) => {
58-
if (!isSelectedItem(newItem)) {
59-
selectItem(newItem);
60-
} else {
61-
deselectItem(newItem);
62-
}
63-
}, [isSelectedItem, selectItem, deselectItem]);
65+
const handleItemSelect = React.useCallback(
66+
(newItem) => {
67+
if (!isSelectedItem(newItem)) {
68+
selectItem(newItem);
69+
} else {
70+
deselectItem(newItem);
71+
}
72+
},
73+
[isSelectedItem, selectItem, deselectItem]
74+
);
6475

6576
const renderItem = React.useCallback(
6677
(item, { handleClick, modifiers, query }) => {
6778
if (!modifiers.matchesPredicate) {
6879
return null;
6980
}
7081
return React.createElement(MenuItem, {
71-
icon: isSelectedItem(item) ? 'tick' : 'blank',
82+
icon: isSelectedItem(item) ? "tick" : "blank",
7283
selected: modifiers.active,
7384
active: modifiers.active,
7485
disabled: modifiers.disabled,
@@ -102,3 +113,4 @@ export const MultiSelect = ({ items, selected, inputId, popoverProps, ...propsRe
102113
};
103114

104115
MultiSelect.propTypes = propTypes;
116+
export default MultiSelect;

js/src/select.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import React from 'react';
2-
import PropTypes from 'prop-types';
3-
import { MenuItem, Button } from '@blueprintjs/core';
4-
import { Select2 } from '@blueprintjs/select';
5-
import { highlightText } from './utils/highlight-text.js';
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
import { MenuItem, Button } from "@blueprintjs/core";
4+
import { Select2 } from "@blueprintjs/select";
5+
import { highlightText } from "./utils/highlight-text";
66

77
const renderItem = (item, { handleClick, modifiers, query }) => {
88
if (!modifiers.matchesPredicate) {
@@ -29,7 +29,7 @@ const filterItem = (query, item) => {
2929
return item.text.toLowerCase().indexOf(query.toLowerCase()) >= 0;
3030
};
3131

32-
export const Select = ({ items, selected, inputId, popoverProps, ...propsRest }) => {
32+
const Select = ({ items, selected, inputId, popoverProps, ...propsRest }) => {
3333
const [currentItem, setCurrentItem] = React.useState(
3434
items.find(({ text }) => text === selected)
3535
);
@@ -68,3 +68,4 @@ export const Select = ({ items, selected, inputId, popoverProps, ...propsRest })
6868
};
6969

7070
Select.propTypes = propTypes;
71+
export default Select;

0 commit comments

Comments
 (0)