react-arborist 2.0.0-rc.1 → 2.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,9 +2,13 @@
2
2
 
3
3
  <h1>React Arborist</h1>
4
4
 
5
- The tree view is ubiquitous in software applications. This library provides the React ecosystem with complete solution to build the equivalent of the VSCode sidebar, the Mac Finder, the Windows Explorer, or the Sketch/Figma layers panel.
5
+ [See the Demos](https://react-arborist.netlify.app/)
6
6
 
7
- _New Link To Demo_
7
+ The tree view is ubiquitous in software applications. This library provides the React ecosystem with a complete solution to build the equivalent of a VSCode sidebar, Mac Finder, Windows Explorer, or Sketch/Figma layers panel.
8
+
9
+ Here is a Gmail sidebar clone built with react-arborist.
10
+
11
+ <img src="https://user-images.githubusercontent.com/3460638/197306119-59fe59e6-50ae-4bc2-8cb9-3faa2bc52cd2.gif" width="270px" alt="Gmail sidebar clone built with react-arborist" />
8
12
 
9
13
  ## Features
10
14
 
@@ -23,8 +27,6 @@ _New Link To Demo_
23
27
  - More callbacks (onScroll, onActivate, onSelect)
24
28
  - Controlled or uncontrolled trees
25
29
 
26
- _NEW DEMO GIF HERE_
27
-
28
30
  > These docs are for version 2. It contains breaking changes. Here is the [v1.2.0 README](https://github.com/brimdata/react-arborist/tree/4fe9659d2c4cbd57582294330863d4fd7e7af74b).
29
31
 
30
32
  ## Installation
@@ -267,8 +269,7 @@ interface TreeProps<T extends IdObj> {
267
269
  children?: ElementType<renderers.NodeRendererProps<T>>;
268
270
  renderRow?: ElementType<renderers.RowRendererProps<T>>;
269
271
  renderDragPreview?: ElementType<renderers.DragPreviewProps>;
270
- renderCursor?: ElementType<renderers.DropCursorProps>;
271
- renderContainer?: ElementType<{}>;
272
+ renderCursor?: ElementType<renderers.CursorProps>;
272
273
 
273
274
  /* Sizes */
274
275
  rowHeight?: number;
@@ -291,6 +292,8 @@ interface TreeProps<T extends IdObj> {
291
292
  onActivate?: (node: NodeApi<T>) => void;
292
293
  onSelect?: (nodes: NodeApi<T>[]) => void;
293
294
  onScroll?: (props: ListOnScrollProps) => void;
295
+ onToggle?: (id: string) => void;
296
+ onFocus?: (node: NodeApi<T>) => void;
294
297
 
295
298
  /* Selection */
296
299
  selection?: string;
@@ -304,6 +307,7 @@ interface TreeProps<T extends IdObj> {
304
307
 
305
308
  /* Extra */
306
309
  className?: string | undefined;
310
+ rowClassName?: string | undefined;
307
311
  dndRootElement?: globalThis.Node | null;
308
312
  onClick?: MouseEventHandler;
309
313
  onContextMenu?: MouseEventHandler;
@@ -327,7 +331,7 @@ type RowRendererProps<T extends IdObj> = {
327
331
 
328
332
  The _\<NodeRenderer\>_ is responsible for attaching the drag ref, the node style (padding for indentation), the visual look of the node, the edit input of the node, and anything else you can dream up.
329
333
 
330
- There is a default renderer, but it's only there as a placeholder to get started. You'll wan't to create your own component for this. It is passed as the _\<Tree\>_ components only child.
334
+ There is a default renderer, but it's only there as a placeholder to get started. You'll want to create your own component for this. It is passed as the _\<Tree\>_ components only child.
331
335
 
332
336
  ```ts
333
337
  export type NodeRendererProps<T extends IdObj> = {
@@ -358,7 +362,7 @@ type DragPreviewProps = {
358
362
  The _\<Cursor\>_ is responsible for showing a line that indicates where the node will move to when it's dropped. The default is a blue line with circle on the left side. You may want to customize this. Pass your own component to the _renderCursor_ prop.
359
363
 
360
364
  ```ts
361
- export type DropCursorProps = {
365
+ export type CursorProps = {
362
366
  top: number;
363
367
  left: number;
364
368
  indent: number;
@@ -367,7 +371,7 @@ export type DropCursorProps = {
367
371
 
368
372
  ## Node API Reference
369
373
 
370
- #### State Properties
374
+ ### State Properties
371
375
 
372
376
  All these properties on the node instance return booleans related to the state of the node.
373
377
 
@@ -403,6 +407,10 @@ _node_.**isSelectedEnd**
403
407
 
404
408
  Returns true if node is the last of a contiguous group of selected nodes. Useful for styling.
405
409
 
410
+ _node_.**isOnlySelection**
411
+
412
+ Returns true if node is the only node selected in the tree.
413
+
406
414
  _node_.**isFocused**
407
415
 
408
416
  Returns true if node is focused.
@@ -428,11 +436,14 @@ type NodeState = {
428
436
  isSelectedEnd: boolean;
429
437
  isFocused: boolean;
430
438
  isOpen: boolean;
439
+ isClosed: boolean;
440
+ isLeaf: boolean;
441
+ isInternal: boolean;
431
442
  willReceiveDrop: boolean;
432
443
  };
433
444
  ```
434
445
 
435
- #### Accessors
446
+ ### Accessors
436
447
 
437
448
  _node_.**childIndex**
438
449
 
@@ -450,7 +461,7 @@ _node_.**nextSibling**
450
461
 
451
462
  Returns the next sibling in the data of this node. Returns null if none exist.
452
463
 
453
- #### Selection Methods
464
+ ### Selection Methods
454
465
 
455
466
  _node_.**select**()
456
467
 
@@ -468,7 +479,7 @@ _node_.**selectContiguous**()
468
479
 
469
480
  Deselect all nodes from the anchor node to the last selected node, the select all nodes from the anchor node to this node. The anchor changes to the focused node after calling _select()_ or _selectMulti()_.
470
481
 
471
- #### Activation Methods
482
+ ### Activation Methods
472
483
 
473
484
  _node_.**activate**()
474
485
 
@@ -478,7 +489,7 @@ _node_.**focus**()
478
489
 
479
490
  Focus this node.
480
491
 
481
- #### Open/Close Methods
492
+ ### Open/Close Methods
482
493
 
483
494
  _node_.**open**()
484
495
 
@@ -508,7 +519,7 @@ _node_.**reset**()
508
519
 
509
520
  Moves this node out of the editing state without submitting a new name.
510
521
 
511
- #### Event Handlers
522
+ ### Event Handlers
512
523
 
513
524
  _node_.**handleClick**(_event_)
514
525
 
@@ -518,7 +529,7 @@ Useful for using the standard selection methods when a node is clicked. If the m
518
529
 
519
530
  The tree api reference is stable across re-renders. It always has the most recent state and props.
520
531
 
521
- #### Node Accessors
532
+ ### Node Accessors
522
533
 
523
534
  _tree_.**get**(_id_) : _NodeApi | null_
524
535
 
@@ -556,7 +567,7 @@ _tree_.**prevNode** : _NodeApi | null_
556
567
 
557
568
  The node directly before the _focusedNode_ in the _visibleNodes_ array.
558
569
 
559
- #### Focus Methods
570
+ ### Focus Methods
560
571
 
561
572
  _tree_.**hasFocus** : _boolean_
562
573
 
@@ -578,7 +589,7 @@ _tree_.**pageDown**()
578
589
 
579
590
  Move focus down one page.
580
591
 
581
- #### Selection Methods
592
+ ### Selection Methods
582
593
 
583
594
  _tree_.**selectedIds** : _Set\<string\>_
584
595
 
@@ -588,6 +599,18 @@ _tree_.**selectedNodes** : _NodeApi[]_
588
599
 
589
600
  Returns an array of nodes that are selected.
590
601
 
602
+ _tree_.**hasNoSelection** : boolean
603
+
604
+ Returns true if nothing is selected in the tree.
605
+
606
+ _tree_.**hasSingleSelection** : boolean
607
+
608
+ Returns true if there is only one selection.
609
+
610
+ _tree_.**hasMultipleSelections** : boolean
611
+
612
+ Returns true if there is more than one selection.
613
+
591
614
  _tree_.**isSelected**(_id_) : _boolean_
592
615
 
593
616
  Returns true if the node with _id_ is selected.
@@ -616,7 +639,7 @@ _tree_.**selectAll**()
616
639
 
617
640
  Select all nodes.
618
641
 
619
- #### Visibility
642
+ ### Visibility
620
643
 
621
644
  _tree_.**open**(_id_)
622
645
 
@@ -638,11 +661,19 @@ _tree_.**openSiblings**(_id_)
638
661
 
639
662
  Open all siblings of the node with _id_.
640
663
 
664
+ _tree_.**openAll**()
665
+
666
+ Open all internal nodes.
667
+
668
+ _tree_.**closeAll**()
669
+
670
+ Close all internal nodes.
671
+
641
672
  _tree_.**isOpen**(_id_) : _boolean_
642
673
 
643
674
  Returns true if the node with _id_ is open.
644
675
 
645
- #### Drag and Drop
676
+ ### Drag and Drop
646
677
 
647
678
  _tree_.**isDragging**(_id_) : _boolean_
648
679
 
@@ -652,13 +683,13 @@ _tree_.**willReceiveDrop**(_id_) : _boolean_
652
683
 
653
684
  Returns true if the node with _id_ is internal and is under the dragged node.
654
685
 
655
- #### Scrolling
686
+ ### Scrolling
656
687
 
657
688
  _tree_.**scrollTo**(_id_, _[align]_)
658
689
 
659
690
  Scroll to the node with _id_. If this node is not visible, this method will open all its parents. The align argument can be _"auto" | "smart" | "center" | "end" | "start"_.
660
691
 
661
- #### Properties
692
+ ### Properties
662
693
 
663
694
  _tree_.**isEditing** : _boolean_
664
695
 
@@ -1,2 +1,2 @@
1
1
  /// <reference types="react" />
2
- export declare function DropCursor(): JSX.Element | null;
2
+ export declare function Cursor(): JSX.Element | null;
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
- import { DropCursorProps } from "../types/renderers";
3
- export declare const DefaultCursor: React.NamedExoticComponent<DropCursorProps>;
2
+ import { CursorProps } from "../types/renderers";
3
+ export declare const DefaultCursor: React.NamedExoticComponent<CursorProps>;
package/dist/index.js CHANGED
@@ -72,6 +72,7 @@ $parcel$export($eb5355379510ac9b$exports, "isDecendent", () => $eb5355379510ac9b
72
72
  $parcel$export($eb5355379510ac9b$exports, "indexOf", () => $eb5355379510ac9b$export$305f7d4e9d4624f2);
73
73
  $parcel$export($eb5355379510ac9b$exports, "noop", () => $eb5355379510ac9b$export$8793edee2d425525);
74
74
  $parcel$export($eb5355379510ac9b$exports, "dfs", () => $eb5355379510ac9b$export$51b654aff22fc5a6);
75
+ $parcel$export($eb5355379510ac9b$exports, "walk", () => $eb5355379510ac9b$export$588732934346abbf);
75
76
  $parcel$export($eb5355379510ac9b$exports, "focusNextElement", () => $eb5355379510ac9b$export$3b0237e8566c8d65);
76
77
  $parcel$export($eb5355379510ac9b$exports, "focusPrevElement", () => $eb5355379510ac9b$export$33b47db07a82b2fb);
77
78
  $parcel$export($eb5355379510ac9b$exports, "access", () => $eb5355379510ac9b$export$9bb0e144ba4929ca);
@@ -80,6 +81,8 @@ $parcel$export($eb5355379510ac9b$exports, "identify", () => $eb5355379510ac9b$ex
80
81
  $parcel$export($eb5355379510ac9b$exports, "mergeRefs", () => $eb5355379510ac9b$export$c9058316764c140e);
81
82
  $parcel$export($eb5355379510ac9b$exports, "safeRun", () => $eb5355379510ac9b$export$c6d63370cef03886);
82
83
  $parcel$export($eb5355379510ac9b$exports, "waitFor", () => $eb5355379510ac9b$export$9bbfceb27f687c1b);
84
+ $parcel$export($eb5355379510ac9b$exports, "getInsertIndex", () => $eb5355379510ac9b$export$e12bf2314d0bc2a9);
85
+ $parcel$export($eb5355379510ac9b$exports, "getInsertParentId", () => $eb5355379510ac9b$export$58fe32731f07ed56);
83
86
  function $eb5355379510ac9b$export$adf7c0fe6059d774(n, min, max) {
84
87
  return Math.max(Math.min(n, max), min);
85
88
  }
@@ -111,6 +114,10 @@ function $eb5355379510ac9b$export$51b654aff22fc5a6(node, id) {
111
114
  }
112
115
  return null;
113
116
  }
117
+ function $eb5355379510ac9b$export$588732934346abbf(node, fn) {
118
+ fn(node);
119
+ if (node.children) for (let child of node.children)$eb5355379510ac9b$export$588732934346abbf(child, fn);
120
+ }
114
121
  function $eb5355379510ac9b$export$3b0237e8566c8d65(target) {
115
122
  const elements = $eb5355379510ac9b$var$getFocusable(target);
116
123
  let next;
@@ -183,6 +190,20 @@ function $eb5355379510ac9b$export$9bbfceb27f687c1b(fn) {
183
190
  check();
184
191
  });
185
192
  }
193
+ function $eb5355379510ac9b$export$e12bf2314d0bc2a9(tree) {
194
+ const focus = tree.focusedNode;
195
+ if (!focus) return tree.root.children?.length ?? 0;
196
+ if (focus.isOpen) return 0;
197
+ if (focus.parent) return focus.childIndex + 1;
198
+ return 0;
199
+ }
200
+ function $eb5355379510ac9b$export$58fe32731f07ed56(tree) {
201
+ const focus = tree.focusedNode;
202
+ if (!focus) return null;
203
+ if (focus.isOpen) return focus.id;
204
+ if (focus.parent) return focus.parent.id;
205
+ return null;
206
+ }
186
207
 
187
208
 
188
209
 
@@ -368,12 +389,18 @@ class $9b37fe5960a1a3c6$export$d4b903da0f522dc8 {
368
389
  get isOpen() {
369
390
  return this.isLeaf ? false : this.tree.isOpen(this.id);
370
391
  }
392
+ get isClosed() {
393
+ return this.isLeaf ? false : !this.tree.isOpen(this.id);
394
+ }
371
395
  get isEditing() {
372
396
  return this.tree.editingId === this.id;
373
397
  }
374
398
  get isSelected() {
375
399
  return this.tree.isSelected(this.id);
376
400
  }
401
+ get isOnlySelection() {
402
+ return this.isSelected && this.tree.hasOneSelection;
403
+ }
377
404
  get isSelectedStart() {
378
405
  return this.isSelected && !this.prev?.isSelected;
379
406
  }
@@ -391,13 +418,16 @@ class $9b37fe5960a1a3c6$export$d4b903da0f522dc8 {
391
418
  }
392
419
  get state() {
393
420
  return {
394
- isEditing: this.isEditing,
421
+ isClosed: this.isClosed,
395
422
  isDragging: this.isDragging,
396
- isSelected: this.isSelected,
397
- isSelectedStart: this.isSelectedStart,
398
- isSelectedEnd: this.isSelectedEnd,
423
+ isEditing: this.isEditing,
399
424
  isFocused: this.isFocused,
425
+ isInternal: this.isInternal,
426
+ isLeaf: this.isLeaf,
400
427
  isOpen: this.isOpen,
428
+ isSelected: this.isSelected,
429
+ isSelectedEnd: this.isSelectedEnd,
430
+ isSelectedStart: this.isSelectedStart,
401
431
  willReceiveDrop: this.willReceiveDrop
402
432
  };
403
433
  }
@@ -833,7 +863,7 @@ const $6e3db8c23c41dfc9$var$PreviewNode = /*#__PURE__*/ (0, $foSVk$react.memo)(f
833
863
 
834
864
 
835
865
 
836
- function $e527b4e3d64e6932$export$ef961593063b03e8() {
866
+ function $e527b4e3d64e6932$export$b6a79797ad180576() {
837
867
  const tree = (0, $d5cb84d44d1b8acc$export$367b0f2231a90ba0)();
838
868
  const state = (0, $d5cb84d44d1b8acc$export$4930f6bf413be70e)();
839
869
  const cursor = state.cursor;
@@ -876,10 +906,7 @@ const $0e2adc7837d85ac3$var$DropContainer = ()=>{
876
906
  left: "0",
877
907
  right: "0"
878
908
  },
879
- onClick: (e)=>{
880
- console.log(e.currentTarget, e.target);
881
- },
882
- children: /*#__PURE__*/ (0, $foSVk$reactjsxruntime.jsx)((0, $e527b4e3d64e6932$export$ef961593063b03e8), {})
909
+ children: /*#__PURE__*/ (0, $foSVk$reactjsxruntime.jsx)((0, $e527b4e3d64e6932$export$b6a79797ad180576), {})
883
910
  });
884
911
  };
885
912
 
@@ -1228,7 +1255,8 @@ const $37e3f46f8fd1101f$export$a9754b3c8daa5172 = /*#__PURE__*/ (0, ($parcel$int
1228
1255
  "aria-level": node.level,
1229
1256
  "aria-selected": node.isSelected,
1230
1257
  style: rowStyle,
1231
- tabIndex: -1
1258
+ tabIndex: -1,
1259
+ className: tree.props.rowClassName
1232
1260
  };
1233
1261
  (0, $foSVk$react.useEffect)(()=>{
1234
1262
  if (!node.isEditing && node.isFocused) el.current?.focus();
@@ -1530,16 +1558,16 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1530
1558
  return this.state.nodes.open.unfiltered;
1531
1559
  }
1532
1560
  /* Tree Props */ get width() {
1533
- return this.props.width || 300;
1561
+ return this.props.width ?? 300;
1534
1562
  }
1535
1563
  get height() {
1536
- return this.props.height || 500;
1564
+ return this.props.height ?? 500;
1537
1565
  }
1538
1566
  get indent() {
1539
- return this.props.indent || 24;
1567
+ return this.props.indent ?? 24;
1540
1568
  }
1541
1569
  get rowHeight() {
1542
- return this.props.rowHeight || 24;
1570
+ return this.props.rowHeight ?? 24;
1543
1571
  }
1544
1572
  get searchTerm() {
1545
1573
  return (this.props.searchTerm || "").trim();
@@ -1609,31 +1637,20 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1609
1637
  return this.state.nodes.edit.id;
1610
1638
  }
1611
1639
  createInternal() {
1612
- return this.create("internal");
1640
+ return this.create({
1641
+ type: "internal"
1642
+ });
1613
1643
  }
1614
1644
  createLeaf() {
1615
- return this.create("leaf");
1616
- }
1617
- async create(type) {
1618
- let index;
1619
- let parentId;
1620
- const focus = this.focusedNode;
1621
- if (focus && focus.parent) {
1622
- if (focus.isInternal && focus.isOpen) {
1623
- parentId = focus.id;
1624
- index = 0;
1625
- } else {
1626
- index = focus.childIndex + 1;
1627
- parentId = focus.parent.isRoot ? null : focus.parent.id;
1628
- }
1629
- } else {
1630
- index = this.root?.children?.length || -1;
1631
- parentId = null;
1632
- }
1645
+ return this.create({
1646
+ type: "leaf"
1647
+ });
1648
+ }
1649
+ async create(opts = {}) {
1633
1650
  const data = await $5c74fef433be2b0a$var$safeRun(this.props.onCreate, {
1634
- parentId: parentId,
1635
- index: index,
1636
- type: type
1651
+ type: opts.type ?? "leaf",
1652
+ parentId: opts.parentId === undefined ? $eb5355379510ac9b$exports.getInsertParentId(this) : opts.parentId,
1653
+ index: opts.index ?? $eb5355379510ac9b$exports.getInsertIndex(this)
1637
1654
  });
1638
1655
  if (data) {
1639
1656
  this.focus(data);
@@ -1716,6 +1733,7 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1716
1733
  else {
1717
1734
  this.dispatch((0, $61ef7f2c3c9633e7$export$d7ddd398f22d79ef)($5c74fef433be2b0a$var$identify(node)));
1718
1735
  if (opts.scroll !== false) this.scrollTo(node);
1736
+ if (this.focusedNode) $5c74fef433be2b0a$var$safeRun(this.props.onFocus, this.focusedNode);
1719
1737
  }
1720
1738
  }
1721
1739
  pageUp() {
@@ -1744,6 +1762,7 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1744
1762
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).anchor(id));
1745
1763
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).mostRecent(id));
1746
1764
  this.scrollTo(id, opts.align);
1765
+ if (this.focusedNode) $5c74fef433be2b0a$var$safeRun(this.props.onFocus, this.focusedNode);
1747
1766
  $5c74fef433be2b0a$var$safeRun(this.props.onSelect, this.selectedNodes);
1748
1767
  }
1749
1768
  deselect(node) {
@@ -1759,6 +1778,7 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1759
1778
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).anchor(node.id));
1760
1779
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).mostRecent(node.id));
1761
1780
  this.scrollTo(node);
1781
+ if (this.focusedNode) $5c74fef433be2b0a$var$safeRun(this.props.onFocus, this.focusedNode);
1762
1782
  $5c74fef433be2b0a$var$safeRun(this.props.onSelect, this.selectedNodes);
1763
1783
  }
1764
1784
  selectContiguous(identity) {
@@ -1770,6 +1790,7 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1770
1790
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).add(this.nodesBetween(anchor, $5c74fef433be2b0a$var$identifyNull(id))));
1771
1791
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).mostRecent(id));
1772
1792
  this.scrollTo(id);
1793
+ if (this.focusedNode) $5c74fef433be2b0a$var$safeRun(this.props.onFocus, this.focusedNode);
1773
1794
  $5c74fef433be2b0a$var$safeRun(this.props.onSelect, this.selectedNodes);
1774
1795
  }
1775
1796
  deselectAll() {
@@ -1783,6 +1804,7 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1783
1804
  this.dispatch((0, $61ef7f2c3c9633e7$export$d7ddd398f22d79ef)(this.lastNode?.id));
1784
1805
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).anchor(this.firstNode));
1785
1806
  this.dispatch((0, $58f9381615aa3d17$export$e324594224ef24da).mostRecent(this.lastNode));
1807
+ if (this.focusedNode) $5c74fef433be2b0a$var$safeRun(this.props.onFocus, this.focusedNode);
1786
1808
  $5c74fef433be2b0a$var$safeRun(this.props.onSelect, this.selectedNodes);
1787
1809
  }
1788
1810
  /* Drag and Drop */ get cursorParentId() {
@@ -1808,12 +1830,16 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1808
1830
  /* Visibility */ open(identity) {
1809
1831
  const id = $5c74fef433be2b0a$var$identifyNull(identity);
1810
1832
  if (!id) return;
1833
+ if (this.isOpen(id)) return;
1811
1834
  this.dispatch((0, $d519ceb3313d9d0e$export$e324594224ef24da).open(id, this.isFiltered));
1835
+ $5c74fef433be2b0a$var$safeRun(this.props.onToggle, id);
1812
1836
  }
1813
1837
  close(identity) {
1814
1838
  const id = $5c74fef433be2b0a$var$identifyNull(identity);
1815
1839
  if (!id) return;
1840
+ if (!this.isOpen(id)) return;
1816
1841
  this.dispatch((0, $d519ceb3313d9d0e$export$e324594224ef24da).close(id, this.isFiltered));
1842
+ $5c74fef433be2b0a$var$safeRun(this.props.onToggle, id);
1817
1843
  }
1818
1844
  toggle(identity) {
1819
1845
  const id = $5c74fef433be2b0a$var$identifyNull(identity);
@@ -1839,6 +1865,16 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1839
1865
  this.scrollTo(this.focusedNode);
1840
1866
  }
1841
1867
  }
1868
+ openAll() {
1869
+ $eb5355379510ac9b$exports.walk(this.root, (node)=>{
1870
+ if (node.isInternal) node.open();
1871
+ });
1872
+ }
1873
+ closeAll() {
1874
+ $eb5355379510ac9b$exports.walk(this.root, (node)=>{
1875
+ if (node.isInternal) node.close();
1876
+ });
1877
+ }
1842
1878
  /* Scrolling */ scrollTo(identity, align = "smart") {
1843
1879
  if (!identity) return;
1844
1880
  const id = $5c74fef433be2b0a$var$identify(identity);
@@ -1860,6 +1896,15 @@ class $5c74fef433be2b0a$export$e2da3477247342d1 {
1860
1896
  get hasFocus() {
1861
1897
  return this.state.nodes.focus.treeFocused;
1862
1898
  }
1899
+ get hasNoSelection() {
1900
+ return this.state.nodes.selection.ids.size === 0;
1901
+ }
1902
+ get hasOneSelection() {
1903
+ return this.state.nodes.selection.ids.size === 1;
1904
+ }
1905
+ get hasMultipleSelections() {
1906
+ return this.state.nodes.selection.ids.size > 1;
1907
+ }
1863
1908
  isSelected(id) {
1864
1909
  if (!id) return false;
1865
1910
  return this.state.nodes.selection.ids.has(id);
@@ -2033,6 +2078,7 @@ function $9511ad6af37da13b$export$c49dab5eb1b4ce0c({ treeProps: treeProps , impe
2033
2078
 
2034
2079
 
2035
2080
 
2081
+
2036
2082
  function $6c0a9a91d5e7ff45$export$5a6c424b1725f44f() {
2037
2083
  const tree = (0, $d5cb84d44d1b8acc$export$367b0f2231a90ba0)();
2038
2084
  // In case we drop an item at the bottom of the list
@@ -2042,9 +2088,28 @@ function $6c0a9a91d5e7ff45$export$5a6c424b1725f44f() {
2042
2088
  if (!m.isOver({
2043
2089
  shallow: true
2044
2090
  })) return;
2091
+ if (m.canDrop()) {
2092
+ const offset = m.getClientOffset();
2093
+ if (!tree.listEl.current || !offset) return;
2094
+ const { cursor: cursor } = (0, $462841de7cc5b715$export$f502ca02ebb85a1c)({
2095
+ element: tree.listEl.current,
2096
+ offset: offset,
2097
+ indent: tree.indent,
2098
+ node: null,
2099
+ prevNode: tree.visibleNodes[tree.visibleNodes.length - 1],
2100
+ nextNode: null
2101
+ });
2102
+ if (cursor) tree.showCursor(cursor);
2103
+ } else tree.hideCursor();
2104
+ },
2105
+ canDrop: (item, m)=>{
2106
+ if (!m.isOver({
2107
+ shallow: true
2108
+ })) return false;
2109
+ if (tree.isFiltered) return false;
2045
2110
  const offset = m.getClientOffset();
2046
- if (!tree.listEl.current || !offset) return;
2047
- const { cursor: cursor } = (0, $462841de7cc5b715$export$f502ca02ebb85a1c)({
2111
+ if (!tree.listEl.current || !offset) return false;
2112
+ const { drop: drop } = (0, $462841de7cc5b715$export$f502ca02ebb85a1c)({
2048
2113
  element: tree.listEl.current,
2049
2114
  offset: offset,
2050
2115
  indent: tree.indent,
@@ -2052,12 +2117,15 @@ function $6c0a9a91d5e7ff45$export$5a6c424b1725f44f() {
2052
2117
  prevNode: tree.visibleNodes[tree.visibleNodes.length - 1],
2053
2118
  nextNode: null
2054
2119
  });
2055
- if (cursor) tree.showCursor(cursor);
2056
- },
2057
- canDrop: (item, m)=>{
2058
- return m.isOver({
2059
- shallow: true
2060
- });
2120
+ if (!drop) return false;
2121
+ const dropParent = tree.get(drop.parentId) ?? tree.root;
2122
+ for (let id of item.dragIds){
2123
+ const drag = tree.get(id);
2124
+ if (!drag) return false;
2125
+ if (!dropParent) return false;
2126
+ if (drag.isInternal && (0, $eb5355379510ac9b$export$1e38f72c6c546f70)(dropParent, drag)) return false;
2127
+ }
2128
+ return true;
2061
2129
  },
2062
2130
  drop: (item, m)=>{
2063
2131
  if (m.didDrop()) return;