@powerduck/tree 0.7.3

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,213 @@
1
+ import { ReactNode } from 'react';
2
+ import { T as TreeNode } from '../types-DVz8c2Yd.cjs';
3
+ import { ReorderResult } from '../core/index.cjs';
4
+
5
+ /**
6
+ * RFC 6902 JSON Patch operation.
7
+ */
8
+ interface JsonPatchOp {
9
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test";
10
+ path: (string | number)[];
11
+ value?: unknown;
12
+ from?: (string | number)[];
13
+ }
14
+ /**
15
+ * Context menu item definition.
16
+ */
17
+ interface ContextMenuItem<TMetadata = unknown> {
18
+ /** Display label. */
19
+ label: string;
20
+ /** Optional icon rendered before the label. */
21
+ icon?: ReactNode;
22
+ /** Click handler. */
23
+ onClick: (node: TreeNode<TMetadata>) => void;
24
+ /** Whether the item is disabled. */
25
+ disabled?: boolean;
26
+ /** Whether this is a danger action (red text). */
27
+ danger?: boolean;
28
+ /** Render a separator above this item. */
29
+ separator?: boolean;
30
+ /** Whether this item requires a two-step confirmation. First click arms it
31
+ * (label changes to confirmLabel), second click executes onClick. */
32
+ confirm?: boolean;
33
+ /** Label shown when the item is in confirm state. Default "Confirm?". */
34
+ confirmLabel?: string;
35
+ }
36
+ /**
37
+ * Render context passed to custom render functions.
38
+ */
39
+ interface TreeRenderContext<TMetadata = unknown> {
40
+ node: TreeNode<TMetadata>;
41
+ depth: number;
42
+ isExpanded: boolean;
43
+ isSelected: boolean;
44
+ isBranch: boolean;
45
+ isLeaf: boolean;
46
+ /** Whether this node is currently being dragged. */
47
+ isDragging: boolean;
48
+ /** Whether this node is the current drop target. */
49
+ isDragOver: boolean;
50
+ /** Drop position relative to this node. */
51
+ dragOverPosition: "before" | "after" | "child" | null;
52
+ }
53
+ /**
54
+ * Props for the Tree component.
55
+ */
56
+ interface TreeProps<TMetadata = unknown> {
57
+ /** Root nodes to render. */
58
+ nodes: TreeNode<TMetadata>[];
59
+ /** Called when a leaf node is selected (clicked). */
60
+ onSelect?: (node: TreeNode<TMetadata>) => void;
61
+ /** Called when expanded nodes change. */
62
+ onExpandedChange?: (expandedIds: string[]) => void;
63
+ /** Initially expanded node IDs. Overrides defaultExpandDepth. */
64
+ defaultExpandedIds?: string[];
65
+ /** Default expansion depth. 1 = root only, 2 = root + children, etc. Default 1. */
66
+ defaultExpandDepth?: number;
67
+ /** Enable search input. Default false. */
68
+ searchable?: boolean;
69
+ /** Placeholder text for the search input. Default "Search...". */
70
+ searchPlaceholder?: string;
71
+ /** Show expand/collapse all buttons in the toolbar. Default false. */
72
+ showExpandAll?: boolean;
73
+ /** Show refresh button in the toolbar. When clicked, calls onRefresh. Default false. */
74
+ showRefresh?: boolean;
75
+ /** Called when the refresh button is clicked. Use to reload/rebuild the tree data. */
76
+ onRefresh?: () => void;
77
+ /** Custom toolbar content rendered above the tree. */
78
+ toolbar?: ReactNode;
79
+ /** Extra content rendered inside the search row, between the search input and action buttons. */
80
+ searchRowExtra?: ReactNode;
81
+ /** Custom node renderer. Overrides all default rendering. */
82
+ renderNode?: (context: TreeRenderContext<TMetadata>, defaultNode: ReactNode) => ReactNode;
83
+ /** Custom icon renderer. */
84
+ renderIcon?: (context: TreeRenderContext<TMetadata>) => ReactNode;
85
+ /** Custom label renderer. */
86
+ renderLabel?: (context: TreeRenderContext<TMetadata>) => ReactNode;
87
+ /** Custom suffix renderer (rendered after the label, e.g. badges). */
88
+ renderSuffix?: (context: TreeRenderContext<TMetadata>) => ReactNode;
89
+ /** Additional CSS class name. */
90
+ className?: string;
91
+ /** Inline styles. */
92
+ style?: React.CSSProperties;
93
+ /** Size variant. Default "sm". */
94
+ size?: "xs" | "sm" | "md";
95
+ /** Visual variant for different use cases. Default "default".
96
+ * - "api": API debug tree with method badges and drag handles
97
+ * - "schema": Schema/JSON Schema navigation tree
98
+ * - "doc": Stripe-style documentation tree with section headers
99
+ */
100
+ variant?: "default" | "api" | "schema" | "doc";
101
+ /** Whether to show indent guides. Default true. */
102
+ showIndentGuides?: boolean;
103
+ /** Maximum height before scrolling. Default undefined (no limit). */
104
+ maxHeight?: number | string;
105
+ /** Callback ref for the root DOM element. */
106
+ rootRef?: React.Ref<HTMLDivElement>;
107
+ /** Enable drag and drop reordering. Default false. */
108
+ draggable?: boolean;
109
+ /** Metadata key for drag group isolation. When set, nodes with different
110
+ * group values cannot be dragged into each other's sections. */
111
+ dragGroupKey?: string;
112
+ /** Called when a node is reordered via drag and drop. */
113
+ onReorder?: (result: ReorderResult<TMetadata>) => void;
114
+ /** Called when a node is moved to a different parent via drag and drop. */
115
+ onMove?: (nodes: TreeNode<TMetadata>[], movedNode: TreeNode<TMetadata>, targetParentId: string | null) => void;
116
+ /** Predicate to control which nodes can be dragged. Default all nodes draggable. */
117
+ canDrag?: (node: TreeNode<TMetadata>) => boolean;
118
+ /** Predicate to control whether a drop is allowed at the target. Default all drops allowed. */
119
+ canDrop?: (draggedNode: TreeNode<TMetadata>, targetNode: TreeNode<TMetadata>, position: "before" | "after" | "child") => boolean;
120
+ /**
121
+ * Context menu items for right-click and the more (…) button.
122
+ * Receives the node and returns an array of menu items.
123
+ * When provided, a more button appears on row hover and right-click opens the menu.
124
+ */
125
+ contextMenuItems?: (node: TreeNode<TMetadata>) => ContextMenuItem<TMetadata>[];
126
+ /**
127
+ * Called when a mutation (reorder, move, delete via context menu) produces JSON Patch operations.
128
+ * Only fires when the affected node has a `jsonPath` in its metadata.
129
+ * Use with @powerduck/conf-patch `patchContent` to apply to the original document.
130
+ */
131
+ onPatch?: (ops: JsonPatchOp[], context: {
132
+ node: TreeNode<TMetadata>;
133
+ type: "reorder" | "move" | "remove";
134
+ }) => void;
135
+ }
136
+ /**
137
+ * Handle exposed by the Tree component via ref.
138
+ */
139
+ interface TreeHandle {
140
+ /** Expand all nodes. */
141
+ expandAll: () => void;
142
+ /** Collapse all nodes. */
143
+ collapseAll: () => void;
144
+ /** Expand nodes to a specific depth. */
145
+ expandToDepth: (depth: number) => void;
146
+ /** Get the currently expanded node IDs. */
147
+ getExpandedIds: () => string[];
148
+ /** Get the currently selected node. */
149
+ getSelectedNode: () => TreeNode | undefined;
150
+ /** Scroll a node into view by ID. */
151
+ scrollToNode: (id: string) => void;
152
+ /** Find a node by predicate, expand its ancestors, select it, and scroll into view. Returns the found node or undefined. */
153
+ locateNode: (predicate: (node: TreeNode) => boolean) => TreeNode | undefined;
154
+ }
155
+
156
+ declare const Tree: <TMetadata = unknown>(props: TreeProps<TMetadata> & {
157
+ ref?: React.Ref<TreeHandle>;
158
+ }) => React.ReactElement;
159
+
160
+ /**
161
+ * Manages tree search state with deferred query for performance.
162
+ *
163
+ * When searching, the expansion state is temporarily overridden to show
164
+ * all matching nodes and their ancestors. When the search is cleared,
165
+ * the previous expansion state is restored.
166
+ */
167
+ declare function useTreeSearch<TMetadata>(nodes: TreeNode<TMetadata>[]): {
168
+ query: string;
169
+ deferredQuery: string;
170
+ isSearching: boolean;
171
+ filteredNodes: TreeNode<TMetadata>[];
172
+ expandedBeforeSearch: string[] | null;
173
+ handleQueryChange: (value: string, currentExpanded: string[]) => void;
174
+ clearSearch: () => void;
175
+ };
176
+
177
+ /**
178
+ * Manages tree expansion state.
179
+ *
180
+ * Supports controlled (via onExpandedChange) and uncontrolled usage.
181
+ * Provides expandAll, collapseAll, and expandToDepth helpers.
182
+ */
183
+ declare function useTreeExpansion<TMetadata>(nodes: TreeNode<TMetadata>[], options?: {
184
+ defaultExpandedIds?: string[];
185
+ defaultExpandDepth?: number;
186
+ onExpandedChange?: (expandedIds: string[]) => void;
187
+ }): {
188
+ expandedIds: string[];
189
+ setExpandedIds: (nextExpanded: string[]) => void;
190
+ toggleNode: (id: string) => void;
191
+ expandAll: () => void;
192
+ collapseAll: () => void;
193
+ expandToDepth: (depth: number) => void;
194
+ isAllExpanded: boolean;
195
+ allBranchIds: string[];
196
+ setNodeElementRef: (id: string, element: HTMLElement | null) => void;
197
+ scrollToNode: (id: string) => void;
198
+ };
199
+
200
+ /**
201
+ * HTTP method display labels for compact badge rendering.
202
+ *
203
+ * Longer methods are abbreviated to fit the fixed-width badge.
204
+ * Exported so consumer libraries can reuse the same mapping.
205
+ */
206
+ declare const METHOD_LABEL_MAP: Record<string, string>;
207
+ /**
208
+ * Returns the compact display label for an HTTP method.
209
+ * Falls back to the first 4 characters uppercased for unknown methods.
210
+ */
211
+ declare function getMethodLabel(method: string): string;
212
+
213
+ export { type ContextMenuItem, type JsonPatchOp, METHOD_LABEL_MAP, Tree, type TreeHandle, type TreeProps, type TreeRenderContext, getMethodLabel, useTreeExpansion, useTreeSearch };
@@ -0,0 +1,213 @@
1
+ import { ReactNode } from 'react';
2
+ import { T as TreeNode } from '../types-DVz8c2Yd.js';
3
+ import { ReorderResult } from '../core/index.js';
4
+
5
+ /**
6
+ * RFC 6902 JSON Patch operation.
7
+ */
8
+ interface JsonPatchOp {
9
+ op: "add" | "remove" | "replace" | "move" | "copy" | "test";
10
+ path: (string | number)[];
11
+ value?: unknown;
12
+ from?: (string | number)[];
13
+ }
14
+ /**
15
+ * Context menu item definition.
16
+ */
17
+ interface ContextMenuItem<TMetadata = unknown> {
18
+ /** Display label. */
19
+ label: string;
20
+ /** Optional icon rendered before the label. */
21
+ icon?: ReactNode;
22
+ /** Click handler. */
23
+ onClick: (node: TreeNode<TMetadata>) => void;
24
+ /** Whether the item is disabled. */
25
+ disabled?: boolean;
26
+ /** Whether this is a danger action (red text). */
27
+ danger?: boolean;
28
+ /** Render a separator above this item. */
29
+ separator?: boolean;
30
+ /** Whether this item requires a two-step confirmation. First click arms it
31
+ * (label changes to confirmLabel), second click executes onClick. */
32
+ confirm?: boolean;
33
+ /** Label shown when the item is in confirm state. Default "Confirm?". */
34
+ confirmLabel?: string;
35
+ }
36
+ /**
37
+ * Render context passed to custom render functions.
38
+ */
39
+ interface TreeRenderContext<TMetadata = unknown> {
40
+ node: TreeNode<TMetadata>;
41
+ depth: number;
42
+ isExpanded: boolean;
43
+ isSelected: boolean;
44
+ isBranch: boolean;
45
+ isLeaf: boolean;
46
+ /** Whether this node is currently being dragged. */
47
+ isDragging: boolean;
48
+ /** Whether this node is the current drop target. */
49
+ isDragOver: boolean;
50
+ /** Drop position relative to this node. */
51
+ dragOverPosition: "before" | "after" | "child" | null;
52
+ }
53
+ /**
54
+ * Props for the Tree component.
55
+ */
56
+ interface TreeProps<TMetadata = unknown> {
57
+ /** Root nodes to render. */
58
+ nodes: TreeNode<TMetadata>[];
59
+ /** Called when a leaf node is selected (clicked). */
60
+ onSelect?: (node: TreeNode<TMetadata>) => void;
61
+ /** Called when expanded nodes change. */
62
+ onExpandedChange?: (expandedIds: string[]) => void;
63
+ /** Initially expanded node IDs. Overrides defaultExpandDepth. */
64
+ defaultExpandedIds?: string[];
65
+ /** Default expansion depth. 1 = root only, 2 = root + children, etc. Default 1. */
66
+ defaultExpandDepth?: number;
67
+ /** Enable search input. Default false. */
68
+ searchable?: boolean;
69
+ /** Placeholder text for the search input. Default "Search...". */
70
+ searchPlaceholder?: string;
71
+ /** Show expand/collapse all buttons in the toolbar. Default false. */
72
+ showExpandAll?: boolean;
73
+ /** Show refresh button in the toolbar. When clicked, calls onRefresh. Default false. */
74
+ showRefresh?: boolean;
75
+ /** Called when the refresh button is clicked. Use to reload/rebuild the tree data. */
76
+ onRefresh?: () => void;
77
+ /** Custom toolbar content rendered above the tree. */
78
+ toolbar?: ReactNode;
79
+ /** Extra content rendered inside the search row, between the search input and action buttons. */
80
+ searchRowExtra?: ReactNode;
81
+ /** Custom node renderer. Overrides all default rendering. */
82
+ renderNode?: (context: TreeRenderContext<TMetadata>, defaultNode: ReactNode) => ReactNode;
83
+ /** Custom icon renderer. */
84
+ renderIcon?: (context: TreeRenderContext<TMetadata>) => ReactNode;
85
+ /** Custom label renderer. */
86
+ renderLabel?: (context: TreeRenderContext<TMetadata>) => ReactNode;
87
+ /** Custom suffix renderer (rendered after the label, e.g. badges). */
88
+ renderSuffix?: (context: TreeRenderContext<TMetadata>) => ReactNode;
89
+ /** Additional CSS class name. */
90
+ className?: string;
91
+ /** Inline styles. */
92
+ style?: React.CSSProperties;
93
+ /** Size variant. Default "sm". */
94
+ size?: "xs" | "sm" | "md";
95
+ /** Visual variant for different use cases. Default "default".
96
+ * - "api": API debug tree with method badges and drag handles
97
+ * - "schema": Schema/JSON Schema navigation tree
98
+ * - "doc": Stripe-style documentation tree with section headers
99
+ */
100
+ variant?: "default" | "api" | "schema" | "doc";
101
+ /** Whether to show indent guides. Default true. */
102
+ showIndentGuides?: boolean;
103
+ /** Maximum height before scrolling. Default undefined (no limit). */
104
+ maxHeight?: number | string;
105
+ /** Callback ref for the root DOM element. */
106
+ rootRef?: React.Ref<HTMLDivElement>;
107
+ /** Enable drag and drop reordering. Default false. */
108
+ draggable?: boolean;
109
+ /** Metadata key for drag group isolation. When set, nodes with different
110
+ * group values cannot be dragged into each other's sections. */
111
+ dragGroupKey?: string;
112
+ /** Called when a node is reordered via drag and drop. */
113
+ onReorder?: (result: ReorderResult<TMetadata>) => void;
114
+ /** Called when a node is moved to a different parent via drag and drop. */
115
+ onMove?: (nodes: TreeNode<TMetadata>[], movedNode: TreeNode<TMetadata>, targetParentId: string | null) => void;
116
+ /** Predicate to control which nodes can be dragged. Default all nodes draggable. */
117
+ canDrag?: (node: TreeNode<TMetadata>) => boolean;
118
+ /** Predicate to control whether a drop is allowed at the target. Default all drops allowed. */
119
+ canDrop?: (draggedNode: TreeNode<TMetadata>, targetNode: TreeNode<TMetadata>, position: "before" | "after" | "child") => boolean;
120
+ /**
121
+ * Context menu items for right-click and the more (…) button.
122
+ * Receives the node and returns an array of menu items.
123
+ * When provided, a more button appears on row hover and right-click opens the menu.
124
+ */
125
+ contextMenuItems?: (node: TreeNode<TMetadata>) => ContextMenuItem<TMetadata>[];
126
+ /**
127
+ * Called when a mutation (reorder, move, delete via context menu) produces JSON Patch operations.
128
+ * Only fires when the affected node has a `jsonPath` in its metadata.
129
+ * Use with @powerduck/conf-patch `patchContent` to apply to the original document.
130
+ */
131
+ onPatch?: (ops: JsonPatchOp[], context: {
132
+ node: TreeNode<TMetadata>;
133
+ type: "reorder" | "move" | "remove";
134
+ }) => void;
135
+ }
136
+ /**
137
+ * Handle exposed by the Tree component via ref.
138
+ */
139
+ interface TreeHandle {
140
+ /** Expand all nodes. */
141
+ expandAll: () => void;
142
+ /** Collapse all nodes. */
143
+ collapseAll: () => void;
144
+ /** Expand nodes to a specific depth. */
145
+ expandToDepth: (depth: number) => void;
146
+ /** Get the currently expanded node IDs. */
147
+ getExpandedIds: () => string[];
148
+ /** Get the currently selected node. */
149
+ getSelectedNode: () => TreeNode | undefined;
150
+ /** Scroll a node into view by ID. */
151
+ scrollToNode: (id: string) => void;
152
+ /** Find a node by predicate, expand its ancestors, select it, and scroll into view. Returns the found node or undefined. */
153
+ locateNode: (predicate: (node: TreeNode) => boolean) => TreeNode | undefined;
154
+ }
155
+
156
+ declare const Tree: <TMetadata = unknown>(props: TreeProps<TMetadata> & {
157
+ ref?: React.Ref<TreeHandle>;
158
+ }) => React.ReactElement;
159
+
160
+ /**
161
+ * Manages tree search state with deferred query for performance.
162
+ *
163
+ * When searching, the expansion state is temporarily overridden to show
164
+ * all matching nodes and their ancestors. When the search is cleared,
165
+ * the previous expansion state is restored.
166
+ */
167
+ declare function useTreeSearch<TMetadata>(nodes: TreeNode<TMetadata>[]): {
168
+ query: string;
169
+ deferredQuery: string;
170
+ isSearching: boolean;
171
+ filteredNodes: TreeNode<TMetadata>[];
172
+ expandedBeforeSearch: string[] | null;
173
+ handleQueryChange: (value: string, currentExpanded: string[]) => void;
174
+ clearSearch: () => void;
175
+ };
176
+
177
+ /**
178
+ * Manages tree expansion state.
179
+ *
180
+ * Supports controlled (via onExpandedChange) and uncontrolled usage.
181
+ * Provides expandAll, collapseAll, and expandToDepth helpers.
182
+ */
183
+ declare function useTreeExpansion<TMetadata>(nodes: TreeNode<TMetadata>[], options?: {
184
+ defaultExpandedIds?: string[];
185
+ defaultExpandDepth?: number;
186
+ onExpandedChange?: (expandedIds: string[]) => void;
187
+ }): {
188
+ expandedIds: string[];
189
+ setExpandedIds: (nextExpanded: string[]) => void;
190
+ toggleNode: (id: string) => void;
191
+ expandAll: () => void;
192
+ collapseAll: () => void;
193
+ expandToDepth: (depth: number) => void;
194
+ isAllExpanded: boolean;
195
+ allBranchIds: string[];
196
+ setNodeElementRef: (id: string, element: HTMLElement | null) => void;
197
+ scrollToNode: (id: string) => void;
198
+ };
199
+
200
+ /**
201
+ * HTTP method display labels for compact badge rendering.
202
+ *
203
+ * Longer methods are abbreviated to fit the fixed-width badge.
204
+ * Exported so consumer libraries can reuse the same mapping.
205
+ */
206
+ declare const METHOD_LABEL_MAP: Record<string, string>;
207
+ /**
208
+ * Returns the compact display label for an HTTP method.
209
+ * Falls back to the first 4 characters uppercased for unknown methods.
210
+ */
211
+ declare function getMethodLabel(method: string): string;
212
+
213
+ export { type ContextMenuItem, type JsonPatchOp, METHOD_LABEL_MAP, Tree, type TreeHandle, type TreeProps, type TreeRenderContext, getMethodLabel, useTreeExpansion, useTreeSearch };
@@ -0,0 +1 @@
1
+ import{filterTree as e,findPath as n,getBranchIds as t,getExpandableIds as r,moveNode as d,reorderNode as o}from"../chunk-5KF7QUTD.js";import{forwardRef as a,memo as i,useCallback as l,useEffect as s,useImperativeHandle as c,useMemo as u,useRef as p,useState as h}from"react";import{useCallback as g,useMemo as f,useRef as m,useState as x}from"react";function I(e,n={}){const{defaultExpandedIds:d,defaultExpandDepth:o=1,onExpandedChange:a}=n,i=f(()=>d&&d.length>0?[...d]:o<=1?[]:r(e,{maxDepth:o-1,onlyWithChildren:!0}),[]),[l,s]=x(i),c=m(new Map),u=f(()=>t(e),[e]),p=f(()=>u.length>0&&u.every(e=>l.includes(e)),[u,l]),h=g(e=>{s(e),a?.(e)},[a]),I=g(e=>{s(n=>{const t=n.includes(e)?n.filter(n=>n!==e):[...n,e];return a?.(t),t})},[a]),v=g(()=>{h([...u])},[u,h]),D=g(()=>{h([])},[h]),N=g(n=>{const t=r(e,{maxDepth:n,onlyWithChildren:!0});h(t)},[e,h]),b=g((e,n)=>{n?c.current.set(e,n):c.current.delete(e)},[]),S=g(e=>{const n=c.current.get(e);n&&n.scrollIntoView({behavior:"smooth",block:"nearest"})},[]);return{expandedIds:l,setExpandedIds:h,toggleNode:I,expandAll:v,collapseAll:D,expandToDepth:N,isAllExpanded:p,allBranchIds:u,setNodeElementRef:b,scrollToNode:S}}import{useCallback as v,useDeferredValue as D,useMemo as N,useState as b}from"react";function S(n){const[t,r]=b(""),d=D(t),[o,a]=b(null),i=d.trim().length>0,l=N(()=>i?e(n,{query:d,keepAncestors:!0}):n,[n,d,i]),s=v((e,n)=>{const d=t.trim(),o=e.trim();!d&&o&&a(n),d&&!o&&a(null),r(e)},[t]),c=v(()=>{r(""),a(null)},[]);return{query:t,deferredQuery:d,isSearching:i,filteredNodes:l,expandedBeforeSearch:o,handleQueryChange:s,clearSearch:c}}function C(e,n,t=[]){for(const r of e){if(r.id===n)return[...t,r];if(r.children?.length){const e=C(r.children,n,[...t,r]);if(e)return e}}return null}function y(e,n){const t=C(e,n);return t?t.slice(0,-1).map(e=>e.id):[]}var M={get:"GET",post:"POST",put:"PUT",delete:"DEL",patch:"PATCH",head:"HEAD",options:"OPT",trace:"TRA",connect:"CONN"};function E(e){const n=e.toLowerCase().trim();return M[n]??n.slice(0,4).toUpperCase()}import{LuBraces as w,LuChevronDown as B,LuChevronRight as O,LuEllipsisVertical as A,LuFolder as L,LuFolderOpen as P,LuGripVertical as R,LuList as k,LuRefreshCw as T,LuSearch as z,LuZap as G}from"react-icons/lu";import{MdOutlineUnfoldMore as $,MdUnfoldLess as q}from"react-icons/md";import{Fragment as H,jsx as Q,jsxs as j}from"react/jsx-runtime";var F={branchControl:"pde-tree-branchControl",contextMenu:"pde-tree-contextMenu",contextMenuItem:"pde-tree-contextMenuItem",contextMenuItemDanger:"pde-tree-contextMenuItemDanger",contextMenuItemConfirming:"pde-tree-contextMenuItemConfirming",contextMenuIcon:"pde-tree-contextMenuIcon",contextMenuSeparator:"pde-tree-contextMenuSeparator",deprecatedLabel:"pde-tree-deprecatedLabel",dragHandle:"pde-tree-dragHandle",dragHandleDisabled:"pde-tree-dragHandleDisabled",dropIndicatorAfter:"pde-tree-dropIndicatorAfter",dropIndicatorBefore:"pde-tree-dropIndicatorBefore",dropIndicatorChild:"pde-tree-dropIndicatorChild",emptyState:"pde-tree-emptyState",expandIcon:"pde-tree-expandIcon",expandIconExpanded:"pde-tree-expandIconExpanded",expandIconPlaceholder:"pde-tree-expandIconPlaceholder",highlight:"pde-tree-highlight",iconButton:"pde-tree-iconButton",indentGuide:"pde-tree-indentGuide",leafItem:"pde-tree-leafItem",methodBadge:"pde-tree-methodBadge",methodDelete:"pde-tree-methodDelete",methodGet:"pde-tree-methodGet",methodOther:"pde-tree-methodOther",methodPatch:"pde-tree-methodPatch",methodPost:"pde-tree-methodPost",methodPut:"pde-tree-methodPut",moreButton:"pde-tree-moreButton",moreButtonActive:"pde-tree-moreButtonActive",nodeDragging:"pde-tree-nodeDragging",nodeIcon:"pde-tree-nodeIcon",primitiveDot:"pde-tree-primitiveDot",nodeLabel:"pde-tree-nodeLabel",nodeLabelBranch:"pde-tree-nodeLabelBranch",nodeRow:"pde-tree-nodeRow",nodeRowSelected:"pde-tree-nodeRowSelected",nodeSuffix:"pde-tree-nodeSuffix",requiredDot:"pde-tree-requiredDot",root:"pde-tree-root",searchIcon:"pde-tree-searchIcon",searchInput:"pde-tree-searchInput",searchInputWrap:"pde-tree-searchInputWrap",searchRow:"pde-tree-searchRow",toolbar:"pde-tree-toolbar",treeContainer:"pde-tree-treeContainer"};function W({expanded:e}){return Q("span",{className:F.expandIcon,children:Q(e?B:O,{size:14})})}function K(){return Q(z,{size:14,"aria-hidden":"true"})}function U(){return Q(R,{size:14,"aria-hidden":"true"})}function Y(){return Q(A,{size:14,"aria-hidden":"true"})}function V({state:e,onClose:n}){const{x:t,y:r,items:d}=e,[o,a]=h(null);return Q("div",{className:F.contextMenu,style:{left:t,top:r},role:"menu",onMouseDown:e=>e.stopPropagation(),children:d.map((t,r)=>t.separator?Q("div",{className:F.contextMenuSeparator},`sep-${r}`):j("button",{type:"button",role:"menuitem",className:[F.contextMenuItem,t.danger?F.contextMenuItemDanger:"",o===r?F.contextMenuItemConfirming:""].filter(Boolean).join(" "),disabled:t.disabled,onClick:()=>((t,r)=>{t.confirm&&o!==r?a(r):(t.onClick(e.node),a(null),n())})(t,r),children:[t.icon&&Q("span",{className:F.contextMenuIcon,children:t.icon}),Q("span",{style:{flex:1,overflow:"hidden",textOverflow:"ellipsis"},children:t.confirm&&o===r?t.confirmLabel??"Confirm?":t.label})]},`${t.label}-${r}`))})}function X(e,n,t){const r=function(e){const n=e.metadata,t=n?.jsonPath;if(Array.isArray(t)&&t.length>0)return t}(e);if(!r||0===r.length)return[];const d=r.slice(0,-1);return[{op:"move",from:[...d,n],path:[...d,t]}]}function J({text:e,query:n}){if(!n)return Q(H,{children:e});const t=e.toLowerCase(),r=n.toLowerCase(),d=t.indexOf(r);return-1===d?Q(H,{children:e}):j(H,{children:[e.slice(0,d),Q("span",{className:F.highlight,children:e.slice(d,d+n.length)}),e.slice(d+n.length)]})}var Z={get:F.methodGet,post:F.methodPost,put:F.methodPut,patch:F.methodPatch,delete:F.methodDelete};function _({method:e}){const n=e.toLowerCase(),t=Z[n]??F.methodOther,r=E(e);return Q("span",{className:`${F.methodBadge} ${t}`,children:r})}var ee={draggedId:null,dragOverId:null,dragOverPosition:null};var ne=i(function(e){const{node:n,depth:t,expandedIds:r,selectedId:d,onToggle:o,onSelect:a,onNodeRef:i,searchQuery:s,showIndentGuides:c,renderIcon:u,renderLabel:p,renderSuffix:h,renderNode:g,draggable:f,dragState:m,canDragNode:x,canDragNodeFn:I,onDragStart:v,onDragOver:D,onDragLeave:N,onDrop:b,onDragEnd:S,showContextMenuButton:C,activeMenuNodeId:y,onContextMenu:M,onMoreClick:E}=e,B=r.includes(n.id),O=d===n.id,A=(n.children?.length??0)>0,R=A,T=!A,z=m.draggedId===n.id,$=m.dragOverId===n.id,q=$?m.dragOverPosition:null,H=n.metadata,K="string"==typeof H?.method?H.method:void 0,V=!0===H?.deprecated,X=!0===H?.required,Z="string"==typeof H?.kind?H.kind:void 0,ee={node:n,depth:t,isExpanded:B,isSelected:O,isBranch:R,isLeaf:T,isDragging:z,isDragOver:$,dragOverPosition:q},te=l(()=>{R?o(n.id):a(n)},[R,n,a,o]),re=l(e=>{"Enter"===e.key||" "===e.key?(e.preventDefault(),te()):("ArrowRight"===e.key&&R&&!B||"ArrowLeft"===e.key&&R&&B)&&(e.preventDefault(),o(n.id))},[te,R,B,n.id,o]),de=u?u(ee):K?null:Q("span",{className:F.nodeIcon,children:"section"===Z&&"components"===H?.section?Q(w,{size:14}):"section"===Z&&"webhooks"===H?.section?Q(G,{size:14}):"schema"===Z||"component"===Z||"object"===Z?Q(w,{size:14}):"array"===Z||"items"===Z?Q(k,{size:14}):R?Q(B?P:L,{size:14}):Q("span",{className:F.primitiveDot})}),oe=p?p(ee):Q("span",{className:`${F.nodeLabel} ${R?F.nodeLabelBranch:""} ${V?F.deprecatedLabel:""}`,children:Q(J,{text:n.name,query:s})}),ae=h?h(ee):null,ie=[F.nodeRow,R?F.branchControl:F.leafItem,O?F.nodeRowSelected:"",z?F.nodeDragging:"",$&&"before"===q?F.dropIndicatorBefore:"",$&&"after"===q?F.dropIndicatorAfter:"",$&&"child"===q?F.dropIndicatorChild:"",Z?`pde-tree-kind-${Z}`:""].filter(Boolean).join(" "),le=j("div",{ref:e=>i(n.id,e),className:ie,style:{paddingLeft:14*t+8+"px"},role:"treeitem","aria-expanded":R?B:void 0,"aria-selected":O,"aria-level":t,"aria-grabbed":f&&x?z:void 0,tabIndex:0,onClick:te,onKeyDown:re,onContextMenu:C?e=>M(n,e):void 0,onDragOver:f?e=>D(n,e):void 0,onDragLeave:f?()=>N(n):void 0,onDrop:f?e=>b(n,e):void 0,children:[c&&t>1&&Array.from({length:t-1},(e,n)=>Q("span",{className:F.indentGuide,style:{left:14*(n+1)+33+"px"}},`guide-${n}`)),f&&x&&Q("span",{className:F.dragHandle,draggable:!0,onDragStart:e=>v(n,e),onDragEnd:S,title:"Drag to reorder","aria-label":"Drag to reorder",children:Q(U,{})}),R?Q(W,{expanded:B}):Q("span",{className:F.expandIconPlaceholder}),de,K&&Q(_,{method:K}),oe,X&&Q("span",{className:F.requiredDot,title:"Required"}),Q("span",{className:F.nodeSuffix,children:ae}),C&&Q("button",{type:"button",className:[F.moreButton,y===n.id?F.moreButtonActive:""].filter(Boolean).join(" "),onClick:e=>E(n,e),title:"More actions","aria-label":"More actions",children:Q(Y,{})})]}),se=g?g(ee,le):le;return j("div",{role:"presentation",children:[se,R&&B&&n.children?.map(n=>Q(ne,{...e,node:n,depth:t+1,isExpanded:r.includes(n.id),isSelected:d===n.id,canDragNode:I(n)},n.id))]})},function(e,n){if(e.node!==n.node)return!1;if(e.depth!==n.depth)return!1;if(e.isExpanded!==n.isExpanded)return!1;if(e.isSelected!==n.isSelected)return!1;if(e.searchQuery!==n.searchQuery)return!1;if(e.showIndentGuides!==n.showIndentGuides)return!1;if(e.canDragNode!==n.canDragNode)return!1;if(e.draggable!==n.draggable)return!1;if(e.showContextMenuButton!==n.showContextMenuButton)return!1;if(e.activeMenuNodeId!==n.activeMenuNodeId)return!1;if((e.node.children?.length??0)>0){if(e.expandedIds!==n.expandedIds)return!1;if(e.selectedId!==n.selectedId)return!1;if(e.dragState!==n.dragState)return!1}if(e.dragState.draggedId===e.node.id!==(n.dragState.draggedId===n.node.id))return!1;const t=e.dragState.dragOverId===e.node.id,r=n.dragState.dragOverId===n.node.id;return t===r&&((!t||!r||e.dragState.dragOverPosition===n.dragState.dragOverPosition)&&(e.renderIcon===n.renderIcon&&(e.renderLabel===n.renderLabel&&(e.renderSuffix===n.renderSuffix&&(e.renderNode===n.renderNode&&(e.onToggle===n.onToggle&&(e.onSelect===n.onSelect&&(e.onNodeRef===n.onNodeRef&&(e.canDragNodeFn===n.canDragNodeFn&&(e.onDragStart===n.onDragStart&&(e.onDragOver===n.onDragOver&&(e.onDragLeave===n.onDragLeave&&(e.onDrop===n.onDrop&&(e.onDragEnd===n.onDragEnd&&(e.onContextMenu===n.onContextMenu&&e.onMoreClick===n.onMoreClick)))))))))))))))}),te=a(function(e,t){const{nodes:r,onSelect:a,onExpandedChange:i,defaultExpandedIds:g,defaultExpandDepth:f=1,searchable:m=!1,searchPlaceholder:x="Search...",showExpandAll:v=!1,showRefresh:D=!1,onRefresh:N,toolbar:b,searchRowExtra:C,renderNode:M,renderIcon:E,renderLabel:w,renderSuffix:B,className:O,style:A,size:L="sm",variant:P="default",showIndentGuides:R=!0,maxHeight:k,rootRef:z,draggable:G=!1,dragGroupKey:H,onReorder:W,onMove:U,canDrag:Y,canDrop:J,contextMenuItems:Z,onPatch:_}=e,[te,re]=h(null),[de,oe]=h(ee),[ae,ie]=h(null),le=p(null),se=I(r,{defaultExpandedIds:g,defaultExpandDepth:f,onExpandedChange:i}),ce=S(r),ue=ce.isSearching?se.allBranchIds:ce.expandedBeforeSearch??se.expandedIds,pe=l(e=>{re(e.id),a?.(e)},[a]),he=l(e=>{ce.handleQueryChange(e,se.expandedIds)},[se.expandedIds,ce]),ge=l(e=>{if(!G)return!1;const n=e.metadata;return"section"!==n?.kind&&(!Y||Y(e))},[Y,G]),fe=l((e,n)=>{ge(e)?(n.dataTransfer.effectAllowed="move",n.dataTransfer.setData("text/plain",e.id),oe({draggedId:e.id,dragOverId:null,dragOverPosition:null})):n.preventDefault()},[ge]),me=l((e,t)=>{if(!de.draggedId||de.draggedId===e.id)return;t.preventDefault(),t.dataTransfer.dropEffect="move";const d=t.currentTarget.getBoundingClientRect(),o=(t.clientY-d.top)/d.height,a=(e.children?.length??0)>0;let i;i=a?o<.25?"before":o>.75?"after":"child":o<.5?"before":"after";const l=de.draggedId?n(r,de.draggedId):null;if("child"!==i||!l||!l.ancestorIds.includes(e.id)){if(H&&l){const t=n(r,e.id);if(t){const e=e=>{for(let n=e.nodes.length-1;n>=0;n--){const t=e.nodes[n]?.metadata;if(t&&H in t)return t[H]}},n=e(l),r=e(t);if(void 0!==n&&void 0!==r&&n!==r)return}}if(J){const n=l?.target;if(!n||!J(n,e,i))return}oe(n=>n.dragOverId===e.id&&n.dragOverPosition===i?n:{...n,dragOverId:e.id,dragOverPosition:i})}},[J,de.draggedId,r]),xe=l(e=>{oe(n=>n.dragOverId!==e.id?n:{...n,dragOverId:null,dragOverPosition:null})},[]),Ie=l((e,t)=>{t.preventDefault();const a=de.draggedId,i=de.dragOverPosition;if(!a||!i||a===e.id)return void oe(ee);if("child"===i){const t=n(r,a),o=t?.target;if(!o)return void oe(ee);const i=d(r,a,e.id);return i&&U?.(i,o,e.id),void oe(ee)}const l=n(r,e.id);if(!l)return void oe(ee);const s=l.parent?.children??r,c=s.findIndex(n=>n.id===e.id);if(-1===c)return void oe(ee);let u="before"===i?c:c+1;const p=n(r,a),h=l.parent?.id??null;if((p?.parent?.id??null)!==h){const e=p?.target,n=d(r,a,h,u);return n&&e&&U?.(n,e,h),void oe(ee)}if(p&&p.parent===l.parent){const e=s.findIndex(e=>e.id===a);-1!==e&&e<u&&(u-=1)}const g=o(r,a,u);if(g&&g.fromIndex!==g.toIndex&&(W?.(g),_)){const e=X(g.moved,g.fromIndex,g.toIndex);e.length>0&&_(e,{node:g.moved,type:"reorder"})}oe(ee)},[de,r,U,_,W]),ve=l(()=>{oe(ee)},[]),De=l((e,n,t)=>{if(!Z)return;const r=Z(e);if(0===r.length)return;const d=28*r.length+8,o=Math.min(n,window.innerWidth-200-8),a=Math.min(t,window.innerHeight-d-8);ie({x:Math.max(8,o),y:Math.max(8,a),node:e,items:r})},[Z]),Ne=l(()=>{ie(null)},[]),be=l((e,n)=>{n.preventDefault(),De(e,n.clientX,n.clientY)},[De]),Se=l((e,n)=>{n.stopPropagation();const t=n.currentTarget.getBoundingClientRect();De(e,t.left,t.bottom+4)},[De]);s(()=>{if(!ae)return;const e=e=>{const n=e.target;n.closest(`.${F.contextMenu}`)||n.closest(`.${F.moreButton}`)||Ne()},n=e=>{"Escape"===e.key&&Ne()};return document.addEventListener("mousedown",e),document.addEventListener("keydown",n),()=>{document.removeEventListener("mousedown",e),document.removeEventListener("keydown",n)}},[ae,Ne]);const Ce=l(e=>{const n=y(r,e);se.setExpandedIds([...new Set([...se.expandedIds,...n])]),requestAnimationFrame(()=>{se.scrollToNode(e)})},[se,r]);c(t,()=>({expandAll:se.expandAll,collapseAll:se.collapseAll,expandToDepth:se.expandToDepth,getExpandedIds:()=>se.expandedIds,getSelectedNode:()=>{if(!te)return;const e=n(r,te);return e?.target},scrollToNode:Ce,locateNode:e=>{const t=[...r];for(;t.length>0;){const d=t.shift();if(d){if(e(d)){const e=n(r,d.id);return e&&se.setExpandedIds([...new Set([...se.expandedIds,...e.ancestorIds])]),re(d.id),requestAnimationFrame(()=>{se.scrollToNode(d.id)}),d}d.children?.length&&t.push(...d.children)}}}}),[se,Ce,te,r]);const ye=u(()=>({...A,...void 0!==k?{maxHeight:k}:{}}),[A,k]),Me=[F.root,"default"!==P?`pde-tree-variant-${P}`:"",O].filter(Boolean).join(" ");return j("div",{ref:z,className:Me,style:ye,"data-size":L,children:[b&&Q("div",{className:F.toolbar,children:b}),m&&j("div",{className:F.searchRow,children:[j("div",{className:F.searchInputWrap,children:[Q("span",{className:F.searchIcon,children:Q(K,{})}),Q("input",{className:F.searchInput,type:"search",placeholder:x,value:ce.query,onChange:e=>he(e.target.value),"aria-label":"Search tree"})]}),C,v&&Q("button",{type:"button",className:F.iconButton,onClick:se.isAllExpanded?se.collapseAll:se.expandAll,title:se.isAllExpanded?"Collapse all":"Expand all","aria-label":se.isAllExpanded?"Collapse all":"Expand all",children:se.isAllExpanded?Q(q,{size:16,"aria-hidden":"true"}):Q($,{size:16,"aria-hidden":"true"})}),D&&Q("button",{type:"button",className:F.iconButton,onClick:N,title:"Refresh","aria-label":"Refresh",children:Q(T,{size:14,"aria-hidden":"true"})})]}),Q("div",{ref:le,className:F.treeContainer,role:"tree","aria-label":"Tree navigation",children:0===ce.filteredNodes.length?Q("div",{className:F.emptyState,children:ce.isSearching?"No matching results":"No items"}):ce.filteredNodes.map(e=>Q(ne,{node:e,depth:0,expandedIds:ue,selectedId:te,isExpanded:ue.includes(e.id),isSelected:te===e.id,onToggle:se.toggleNode,onSelect:pe,onNodeRef:se.setNodeElementRef,searchQuery:ce.deferredQuery,showIndentGuides:R,renderIcon:E,renderLabel:w,renderSuffix:B,renderNode:M,draggable:G,dragState:de,canDragNode:ge(e),canDragNodeFn:ge,onDragStart:fe,onDragOver:me,onDragLeave:xe,onDrop:Ie,onDragEnd:ve,showContextMenuButton:Boolean(Z),activeMenuNodeId:ae?.node.id??null,onContextMenu:be,onMoreClick:Se},e.id))}),ae&&Q(V,{state:ae,onClose:Ne})]})});export{M as METHOD_LABEL_MAP,te as Tree,E as getMethodLabel,I as useTreeExpansion,S as useTreeSearch};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Generic tree node with extensible metadata.
3
+ *
4
+ * The metadata field is generic so each adapter (openapi, json-schema, doc)
5
+ * can attach its own data without subclassing.
6
+ */
7
+ interface TreeNode<TMetadata = unknown> {
8
+ /** Unique identifier within the tree. */
9
+ id: string;
10
+ /** Display label. */
11
+ name: string;
12
+ /** Optional sort order. Lower values come first. */
13
+ order?: number;
14
+ /** Child nodes. Undefined means a leaf; empty array means expandable with no children. */
15
+ children?: TreeNode<TMetadata>[];
16
+ /** Adapter-specific data (method, path, jsonPath, type, etc.). */
17
+ metadata?: TMetadata;
18
+ }
19
+ /**
20
+ * A resolved path through the tree, from root to a target node.
21
+ */
22
+ interface TreePath<TMetadata = unknown> {
23
+ /** All nodes from root (inclusive) to the target (inclusive). */
24
+ nodes: TreeNode<TMetadata>[];
25
+ /** The target node (last in nodes). */
26
+ target: TreeNode<TMetadata>;
27
+ /** The parent node, or undefined if the target is at the root level. */
28
+ parent: TreeNode<TMetadata> | undefined;
29
+ /** IDs of all ancestor nodes (excluding the target). */
30
+ ancestorIds: string[];
31
+ }
32
+ /**
33
+ * Options for filtering trees.
34
+ */
35
+ interface FilterTreeOptions {
36
+ /** Case-insensitive substring match on node name and id. */
37
+ query: string;
38
+ /** When true, ancestors of matching nodes are retained even if they do not match. */
39
+ keepAncestors?: boolean;
40
+ }
41
+ /**
42
+ * Options for building expansion paths.
43
+ */
44
+ interface ExpandOptions {
45
+ /** Maximum depth to expand. 0 means only the root. Defaults to Infinity. */
46
+ maxDepth?: number;
47
+ /** When true, only expand nodes that have children. Defaults to true. */
48
+ onlyWithChildren?: boolean;
49
+ }
50
+
51
+ export type { ExpandOptions as E, FilterTreeOptions as F, TreeNode as T, TreePath as a };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Generic tree node with extensible metadata.
3
+ *
4
+ * The metadata field is generic so each adapter (openapi, json-schema, doc)
5
+ * can attach its own data without subclassing.
6
+ */
7
+ interface TreeNode<TMetadata = unknown> {
8
+ /** Unique identifier within the tree. */
9
+ id: string;
10
+ /** Display label. */
11
+ name: string;
12
+ /** Optional sort order. Lower values come first. */
13
+ order?: number;
14
+ /** Child nodes. Undefined means a leaf; empty array means expandable with no children. */
15
+ children?: TreeNode<TMetadata>[];
16
+ /** Adapter-specific data (method, path, jsonPath, type, etc.). */
17
+ metadata?: TMetadata;
18
+ }
19
+ /**
20
+ * A resolved path through the tree, from root to a target node.
21
+ */
22
+ interface TreePath<TMetadata = unknown> {
23
+ /** All nodes from root (inclusive) to the target (inclusive). */
24
+ nodes: TreeNode<TMetadata>[];
25
+ /** The target node (last in nodes). */
26
+ target: TreeNode<TMetadata>;
27
+ /** The parent node, or undefined if the target is at the root level. */
28
+ parent: TreeNode<TMetadata> | undefined;
29
+ /** IDs of all ancestor nodes (excluding the target). */
30
+ ancestorIds: string[];
31
+ }
32
+ /**
33
+ * Options for filtering trees.
34
+ */
35
+ interface FilterTreeOptions {
36
+ /** Case-insensitive substring match on node name and id. */
37
+ query: string;
38
+ /** When true, ancestors of matching nodes are retained even if they do not match. */
39
+ keepAncestors?: boolean;
40
+ }
41
+ /**
42
+ * Options for building expansion paths.
43
+ */
44
+ interface ExpandOptions {
45
+ /** Maximum depth to expand. 0 means only the root. Defaults to Infinity. */
46
+ maxDepth?: number;
47
+ /** When true, only expand nodes that have children. Defaults to true. */
48
+ onlyWithChildren?: boolean;
49
+ }
50
+
51
+ export type { ExpandOptions as E, FilterTreeOptions as F, TreeNode as T, TreePath as a };
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@powerduck/tree",
3
+ "version": "0.7.3",
4
+ "description": "Extensible tree component for API navigation, schema exploration, and documentation. Supports OpenAPI 3.2 nested tags, x-tagGroups, and custom data sources.",
5
+ "license": "MIT",
6
+ "author": "powerduck",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./react": {
18
+ "types": "./dist/react/index.d.ts",
19
+ "import": "./dist/react/index.js",
20
+ "require": "./dist/react/index.cjs"
21
+ },
22
+ "./react/index.css": {
23
+ "import": "./dist/react/index.css",
24
+ "require": "./dist/react/index.css",
25
+ "default": "./dist/react/index.css"
26
+ },
27
+ "./adapters": {
28
+ "types": "./dist/adapters/index.d.ts",
29
+ "import": "./dist/adapters/index.js",
30
+ "require": "./dist/adapters/index.cjs"
31
+ },
32
+ "./core": {
33
+ "types": "./dist/core/index.d.ts",
34
+ "import": "./dist/core/index.js",
35
+ "require": "./dist/core/index.cjs"
36
+ }
37
+ },
38
+ "files": [
39
+ "dist"
40
+ ],
41
+ "scripts": {
42
+ "build": "tsup",
43
+ "test": "vitest run",
44
+ "test:watch": "vitest",
45
+ "typecheck": "tsc --noEmit",
46
+ "prepublishOnly": "npm run build && npm run test"
47
+ },
48
+ "peerDependencies": {
49
+ "@chakra-ui/react": ">=2.4.0",
50
+ "react": ">=17.0.0",
51
+ "react-dom": ">=17.0.0"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "@chakra-ui/react": {
55
+ "optional": true
56
+ },
57
+ "react": {
58
+ "optional": true
59
+ },
60
+ "react-dom": {
61
+ "optional": true
62
+ }
63
+ },
64
+ "dependencies": {
65
+ "@powerduck/openapi-parser": "^0.3.3",
66
+ "react-icons": "^5.7.0"
67
+ },
68
+ "devDependencies": {
69
+ "@types/react": "^18.2.0",
70
+ "@types/react-dom": "^18.2.0",
71
+ "react": "^18.2.0",
72
+ "react-dom": "^18.2.0",
73
+ "terser": "^5.51.2",
74
+ "tsup": "^8.0.0",
75
+ "typescript": "^5.3.0",
76
+ "vitest": "^1.2.0"
77
+ },
78
+ "keywords": [
79
+ "tree",
80
+ "openapi",
81
+ "api-navigation",
82
+ "schema-explorer",
83
+ "documentation",
84
+ "chakra-ui",
85
+ "powerduck"
86
+ ],
87
+ "publishConfig": {
88
+ "access": "public"
89
+ }
90
+ }