@plannotator/ui 0.49.0 → 0.50.0

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.
@@ -0,0 +1,92 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import {
3
+ getAllFolderPaths,
4
+ getAncestorPaths,
5
+ type DiffFileTreeFile,
6
+ type DiffFileTreeNode,
7
+ } from '../utils/diffFileTree';
8
+
9
+ /** Which folders start open: every folder (the review's behavior), none, or
10
+ * an explicit list of folder paths (`DiffFileTreeNode.path`). */
11
+ export type DiffFileTreeDefaultExpanded = 'all' | 'none' | readonly string[];
12
+
13
+ function initialSet(allFolderPaths: string[], defaultExpanded: DiffFileTreeDefaultExpanded): Set<string> {
14
+ if (defaultExpanded === 'all') return new Set(allFolderPaths);
15
+ if (defaultExpanded === 'none') return new Set();
16
+ return new Set(defaultExpanded);
17
+ }
18
+
19
+ /**
20
+ * Folder open/closed state for a diff file tree, shared by the review's
21
+ * FileTree and the embeddable DiffFileTree:
22
+ * - starts from `defaultExpanded` and resets to it whenever `tree` changes
23
+ * identity (a new diff), so pass a memoized tree;
24
+ * - keeps every ancestor of `activePath` open, so moving the selection always
25
+ * reveals the selected file.
26
+ */
27
+ export function useDiffFileTreeExpansion<F extends DiffFileTreeFile>(
28
+ tree: DiffFileTreeNode<F>[],
29
+ activePath: string | null | undefined,
30
+ defaultExpanded: DiffFileTreeDefaultExpanded = 'all',
31
+ ) {
32
+ const allFolderPaths = useMemo(() => getAllFolderPaths(tree), [tree]);
33
+ const [expandedFolders, setExpandedFolders] = useState<Set<string>>(() => initialSet(allFolderPaths, defaultExpanded));
34
+ const [prevTree, setPrevTree] = useState(tree);
35
+
36
+ // Reset when the tree changes (initial render + diff switch).
37
+ if (tree !== prevTree) {
38
+ setPrevTree(tree);
39
+ setExpandedFolders(initialSet(allFolderPaths, defaultExpanded));
40
+ }
41
+
42
+ // Auto-expand ancestors of the active file so keyboard nav always reveals the target.
43
+ useEffect(() => {
44
+ if (activePath) {
45
+ const ancestors = getAncestorPaths(activePath);
46
+ setExpandedFolders((prev) => {
47
+ const missing = ancestors.filter((p) => !prev.has(p));
48
+ if (missing.length === 0) return prev;
49
+ const next = new Set(prev);
50
+ for (const p of missing) next.add(p);
51
+ return next;
52
+ });
53
+ }
54
+ }, [activePath, tree]);
55
+
56
+ const toggleFolder = useCallback((path: string) => {
57
+ setExpandedFolders((prev) => {
58
+ const next = new Set(prev);
59
+ if (next.has(path)) {
60
+ next.delete(path);
61
+ } else {
62
+ next.add(path);
63
+ }
64
+ return next;
65
+ });
66
+ }, []);
67
+
68
+ const setFolderExpanded = useCallback((path: string, expanded: boolean) => {
69
+ setExpandedFolders((prev) => {
70
+ if (prev.has(path) === expanded) return prev;
71
+ const next = new Set(prev);
72
+ if (expanded) next.add(path);
73
+ else next.delete(path);
74
+ return next;
75
+ });
76
+ }, []);
77
+
78
+ const areAllFoldersExpanded = allFolderPaths.length > 0 && allFolderPaths.every((path) => expandedFolders.has(path));
79
+
80
+ const toggleAllFolders = useCallback(() => {
81
+ setExpandedFolders(areAllFoldersExpanded ? new Set() : new Set(allFolderPaths));
82
+ }, [allFolderPaths, areAllFoldersExpanded]);
83
+
84
+ return {
85
+ expandedFolders,
86
+ allFolderPaths,
87
+ areAllFoldersExpanded,
88
+ toggleFolder,
89
+ setFolderExpanded,
90
+ toggleAllFolders,
91
+ };
92
+ }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@plannotator/ui",
3
- "version": "0.49.0",
3
+ "version": "0.50.0",
4
+ "license": "Apache-2.0",
4
5
  "type": "module",
5
6
  "exports": {
6
7
  "./components/*": "./components/*.tsx",
@@ -76,7 +77,7 @@
76
77
  "@lezer/highlight": "^1.2.3",
77
78
  "@pierre/diffs": "1.3.6",
78
79
  "@plannotator/atomic-editor": "^0.9.0",
79
- "@plannotator/core": "0.25.9",
80
+ "@plannotator/core": "0.25.10",
80
81
  "@plannotator/markdown-editor": "^0.5.0",
81
82
  "@plannotator/web-highlighter": "^0.8.1",
82
83
  "@tanstack/react-table": "^8.21.3",