brimdata / react-arborist Goto Github PK
View Code? Open in Web Editor NEWThe complete tree view component for React
License: MIT License
The complete tree view component for React
License: MIT License
First of all, thanks for creating this package!
Currently, the tree only works with static widths and heights (using observers excluded).
However, since the tree height is already calculated in OuterElement
in tree.tsx
, I don't see why a static height would be required.
I did some quick tests - passing the calculated tree height to the enclosing position: relative
div and changing the overflow
values was already enough to get rid of the "height" prop requirement.
Bonus: Custom scroll bar libraries also started working correctly.
It's reported that this happens. I am also aware that there can only be one instance of html5 backend on the page at once.
This is possible today, but maybe we could make an easier api.
Today, you'd make a custom RowRenderer and NodeRenderer. Then in there, you'd prevent selection if that node meets a certain criteria. An Tree Prop would make it all easier.
The docs say there's childrenAccessor and isOpenAccessor but I only see getChildren in the code ๐ค is this upcoming API?
Hi James,
I need to listen for the tree node select event via the Tree component.
Would it be possible to add this?
My use case is I'm using check-boxes to select multiple tree nodes using the handlers.select
which has shift-click but I only want one event to fire.
Kind regards,
Marten
I'm probably missing something, but it seems a little strange to me that the Tree
component takes data for its children, rather than the more typical approach of children nodes being content to be passed in to a component. It seems like a more common approach would be to pass the node renderer as a prop to Tree
. Which would probably mean that Tree
would be a self-closing tag/component.
I notice here that the main Tree
component implementation does, indeed, assign children
to the renderer
prop of TreeViewProvider
, which appears to be the real workhorse component.
Suggestion:
renderer
prop on Tree
Tree
's childrenThis way we don't have to keep a ref to the tree in the parent component if we don't need to.
It might be cleaner to have an onSelect callback that can be placed on the root tree node. It only get's fired when an item gets selected. A group can only be selected during multi select.
New Api:
type TreeProps = {
onSelect: () // only get's called when a single item is selected.
}
Then when the tree selects something programmatically, this code can run and does not need to be duplicated.
This should be possible with the current api, but it would be good to write a demo. If anyone has already done this, please post the code here! Thanks.
Is there any facility in react-arborist to control dropping via source and target? More specifically can I limit dropping based on a combination of source key and target key? React DnD provides this via canDrop
but disabledDrop
is really just a static list. Thanks.
Hi there,
I am trying to write a custom container for our tree but can't find any document on renderContainer
? Just reading the code, the renderContainer
provides no tree-api
access, so not sure if it is even possible to have a custom one?
Thanks for the great works!
Cheers
Is there a way to get the tree's height? The only way I've found is by multiplying the rowHeight
with tree.visibleNodes()
- but the latter is only available inside the node renderer.
I'd like to use custom scroll bars with this package.
Hey the component is really cool but I would like to ask for an example with connection line (horizontal and vertical).
Is it possible to provide code example or add it to the api?
I tried doing it with css and custom render of the node but got confused.
Tnx!
Hello,
I'm looking for a way to move a node to the child of the other leaf node.
Currently, I can move nodes into exisiting folder nodes (it means they have children already)
Please help me!
When a parent folder is being dragged into a child there is no check to prohibit this from happening.
This causes the entire subtree to disappear.
Might be easier if we have separate types for each of these.
How does one drag/drop with the Tree.data attribute set (instead of the initialData). There are no drag and drop callbacks. Am I missing something? Also I would prefer to just use initialData, let the tree handle everything like it does by default, and have callbacks for when I add/edit/delete/drag nodes so I can update my database. Right now this isn't possible and I have to re-implement a lot of functionality in the callbacks because the callbacks don't work with initialData set.
We need a way to mount the Tree component with a selection already in place.
Idea 1: I think a prop called initialSelectedIds
would be a good option.
Idea 2: Or we do nothing and leave this to the user. They can get a tree ref, then use an effect for each time their "selection" criteria changes. Then use the tree's api to select that id.
Is this planned?
Thanks for this great library.
I'm looking at the this demo and when I click on the edit button (hand that hold a pen), everything move up and input will stick to top of the container.
Is there any way to do this?
I saw your post on reddit. Nice tree control.
I wanted to give a suggestion that could help take it to the next level. Right now it is very mouse oriented. However, not everyone may prefer to use the mouse. If you look up the the tree role on MDN it documents keyboard interactions for a tree. That way users can operate it without taking their hands off the keyboard if they prefer (similar to Ctrl-C Ctrl-V for copy and paste).
Failed to compile.
./node_modules/react-arborist/dist/module.js 394:7
Module parse failed: Unexpected token (394:7)
File was processed with these loaders:
* ./node_modules/react-scripts/node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| };
|
> el?.addEventListener("keydown", cb);
| return () => {
| el?.removeEventListener("keydown", cb);
As pointed out on Hacker News:
W3C has some in-depth list of expected keyboard interactions:
https://w3c.github.io/aria-practices/#TreeView
https://w3c.github.io/aria-practices/examples/treeview/treev...
Data
const treeData = {
id: nanoid(),
name: "Bookmarks",
isOpen: true,
children: [
{
id: nanoid(),
name: "Brim Github",
isOpen: true,
children: [
{
id: nanoid(),
name: "brim/pulls",
},
{
id: nanoid(),
name: "zed/pulls",
},
{
id: nanoid(),
name: "brim/releases",
},
{
id: nanoid(),
name: "brim/zson",
},
{
id: nanoid(),
name: "Level 3",
isOpen: true,
children: [
{ id: nanoid(), name: "amazon" },
{ id: nanoid(), name: "apple" },
{ id: nanoid(), name: "facebook" },
],
},
],
},
{
id: nanoid(),
name: "Brim Zenhub",
isOpen: true,
children: [
{ id: nanoid(), name: "My Issues" },
{ id: nanoid(), name: "Brim All Issues" },
{ id: nanoid(), name: "MVP 0" },
{ id: nanoid(), name: "Manual Brim Test Cases" },
],
},
{
id: nanoid(),
name: "Meetings",
isOpen: true,
children: [
{ id: nanoid(), name: "Thursday" },
{ id: nanoid(), name: "Saturday" },
],
},
{
id: nanoid(),
name: "Personal",
isOpen: true,
children: [
{ id: nanoid(), name: "Imbox" },
{ id: nanoid(), name: "Facebook Marketplace" },
{ id: nanoid(), name: "Bank of America" },
{ id: nanoid(), name: "Mint" },
{ id: nanoid(), name: "Learn UI Design" },
],
},
],
};
Element
function MaybeToggleButton({ toggle, isOpen, isFolder, isSelected }: any) {
if (isFolder) {
const Icon = isOpen ? treeMinusSmall : treePlusSmall;
return (
<button onClick={toggle} css={treeExpand}>
<img src={Icon} alt="" />
</button>
);
} else {
return <div className="spacer" />;
}
}
function Node({ innerRef, styles, data, state, handlers, tree }: any) {
debugger;
const folder = Array.isArray(data.children);
const open = state.isOpen;
const name = data.name;
return (
<div
ref={innerRef}
style={styles.row}
className={clsx("tree-row", state)}
onClick={(e) => handlers.select(e)}
css={treeRow}
>
<div
className="tree-row-contents"
style={styles.indent}
css={treeRowContents}
>
<MaybeToggleButton
toggle={handlers.toggle}
isOpen={open}
isFolder={folder}
isSelected={state.isSelected}
/>
<div style={styles.indent}>{data.name}</div>
</div>
</div>
);
}
Main Component
<Tree
data={treeData}
hideRoot={true}
isOpen="isOpen"
getChildren="children"
indent={24}
>
{Node}
</Tree>
Love what you have made!!
Learning so much by reading the source. Fantastic job.
I would love a drag handle ref option.
packages/react-arborist/src/components/row.tsx maybe expose optionally the dragRef ?
Thanks!
This will help users get up and running quickly, without needing to create their own styles at first. @mason-fish had this idea.
It'd be nice to have a demo where you have folders of expenses and each expense amount is on the right. The folders would sum the children and display it on the right.
Dragging around would update folder amounts like usual react stuff.
handlers.select(e, {selectOnClick: true})
That's weird.
I have a use-case where I never want to collapse the tree at any level. I just want a reorderable tree that's always expanded.
It would be good to allow a prop for this. Eg alwaysOpen
/ alwaysExpanded
which did this.
It would also disable left/right arrow keys to expand/collapse branches)
Change the other api to TreeApi.selectByIndex
If you have 2 Tree components rendering at the same time a React Maximum update depth exceeded
error is thrown. The line below is causing the error.
useLayoutEffect(() => {
// @ts-ignore
dispatch(actions.setVisibleIds(api.visibleIds, api.idToIndex)); // <- causes the error.
}, [dispatch, api.visibleIds, api.idToIndex, props.root]);
Here is a codesandbox with a basic repro.
https://codesandbox.io/s/react-arborist-forked-xb7ezj
Thanks!
If we create a simple handlers.onClick
function, it should check if the meta key is held. If so, it needs to select the folder, not toggle it. Otherwise it toggles it.
If we create an onSelect property, it should not run if the meta keys are held down.
Hello! I'm trying the demo and amazing package! The only thing i'm missing is an historic and a ctrl + Z, in case you did not have it already in mind!
I will try the package and if i end up using it I migth try to build that feature myself if you accept contributors :)
Cheers for the project!
Nothing renders. You need to use data.id
instead of data.name
.
due to :
Consider accomodating users of assistive tech, with the appropriate roles and aria attribution.
I've created a new react apop using create-react-app and updated App.js with the example from the project's GitHub README so that I can start experimenting and learning, but the example given renders nothing for me. In the React Developer Tools, I can see the nodes are there, but I have no idea yet how to make them visible.
Shown below is what I see in the Components tab of the tools...
Following is my App.js
...
import './App.css';
import { Tree } from "react-arborist";
const data = {
id: "The Root",
children: [{ id: "Node A" }, { id: "Node B" }]
}
function Node({ ref, styles, data }) {
return (
<div ref={ref} style={styles.row}>
<div style={styles.indent}>
{data.name}
</div>
</div>
)
}
function App() {
return (
<div className="App">
<div className="workspace-leaf-content" data-type="collection-manager">
<div className="view-content">
<h4>React Arborist Tree Component Test</h4>
<Tree data={data}>{Node}</Tree>
</div>
</div>
</div>
);
}
export default App;
But, as you can see, nothing renders...
I am guessing the README just assumes one knows more than I do about React or something. I could use a hint! Or do you sell consulting hours?
I want to make a tree which would load data asynchronously upon user opening a tree node (which seems easy to do here) or upon scrolling down the tree root (in my use case root would have not only folders, but also lots and lots of items (thoughsands of them) and it wouldn't be a great experience for a user to load them all at once).
Is there a way to get the overall height of the scroll container and current scroll position to make the latter possible? Or if not, is there a better way to do what I need?
The styles are hard-coded at the moment
Hello,
I would like to replace react-dropdown-tree-select with this library.
Would it be possible to add functionality where you can checkbox folders and search for folders?
There are a number of use-cases where extra visual spacing and/or just larger rowHeight
s for specific nodes or groups of nodes on the tree would be helpful. As far as I can tell, the height of all node rows is set globally by the rowHeight
prop with no option (or styling) possible to change it for individual rows.
Hi,
I have seen, we are using tree with absolute position to align tree items.
But can we use nested ul and li element to align trees?
We need to document the Tree's onClick and onContextMenu props. Those are attached to the tree container so that you can take action when the user clicks or rightclicks on an area of the tree that has no items. Maybe you clear the selection, or provide a different context menu.
All the keyboard shortcuts are listed in the DefaultContainer component. I could see how people would want to use their own keybindings.
Something like:
{
"a": "createLeaf",
"shift+a": "createInternal"
"space": "activate",
"meta+DownArrow": "activate"
}
We need to have two tree instances which allow users to move nodes (complete with their hierarchy) between them.
For the API, we'd have a button
that onClick, moves all selected nodes from tree1 to tree2. The node will disappear from tree1, and appear in tree2. If it's parent nodes have no other children, they too will disappear. If any parent nodes already existed in tree2, they will merge.
Drag and drop would use the same move logic, it would just occur when a user drags a node.
I don't see any clear support for this yet.
This works pretty well. I've been comparing this package to a bunch of other react trees, and I am most hopeful this will work for my use case.
One thing I find strange is I can only access selection state from inside the Node renderer. Why not expose onSelect the same as you do with onEdit and onToggle, to make it easier for syncing with the selection state of the tree?
Related, you added an onClick prop (that isn't listed on the documentation page) and I'm wondering if that was meant to make it possible to configure external selection state synching? It fires the synthetic click event and not some computed state object so I'd be we wary using that to try and set up outside mgmt.
Am I missing something?
While I've implemented the tree just fine, I'm stuck on how to make something actually draggable.
I tried adding isDraggable/isDroppable to the data nodes. No luck.
Any thoughts?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.