@negative-space/file-tree 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Matheus Bastani
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # @negative-space/file-tree
2
+
3
+ A lightweight and flexible file tree component for React.
4
+
5
+ ## Installation
6
+
7
+ # Using Yarn
8
+ yarn add @negative-space/file-tree
9
+
10
+ # Using npm
11
+ npm install @negative-space/file-tree
12
+
13
+ ## Contributing
14
+
15
+ Feel free to fork, tweak, and send a pull request!
@@ -0,0 +1,77 @@
1
+ import { FlexProps } from '@negative-space/flex';
2
+ import React from 'react';
3
+ import { IconButtonProps } from '@negative-space/button';
4
+
5
+ interface FileTreeFolderProps extends Omit<FlexProps, 'children' | 'className' | 'style' | 'prefix'> {
6
+ classNames?: {
7
+ root?: string;
8
+ header?: string;
9
+ collapseButton?: IconButtonProps['classNames'];
10
+ prefix?: string;
11
+ label?: string;
12
+ suffix?: string;
13
+ children?: string;
14
+ };
15
+ styles?: {
16
+ root?: React.CSSProperties;
17
+ header?: React.CSSProperties;
18
+ collapseButton?: IconButtonProps['styles'];
19
+ prefix?: React.CSSProperties;
20
+ label?: React.CSSProperties;
21
+ suffix?: React.CSSProperties;
22
+ children?: React.CSSProperties;
23
+ };
24
+ prefix?: React.ReactNode;
25
+ label?: React.ReactNode;
26
+ suffix?: React.ReactNode;
27
+ children?: React.ReactNode;
28
+ collapsable?: boolean;
29
+ collapsed?: boolean;
30
+ setCollapsed?: (collapsed: boolean) => void;
31
+ active?: boolean;
32
+ }
33
+
34
+ interface FileTreeItemProps extends Omit<FlexProps, 'children' | 'className' | 'style' | 'prefix'> {
35
+ classNames?: {
36
+ root?: string;
37
+ prefix?: string;
38
+ label?: string;
39
+ suffix?: string;
40
+ };
41
+ styles?: {
42
+ root?: React.CSSProperties;
43
+ prefix?: React.CSSProperties;
44
+ label?: React.CSSProperties;
45
+ suffix?: React.CSSProperties;
46
+ };
47
+ prefix?: React.ReactNode;
48
+ label?: React.ReactNode;
49
+ suffix?: React.ReactNode;
50
+ active?: boolean;
51
+ }
52
+
53
+ type FileTreeEntry = {
54
+ folder: Omit<FileTreeFolderProps, 'children'>;
55
+ items?: FileTreeEntry[];
56
+ item?: never;
57
+ } | {
58
+ item: FileTreeItemProps;
59
+ folder?: never;
60
+ items?: never;
61
+ };
62
+ interface FileTreeProps extends Omit<FlexProps, 'children'> {
63
+ classNames?: {
64
+ root?: string;
65
+ folders?: FileTreeFolderProps['classNames'];
66
+ items?: FileTreeItemProps['classNames'];
67
+ };
68
+ styles?: {
69
+ root?: React.CSSProperties;
70
+ folders?: FileTreeFolderProps['styles'];
71
+ items?: FileTreeItemProps['styles'];
72
+ };
73
+ items?: FileTreeEntry[];
74
+ }
75
+ declare const FileTree: React.ForwardRefExoticComponent<FileTreeProps & React.RefAttributes<HTMLDivElement>>;
76
+
77
+ export { FileTree, type FileTreeProps };
@@ -0,0 +1,77 @@
1
+ import { FlexProps } from '@negative-space/flex';
2
+ import React from 'react';
3
+ import { IconButtonProps } from '@negative-space/button';
4
+
5
+ interface FileTreeFolderProps extends Omit<FlexProps, 'children' | 'className' | 'style' | 'prefix'> {
6
+ classNames?: {
7
+ root?: string;
8
+ header?: string;
9
+ collapseButton?: IconButtonProps['classNames'];
10
+ prefix?: string;
11
+ label?: string;
12
+ suffix?: string;
13
+ children?: string;
14
+ };
15
+ styles?: {
16
+ root?: React.CSSProperties;
17
+ header?: React.CSSProperties;
18
+ collapseButton?: IconButtonProps['styles'];
19
+ prefix?: React.CSSProperties;
20
+ label?: React.CSSProperties;
21
+ suffix?: React.CSSProperties;
22
+ children?: React.CSSProperties;
23
+ };
24
+ prefix?: React.ReactNode;
25
+ label?: React.ReactNode;
26
+ suffix?: React.ReactNode;
27
+ children?: React.ReactNode;
28
+ collapsable?: boolean;
29
+ collapsed?: boolean;
30
+ setCollapsed?: (collapsed: boolean) => void;
31
+ active?: boolean;
32
+ }
33
+
34
+ interface FileTreeItemProps extends Omit<FlexProps, 'children' | 'className' | 'style' | 'prefix'> {
35
+ classNames?: {
36
+ root?: string;
37
+ prefix?: string;
38
+ label?: string;
39
+ suffix?: string;
40
+ };
41
+ styles?: {
42
+ root?: React.CSSProperties;
43
+ prefix?: React.CSSProperties;
44
+ label?: React.CSSProperties;
45
+ suffix?: React.CSSProperties;
46
+ };
47
+ prefix?: React.ReactNode;
48
+ label?: React.ReactNode;
49
+ suffix?: React.ReactNode;
50
+ active?: boolean;
51
+ }
52
+
53
+ type FileTreeEntry = {
54
+ folder: Omit<FileTreeFolderProps, 'children'>;
55
+ items?: FileTreeEntry[];
56
+ item?: never;
57
+ } | {
58
+ item: FileTreeItemProps;
59
+ folder?: never;
60
+ items?: never;
61
+ };
62
+ interface FileTreeProps extends Omit<FlexProps, 'children'> {
63
+ classNames?: {
64
+ root?: string;
65
+ folders?: FileTreeFolderProps['classNames'];
66
+ items?: FileTreeItemProps['classNames'];
67
+ };
68
+ styles?: {
69
+ root?: React.CSSProperties;
70
+ folders?: FileTreeFolderProps['styles'];
71
+ items?: FileTreeItemProps['styles'];
72
+ };
73
+ items?: FileTreeEntry[];
74
+ }
75
+ declare const FileTree: React.ForwardRefExoticComponent<FileTreeProps & React.RefAttributes<HTMLDivElement>>;
76
+
77
+ export { FileTree, type FileTreeProps };
package/dist/index.js ADDED
@@ -0,0 +1,213 @@
1
+ 'use strict';
2
+
3
+ var flex = require('@negative-space/flex');
4
+ var system = require('@negative-space/system');
5
+ var React = require('react');
6
+ var button = require('@negative-space/button');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var React__default = /*#__PURE__*/_interopDefault(React);
12
+
13
+ // src/FileTree.tsx
14
+ var FileTreeFolder = React__default.default.forwardRef(
15
+ ({
16
+ classNames,
17
+ styles,
18
+ collapsable = true,
19
+ collapsed = true,
20
+ setCollapsed: setCollapsedProp,
21
+ prefix,
22
+ label,
23
+ suffix,
24
+ active,
25
+ children,
26
+ ...props
27
+ }, ref) => {
28
+ const { global } = system.useNSUI();
29
+ const [collapsedState, setCollapsedState] = React.useState(collapsed);
30
+ React.useEffect(() => {
31
+ setCollapsedState(collapsed);
32
+ }, [collapsed]);
33
+ const isCollapsed = setCollapsedProp ? collapsed : collapsedState;
34
+ const handleCollapse = () => {
35
+ const nextCollapsed = !isCollapsed;
36
+ setCollapsedState(nextCollapsed);
37
+ setCollapsedProp?.(nextCollapsed);
38
+ };
39
+ return /* @__PURE__ */ jsxRuntime.jsxs(
40
+ flex.Flex,
41
+ {
42
+ ref,
43
+ direction: "column",
44
+ className: system.cn(`${global?.prefixCls}-file-tree-folder`, classNames?.root),
45
+ "data-active": active,
46
+ style: styles?.root,
47
+ ...props,
48
+ children: [
49
+ /* @__PURE__ */ jsxRuntime.jsxs(
50
+ flex.Flex,
51
+ {
52
+ className: system.cn(`${global?.prefixCls}-file-tree-folder-header`, classNames?.header),
53
+ "data-active": active,
54
+ "data-collapsed": isCollapsed,
55
+ style: styles?.header,
56
+ children: [
57
+ collapsable && /* @__PURE__ */ jsxRuntime.jsx(
58
+ button.IconButton,
59
+ {
60
+ classNames: classNames?.collapseButton,
61
+ "data-collapsed": isCollapsed,
62
+ styles: styles?.collapseButton,
63
+ onClick: handleCollapse,
64
+ children: /* @__PURE__ */ jsxRuntime.jsx(
65
+ system.ChevronDown,
66
+ {
67
+ style: {
68
+ transform: isCollapsed ? "rotate(-90deg)" : "",
69
+ ...styles?.collapseButton?.icon
70
+ }
71
+ }
72
+ )
73
+ }
74
+ ),
75
+ prefix && /* @__PURE__ */ jsxRuntime.jsx(
76
+ "div",
77
+ {
78
+ className: system.cn(`${global?.prefixCls}-file-tree-folder-prefix`, classNames?.prefix),
79
+ style: styles?.prefix,
80
+ children: prefix
81
+ }
82
+ ),
83
+ /* @__PURE__ */ jsxRuntime.jsx(
84
+ "div",
85
+ {
86
+ className: system.cn(`${global?.prefixCls}-file-tree-folder-label`, classNames?.label),
87
+ style: styles?.label,
88
+ children: label
89
+ }
90
+ ),
91
+ suffix && /* @__PURE__ */ jsxRuntime.jsx(
92
+ "div",
93
+ {
94
+ className: system.cn(`${global?.prefixCls}-file-tree-folder-suffix`, classNames?.suffix),
95
+ style: styles?.suffix,
96
+ children: suffix
97
+ }
98
+ )
99
+ ]
100
+ }
101
+ ),
102
+ !isCollapsed && /* @__PURE__ */ jsxRuntime.jsx(
103
+ "div",
104
+ {
105
+ className: system.cn(`${global?.prefixCls}-file-tree-folder-children`, classNames?.children),
106
+ style: styles?.children,
107
+ children
108
+ }
109
+ )
110
+ ]
111
+ }
112
+ );
113
+ }
114
+ );
115
+ FileTreeFolder.displayName = "FileTreeFolder";
116
+ var FileTreeItem = React__default.default.forwardRef(
117
+ ({ classNames, styles, prefix, label, suffix, active, ...props }, ref) => {
118
+ const { global } = system.useNSUI();
119
+ return /* @__PURE__ */ jsxRuntime.jsxs(
120
+ flex.Flex,
121
+ {
122
+ ref,
123
+ className: system.cn(`${global?.prefixCls}-file-tree-item`, classNames?.root),
124
+ "data-active": active,
125
+ style: styles?.root,
126
+ ...props,
127
+ children: [
128
+ prefix && /* @__PURE__ */ jsxRuntime.jsx(
129
+ "div",
130
+ {
131
+ className: system.cn(`${global?.prefixCls}-file-tree-item-prefix`, classNames?.prefix),
132
+ style: styles?.prefix,
133
+ children: prefix
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsxRuntime.jsx(
137
+ "div",
138
+ {
139
+ className: system.cn(`${global?.prefixCls}-file-tree-item-label`, classNames?.label),
140
+ style: styles?.label,
141
+ children: label
142
+ }
143
+ ),
144
+ suffix && /* @__PURE__ */ jsxRuntime.jsx(
145
+ "div",
146
+ {
147
+ className: system.cn(`${global?.prefixCls}-file-tree-item-suffix`, classNames?.suffix),
148
+ style: styles?.suffix,
149
+ children: suffix
150
+ }
151
+ )
152
+ ]
153
+ }
154
+ );
155
+ }
156
+ );
157
+ FileTreeItem.displayName = "FileTreeItem";
158
+ var FileTree = React__default.default.forwardRef(
159
+ ({ className, classNames, styles, items = [], ...props }, ref) => {
160
+ const { global } = system.useNSUI();
161
+ const renderEntries = (entries) => entries.map((entry, index) => {
162
+ if (entry.folder) {
163
+ return /* @__PURE__ */ jsxRuntime.jsx(
164
+ FileTreeFolder,
165
+ {
166
+ ...entry.folder,
167
+ classNames: {
168
+ ...classNames?.folders,
169
+ ...entry.folder.classNames
170
+ },
171
+ styles: {
172
+ ...styles?.folders,
173
+ ...entry.folder.styles
174
+ },
175
+ children: entry.items && renderEntries(entry.items)
176
+ },
177
+ index
178
+ );
179
+ }
180
+ return /* @__PURE__ */ jsxRuntime.jsx(
181
+ FileTreeItem,
182
+ {
183
+ ...entry.item,
184
+ classNames: {
185
+ ...classNames?.items,
186
+ ...entry.item.classNames
187
+ },
188
+ styles: {
189
+ ...styles?.items,
190
+ ...entry.item.styles
191
+ }
192
+ },
193
+ index
194
+ );
195
+ });
196
+ return /* @__PURE__ */ jsxRuntime.jsx(
197
+ flex.Flex,
198
+ {
199
+ ref,
200
+ direction: "column",
201
+ className: system.cn(`${global?.prefixCls}-file-tree`, className, classNames?.root),
202
+ style: styles?.root,
203
+ ...props,
204
+ children: renderEntries(items)
205
+ }
206
+ );
207
+ }
208
+ );
209
+ FileTree.displayName = "FileTree";
210
+
211
+ exports.FileTree = FileTree;
212
+ //# sourceMappingURL=index.js.map
213
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/FileTreeFolder.tsx","../src/FileTreeItem.tsx","../src/FileTree.tsx"],"names":["React","useNSUI","useState","useEffect","jsxs","Flex","cn","jsx","IconButton","ChevronDown"],"mappings":";;;;;;;;;;;;;AAqCO,IAAM,iBAAiBA,sBAAA,CAAM,UAAA;AAAA,EAClC,CACE;AAAA,IACE,UAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA,GAAc,IAAA;AAAA,IACd,SAAA,GAAY,IAAA;AAAA,IACZ,YAAA,EAAc,gBAAA;AAAA,IACd,MAAA;AAAA,IACA,KAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAG;AAAA,KAEL,GAAA,KACG;AACH,IAAA,MAAM,EAAE,MAAA,EAAO,GAAIC,cAAA,EAAQ;AAC3B,IAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIC,eAAS,SAAS,CAAA;AAE9D,IAAAC,eAAA,CAAU,MAAM;AACd,MAAA,iBAAA,CAAkB,SAAS,CAAA;AAAA,IAC7B,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,IAAA,MAAM,WAAA,GAAc,mBAAmB,SAAA,GAAY,cAAA;AAEnD,IAAA,MAAM,iBAAiB,MAAM;AAC3B,MAAA,MAAM,gBAAgB,CAAC,WAAA;AAEvB,MAAA,iBAAA,CAAkB,aAAa,CAAA;AAC/B,MAAA,gBAAA,GAAmB,aAAa,CAAA;AAAA,IAClC,CAAA;AAEA,IAAA,uBACEC,eAAA;AAAA,MAACC,SAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAU,QAAA;AAAA,QACV,WAAWC,SAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,iBAAA,CAAA,EAAqB,YAAY,IAAI,CAAA;AAAA,QACvE,aAAA,EAAa,MAAA;AAAA,QACb,OAAO,MAAA,EAAQ,IAAA;AAAA,QACd,GAAG,KAAA;AAAA,QAEJ,QAAA,EAAA;AAAA,0BAAAF,eAAA;AAAA,YAACC,SAAA;AAAA,YAAA;AAAA,cACC,WAAWC,SAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,wBAAA,CAAA,EAA4B,YAAY,MAAM,CAAA;AAAA,cAChF,aAAA,EAAa,MAAA;AAAA,cACb,gBAAA,EAAgB,WAAA;AAAA,cAChB,OAAO,MAAA,EAAQ,MAAA;AAAA,cAEd,QAAA,EAAA;AAAA,gBAAA,WAAA,oBACCC,cAAA;AAAA,kBAACC,iBAAA;AAAA,kBAAA;AAAA,oBACC,YAAY,UAAA,EAAY,cAAA;AAAA,oBACxB,gBAAA,EAAgB,WAAA;AAAA,oBAChB,QAAQ,MAAA,EAAQ,cAAA;AAAA,oBAChB,OAAA,EAAS,cAAA;AAAA,oBAET,QAAA,kBAAAD,cAAA;AAAA,sBAACE,kBAAA;AAAA,sBAAA;AAAA,wBACC,KAAA,EAAO;AAAA,0BACL,SAAA,EAAW,cAAc,gBAAA,GAAmB,EAAA;AAAA,0BAC5C,GAAG,QAAQ,cAAA,EAAgB;AAAA;AAC7B;AAAA;AACF;AAAA,iBACF;AAAA,gBAGD,MAAA,oBACCF,cAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,WAAWD,SAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,wBAAA,CAAA,EAA4B,YAAY,MAAM,CAAA;AAAA,oBAChF,OAAO,MAAA,EAAQ,MAAA;AAAA,oBAEd,QAAA,EAAA;AAAA;AAAA,iBACH;AAAA,gCAGFC,cAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,WAAWD,SAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,uBAAA,CAAA,EAA2B,YAAY,KAAK,CAAA;AAAA,oBAC9E,OAAO,MAAA,EAAQ,KAAA;AAAA,oBAEd,QAAA,EAAA;AAAA;AAAA,iBACH;AAAA,gBAEC,MAAA,oBACCC,cAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,WAAWD,SAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,wBAAA,CAAA,EAA4B,YAAY,MAAM,CAAA;AAAA,oBAChF,OAAO,MAAA,EAAQ,MAAA;AAAA,oBAEd,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,WAEJ;AAAA,UAEC,CAAC,WAAA,oBACAC,cAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,WAAWD,SAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,0BAAA,CAAA,EAA8B,YAAY,QAAQ,CAAA;AAAA,cACpF,OAAO,MAAA,EAAQ,QAAA;AAAA,cAEd;AAAA;AAAA;AACH;AAAA;AAAA,KAEJ;AAAA,EAEJ;AACF,CAAA;AAEA,cAAA,CAAe,WAAA,GAAc,gBAAA;AClHtB,IAAM,eAAeN,sBAAAA,CAAM,UAAA;AAAA,EAChC,CAAC,EAAE,UAAA,EAAY,MAAA,EAAQ,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAQ,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACxE,IAAA,MAAM,EAAE,MAAA,EAAO,GAAIC,cAAAA,EAAQ;AAE3B,IAAA,uBACEG,eAAAA;AAAA,MAACC,SAAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,WAAWC,SAAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,eAAA,CAAA,EAAmB,YAAY,IAAI,CAAA;AAAA,QACrE,aAAA,EAAa,MAAA;AAAA,QACb,OAAO,MAAA,EAAQ,IAAA;AAAA,QACd,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,MAAA,oBACCC,cAAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,WAAWD,SAAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,sBAAA,CAAA,EAA0B,YAAY,MAAM,CAAA;AAAA,cAC9E,OAAO,MAAA,EAAQ,MAAA;AAAA,cAEd,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,0BAGFC,cAAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,WAAWD,SAAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,qBAAA,CAAA,EAAyB,YAAY,KAAK,CAAA;AAAA,cAC5E,OAAO,MAAA,EAAQ,KAAA;AAAA,cAEd,QAAA,EAAA;AAAA;AAAA,WACH;AAAA,UAEC,0BACCC,cAAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,WAAWD,SAAAA,CAAG,CAAA,EAAG,QAAQ,SAAS,CAAA,sBAAA,CAAA,EAA0B,YAAY,MAAM,CAAA;AAAA,cAC9E,OAAO,MAAA,EAAQ,MAAA;AAAA,cAEd,QAAA,EAAA;AAAA;AAAA;AACH;AAAA;AAAA,KAEJ;AAAA,EAEJ;AACF,CAAA;AAEA,YAAA,CAAa,WAAA,GAAc,cAAA;AClCpB,IAAM,WAAWN,sBAAAA,CAAM,UAAA;AAAA,EAC5B,CAAC,EAAE,SAAA,EAAW,UAAA,EAAY,MAAA,EAAQ,KAAA,GAAQ,EAAC,EAAG,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AAChE,IAAA,MAAM,EAAE,MAAA,EAAO,GAAIC,cAAAA,EAAQ;AAE3B,IAAA,MAAM,gBAAgB,CAAC,OAAA,KACrB,QAAQ,GAAA,CAAI,CAAC,OAAO,KAAA,KAAU;AAC5B,MAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,QAAA,uBACEM,cAAAA;AAAA,UAAC,cAAA;AAAA,UAAA;AAAA,YAEE,GAAG,KAAA,CAAM,MAAA;AAAA,YACV,UAAA,EAAY;AAAA,cACV,GAAG,UAAA,EAAY,OAAA;AAAA,cACf,GAAG,MAAM,MAAA,CAAO;AAAA,aAClB;AAAA,YACA,MAAA,EAAQ;AAAA,cACN,GAAG,MAAA,EAAQ,OAAA;AAAA,cACX,GAAG,MAAM,MAAA,CAAO;AAAA,aAClB;AAAA,YAEC,QAAA,EAAA,KAAA,CAAM,KAAA,IAAS,aAAA,CAAc,KAAA,CAAM,KAAK;AAAA,WAAA;AAAA,UAXpC;AAAA,SAYP;AAAA,MAEJ;AAEA,MAAA,uBACEA,cAAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UAEE,GAAG,KAAA,CAAM,IAAA;AAAA,UACV,UAAA,EAAY;AAAA,YACV,GAAG,UAAA,EAAY,KAAA;AAAA,YACf,GAAG,MAAM,IAAA,CAAK;AAAA,WAChB;AAAA,UACA,MAAA,EAAQ;AAAA,YACN,GAAG,MAAA,EAAQ,KAAA;AAAA,YACX,GAAG,MAAM,IAAA,CAAK;AAAA;AAChB,SAAA;AAAA,QATK;AAAA,OAUP;AAAA,IAEJ,CAAC,CAAA;AAEH,IAAA,uBACEA,cAAAA;AAAA,MAACF,SAAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAU,QAAA;AAAA,QACV,SAAA,EAAWC,UAAG,CAAA,EAAG,MAAA,EAAQ,SAAS,CAAA,UAAA,CAAA,EAAc,SAAA,EAAW,YAAY,IAAI,CAAA;AAAA,QAC3E,OAAO,MAAA,EAAQ,IAAA;AAAA,QACd,GAAG,KAAA;AAAA,QAEH,wBAAc,KAAK;AAAA;AAAA,KACtB;AAAA,EAEJ;AACF;AAEA,QAAA,CAAS,WAAA,GAAc,UAAA","file":"index.js","sourcesContent":["import { IconButton, type IconButtonProps } from '@negative-space/button'\nimport { Flex, type FlexProps } from '@negative-space/flex'\nimport { ChevronDown, cn, useNSUI } from '@negative-space/system'\nimport React, { useEffect, useState } from 'react'\n\nexport interface FileTreeFolderProps extends Omit<\n FlexProps,\n 'children' | 'className' | 'style' | 'prefix'\n> {\n classNames?: {\n root?: string\n header?: string\n collapseButton?: IconButtonProps['classNames']\n prefix?: string\n label?: string\n suffix?: string\n children?: string\n }\n styles?: {\n root?: React.CSSProperties\n header?: React.CSSProperties\n collapseButton?: IconButtonProps['styles']\n prefix?: React.CSSProperties\n label?: React.CSSProperties\n suffix?: React.CSSProperties\n children?: React.CSSProperties\n }\n prefix?: React.ReactNode\n label?: React.ReactNode\n suffix?: React.ReactNode\n children?: React.ReactNode\n collapsable?: boolean\n collapsed?: boolean\n setCollapsed?: (collapsed: boolean) => void\n active?: boolean\n}\n\nexport const FileTreeFolder = React.forwardRef<HTMLDivElement, FileTreeFolderProps>(\n (\n {\n classNames,\n styles,\n collapsable = true,\n collapsed = true,\n setCollapsed: setCollapsedProp,\n prefix,\n label,\n suffix,\n active,\n children,\n ...props\n },\n ref\n ) => {\n const { global } = useNSUI()\n const [collapsedState, setCollapsedState] = useState(collapsed)\n\n useEffect(() => {\n setCollapsedState(collapsed)\n }, [collapsed])\n\n const isCollapsed = setCollapsedProp ? collapsed : collapsedState\n\n const handleCollapse = () => {\n const nextCollapsed = !isCollapsed\n\n setCollapsedState(nextCollapsed)\n setCollapsedProp?.(nextCollapsed)\n }\n\n return (\n <Flex\n ref={ref}\n direction=\"column\"\n className={cn(`${global?.prefixCls}-file-tree-folder`, classNames?.root)}\n data-active={active}\n style={styles?.root}\n {...props}\n >\n <Flex\n className={cn(`${global?.prefixCls}-file-tree-folder-header`, classNames?.header)}\n data-active={active}\n data-collapsed={isCollapsed}\n style={styles?.header}\n >\n {collapsable && (\n <IconButton\n classNames={classNames?.collapseButton}\n data-collapsed={isCollapsed}\n styles={styles?.collapseButton}\n onClick={handleCollapse}\n >\n <ChevronDown\n style={{\n transform: isCollapsed ? 'rotate(-90deg)' : '',\n ...styles?.collapseButton?.icon\n }}\n />\n </IconButton>\n )}\n\n {prefix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-prefix`, classNames?.prefix)}\n style={styles?.prefix}\n >\n {prefix}\n </div>\n )}\n\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-label`, classNames?.label)}\n style={styles?.label}\n >\n {label}\n </div>\n\n {suffix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-suffix`, classNames?.suffix)}\n style={styles?.suffix}\n >\n {suffix}\n </div>\n )}\n </Flex>\n\n {!isCollapsed && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-children`, classNames?.children)}\n style={styles?.children}\n >\n {children}\n </div>\n )}\n </Flex>\n )\n }\n)\n\nFileTreeFolder.displayName = 'FileTreeFolder'\n","import { Flex, type FlexProps } from '@negative-space/flex'\nimport { cn, useNSUI } from '@negative-space/system'\nimport React from 'react'\n\nexport interface FileTreeItemProps extends Omit<\n FlexProps,\n 'children' | 'className' | 'style' | 'prefix'\n> {\n classNames?: {\n root?: string\n prefix?: string\n label?: string\n suffix?: string\n }\n styles?: {\n root?: React.CSSProperties\n prefix?: React.CSSProperties\n label?: React.CSSProperties\n suffix?: React.CSSProperties\n }\n prefix?: React.ReactNode\n label?: React.ReactNode\n suffix?: React.ReactNode\n active?: boolean\n}\n\nexport const FileTreeItem = React.forwardRef<HTMLDivElement, FileTreeItemProps>(\n ({ classNames, styles, prefix, label, suffix, active, ...props }, ref) => {\n const { global } = useNSUI()\n\n return (\n <Flex\n ref={ref}\n className={cn(`${global?.prefixCls}-file-tree-item`, classNames?.root)}\n data-active={active}\n style={styles?.root}\n {...props}\n >\n {prefix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-item-prefix`, classNames?.prefix)}\n style={styles?.prefix}\n >\n {prefix}\n </div>\n )}\n\n <div\n className={cn(`${global?.prefixCls}-file-tree-item-label`, classNames?.label)}\n style={styles?.label}\n >\n {label}\n </div>\n\n {suffix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-item-suffix`, classNames?.suffix)}\n style={styles?.suffix}\n >\n {suffix}\n </div>\n )}\n </Flex>\n )\n }\n)\n\nFileTreeItem.displayName = 'FileTreeItem'\n","import { Flex, type FlexProps } from '@negative-space/flex'\nimport { cn, useNSUI } from '@negative-space/system'\nimport React from 'react'\n\nimport { FileTreeFolder, type FileTreeFolderProps } from './FileTreeFolder'\nimport { FileTreeItem, type FileTreeItemProps } from './FileTreeItem'\n\nexport type FileTreeEntry =\n | {\n folder: Omit<FileTreeFolderProps, 'children'>\n items?: FileTreeEntry[]\n item?: never\n }\n | {\n item: FileTreeItemProps\n folder?: never\n items?: never\n }\n\nexport interface FileTreeProps extends Omit<FlexProps, 'children'> {\n classNames?: {\n root?: string\n folders?: FileTreeFolderProps['classNames']\n items?: FileTreeItemProps['classNames']\n }\n styles?: {\n root?: React.CSSProperties\n folders?: FileTreeFolderProps['styles']\n items?: FileTreeItemProps['styles']\n }\n items?: FileTreeEntry[]\n}\n\nexport const FileTree = React.forwardRef<HTMLDivElement, FileTreeProps>(\n ({ className, classNames, styles, items = [], ...props }, ref) => {\n const { global } = useNSUI()\n\n const renderEntries = (entries: FileTreeEntry[]) =>\n entries.map((entry, index) => {\n if (entry.folder) {\n return (\n <FileTreeFolder\n key={index}\n {...entry.folder}\n classNames={{\n ...classNames?.folders,\n ...entry.folder.classNames\n }}\n styles={{\n ...styles?.folders,\n ...entry.folder.styles\n }}\n >\n {entry.items && renderEntries(entry.items)}\n </FileTreeFolder>\n )\n }\n\n return (\n <FileTreeItem\n key={index}\n {...entry.item}\n classNames={{\n ...classNames?.items,\n ...entry.item.classNames\n }}\n styles={{\n ...styles?.items,\n ...entry.item.styles\n }}\n />\n )\n })\n\n return (\n <Flex\n ref={ref}\n direction=\"column\"\n className={cn(`${global?.prefixCls}-file-tree`, className, classNames?.root)}\n style={styles?.root}\n {...props}\n >\n {renderEntries(items)}\n </Flex>\n )\n }\n)\n\nFileTree.displayName = 'FileTree'\n"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,207 @@
1
+ import { Flex } from '@negative-space/flex';
2
+ import { useNSUI, cn, ChevronDown } from '@negative-space/system';
3
+ import React, { useState, useEffect } from 'react';
4
+ import { IconButton } from '@negative-space/button';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ // src/FileTree.tsx
8
+ var FileTreeFolder = React.forwardRef(
9
+ ({
10
+ classNames,
11
+ styles,
12
+ collapsable = true,
13
+ collapsed = true,
14
+ setCollapsed: setCollapsedProp,
15
+ prefix,
16
+ label,
17
+ suffix,
18
+ active,
19
+ children,
20
+ ...props
21
+ }, ref) => {
22
+ const { global } = useNSUI();
23
+ const [collapsedState, setCollapsedState] = useState(collapsed);
24
+ useEffect(() => {
25
+ setCollapsedState(collapsed);
26
+ }, [collapsed]);
27
+ const isCollapsed = setCollapsedProp ? collapsed : collapsedState;
28
+ const handleCollapse = () => {
29
+ const nextCollapsed = !isCollapsed;
30
+ setCollapsedState(nextCollapsed);
31
+ setCollapsedProp?.(nextCollapsed);
32
+ };
33
+ return /* @__PURE__ */ jsxs(
34
+ Flex,
35
+ {
36
+ ref,
37
+ direction: "column",
38
+ className: cn(`${global?.prefixCls}-file-tree-folder`, classNames?.root),
39
+ "data-active": active,
40
+ style: styles?.root,
41
+ ...props,
42
+ children: [
43
+ /* @__PURE__ */ jsxs(
44
+ Flex,
45
+ {
46
+ className: cn(`${global?.prefixCls}-file-tree-folder-header`, classNames?.header),
47
+ "data-active": active,
48
+ "data-collapsed": isCollapsed,
49
+ style: styles?.header,
50
+ children: [
51
+ collapsable && /* @__PURE__ */ jsx(
52
+ IconButton,
53
+ {
54
+ classNames: classNames?.collapseButton,
55
+ "data-collapsed": isCollapsed,
56
+ styles: styles?.collapseButton,
57
+ onClick: handleCollapse,
58
+ children: /* @__PURE__ */ jsx(
59
+ ChevronDown,
60
+ {
61
+ style: {
62
+ transform: isCollapsed ? "rotate(-90deg)" : "",
63
+ ...styles?.collapseButton?.icon
64
+ }
65
+ }
66
+ )
67
+ }
68
+ ),
69
+ prefix && /* @__PURE__ */ jsx(
70
+ "div",
71
+ {
72
+ className: cn(`${global?.prefixCls}-file-tree-folder-prefix`, classNames?.prefix),
73
+ style: styles?.prefix,
74
+ children: prefix
75
+ }
76
+ ),
77
+ /* @__PURE__ */ jsx(
78
+ "div",
79
+ {
80
+ className: cn(`${global?.prefixCls}-file-tree-folder-label`, classNames?.label),
81
+ style: styles?.label,
82
+ children: label
83
+ }
84
+ ),
85
+ suffix && /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ className: cn(`${global?.prefixCls}-file-tree-folder-suffix`, classNames?.suffix),
89
+ style: styles?.suffix,
90
+ children: suffix
91
+ }
92
+ )
93
+ ]
94
+ }
95
+ ),
96
+ !isCollapsed && /* @__PURE__ */ jsx(
97
+ "div",
98
+ {
99
+ className: cn(`${global?.prefixCls}-file-tree-folder-children`, classNames?.children),
100
+ style: styles?.children,
101
+ children
102
+ }
103
+ )
104
+ ]
105
+ }
106
+ );
107
+ }
108
+ );
109
+ FileTreeFolder.displayName = "FileTreeFolder";
110
+ var FileTreeItem = React.forwardRef(
111
+ ({ classNames, styles, prefix, label, suffix, active, ...props }, ref) => {
112
+ const { global } = useNSUI();
113
+ return /* @__PURE__ */ jsxs(
114
+ Flex,
115
+ {
116
+ ref,
117
+ className: cn(`${global?.prefixCls}-file-tree-item`, classNames?.root),
118
+ "data-active": active,
119
+ style: styles?.root,
120
+ ...props,
121
+ children: [
122
+ prefix && /* @__PURE__ */ jsx(
123
+ "div",
124
+ {
125
+ className: cn(`${global?.prefixCls}-file-tree-item-prefix`, classNames?.prefix),
126
+ style: styles?.prefix,
127
+ children: prefix
128
+ }
129
+ ),
130
+ /* @__PURE__ */ jsx(
131
+ "div",
132
+ {
133
+ className: cn(`${global?.prefixCls}-file-tree-item-label`, classNames?.label),
134
+ style: styles?.label,
135
+ children: label
136
+ }
137
+ ),
138
+ suffix && /* @__PURE__ */ jsx(
139
+ "div",
140
+ {
141
+ className: cn(`${global?.prefixCls}-file-tree-item-suffix`, classNames?.suffix),
142
+ style: styles?.suffix,
143
+ children: suffix
144
+ }
145
+ )
146
+ ]
147
+ }
148
+ );
149
+ }
150
+ );
151
+ FileTreeItem.displayName = "FileTreeItem";
152
+ var FileTree = React.forwardRef(
153
+ ({ className, classNames, styles, items = [], ...props }, ref) => {
154
+ const { global } = useNSUI();
155
+ const renderEntries = (entries) => entries.map((entry, index) => {
156
+ if (entry.folder) {
157
+ return /* @__PURE__ */ jsx(
158
+ FileTreeFolder,
159
+ {
160
+ ...entry.folder,
161
+ classNames: {
162
+ ...classNames?.folders,
163
+ ...entry.folder.classNames
164
+ },
165
+ styles: {
166
+ ...styles?.folders,
167
+ ...entry.folder.styles
168
+ },
169
+ children: entry.items && renderEntries(entry.items)
170
+ },
171
+ index
172
+ );
173
+ }
174
+ return /* @__PURE__ */ jsx(
175
+ FileTreeItem,
176
+ {
177
+ ...entry.item,
178
+ classNames: {
179
+ ...classNames?.items,
180
+ ...entry.item.classNames
181
+ },
182
+ styles: {
183
+ ...styles?.items,
184
+ ...entry.item.styles
185
+ }
186
+ },
187
+ index
188
+ );
189
+ });
190
+ return /* @__PURE__ */ jsx(
191
+ Flex,
192
+ {
193
+ ref,
194
+ direction: "column",
195
+ className: cn(`${global?.prefixCls}-file-tree`, className, classNames?.root),
196
+ style: styles?.root,
197
+ ...props,
198
+ children: renderEntries(items)
199
+ }
200
+ );
201
+ }
202
+ );
203
+ FileTree.displayName = "FileTree";
204
+
205
+ export { FileTree };
206
+ //# sourceMappingURL=index.mjs.map
207
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/FileTreeFolder.tsx","../src/FileTreeItem.tsx","../src/FileTree.tsx"],"names":["React","useNSUI","jsxs","Flex","cn","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["import { IconButton, type IconButtonProps } from '@negative-space/button'\nimport { Flex, type FlexProps } from '@negative-space/flex'\nimport { ChevronDown, cn, useNSUI } from '@negative-space/system'\nimport React, { useEffect, useState } from 'react'\n\nexport interface FileTreeFolderProps extends Omit<\n FlexProps,\n 'children' | 'className' | 'style' | 'prefix'\n> {\n classNames?: {\n root?: string\n header?: string\n collapseButton?: IconButtonProps['classNames']\n prefix?: string\n label?: string\n suffix?: string\n children?: string\n }\n styles?: {\n root?: React.CSSProperties\n header?: React.CSSProperties\n collapseButton?: IconButtonProps['styles']\n prefix?: React.CSSProperties\n label?: React.CSSProperties\n suffix?: React.CSSProperties\n children?: React.CSSProperties\n }\n prefix?: React.ReactNode\n label?: React.ReactNode\n suffix?: React.ReactNode\n children?: React.ReactNode\n collapsable?: boolean\n collapsed?: boolean\n setCollapsed?: (collapsed: boolean) => void\n active?: boolean\n}\n\nexport const FileTreeFolder = React.forwardRef<HTMLDivElement, FileTreeFolderProps>(\n (\n {\n classNames,\n styles,\n collapsable = true,\n collapsed = true,\n setCollapsed: setCollapsedProp,\n prefix,\n label,\n suffix,\n active,\n children,\n ...props\n },\n ref\n ) => {\n const { global } = useNSUI()\n const [collapsedState, setCollapsedState] = useState(collapsed)\n\n useEffect(() => {\n setCollapsedState(collapsed)\n }, [collapsed])\n\n const isCollapsed = setCollapsedProp ? collapsed : collapsedState\n\n const handleCollapse = () => {\n const nextCollapsed = !isCollapsed\n\n setCollapsedState(nextCollapsed)\n setCollapsedProp?.(nextCollapsed)\n }\n\n return (\n <Flex\n ref={ref}\n direction=\"column\"\n className={cn(`${global?.prefixCls}-file-tree-folder`, classNames?.root)}\n data-active={active}\n style={styles?.root}\n {...props}\n >\n <Flex\n className={cn(`${global?.prefixCls}-file-tree-folder-header`, classNames?.header)}\n data-active={active}\n data-collapsed={isCollapsed}\n style={styles?.header}\n >\n {collapsable && (\n <IconButton\n classNames={classNames?.collapseButton}\n data-collapsed={isCollapsed}\n styles={styles?.collapseButton}\n onClick={handleCollapse}\n >\n <ChevronDown\n style={{\n transform: isCollapsed ? 'rotate(-90deg)' : '',\n ...styles?.collapseButton?.icon\n }}\n />\n </IconButton>\n )}\n\n {prefix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-prefix`, classNames?.prefix)}\n style={styles?.prefix}\n >\n {prefix}\n </div>\n )}\n\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-label`, classNames?.label)}\n style={styles?.label}\n >\n {label}\n </div>\n\n {suffix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-suffix`, classNames?.suffix)}\n style={styles?.suffix}\n >\n {suffix}\n </div>\n )}\n </Flex>\n\n {!isCollapsed && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-folder-children`, classNames?.children)}\n style={styles?.children}\n >\n {children}\n </div>\n )}\n </Flex>\n )\n }\n)\n\nFileTreeFolder.displayName = 'FileTreeFolder'\n","import { Flex, type FlexProps } from '@negative-space/flex'\nimport { cn, useNSUI } from '@negative-space/system'\nimport React from 'react'\n\nexport interface FileTreeItemProps extends Omit<\n FlexProps,\n 'children' | 'className' | 'style' | 'prefix'\n> {\n classNames?: {\n root?: string\n prefix?: string\n label?: string\n suffix?: string\n }\n styles?: {\n root?: React.CSSProperties\n prefix?: React.CSSProperties\n label?: React.CSSProperties\n suffix?: React.CSSProperties\n }\n prefix?: React.ReactNode\n label?: React.ReactNode\n suffix?: React.ReactNode\n active?: boolean\n}\n\nexport const FileTreeItem = React.forwardRef<HTMLDivElement, FileTreeItemProps>(\n ({ classNames, styles, prefix, label, suffix, active, ...props }, ref) => {\n const { global } = useNSUI()\n\n return (\n <Flex\n ref={ref}\n className={cn(`${global?.prefixCls}-file-tree-item`, classNames?.root)}\n data-active={active}\n style={styles?.root}\n {...props}\n >\n {prefix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-item-prefix`, classNames?.prefix)}\n style={styles?.prefix}\n >\n {prefix}\n </div>\n )}\n\n <div\n className={cn(`${global?.prefixCls}-file-tree-item-label`, classNames?.label)}\n style={styles?.label}\n >\n {label}\n </div>\n\n {suffix && (\n <div\n className={cn(`${global?.prefixCls}-file-tree-item-suffix`, classNames?.suffix)}\n style={styles?.suffix}\n >\n {suffix}\n </div>\n )}\n </Flex>\n )\n }\n)\n\nFileTreeItem.displayName = 'FileTreeItem'\n","import { Flex, type FlexProps } from '@negative-space/flex'\nimport { cn, useNSUI } from '@negative-space/system'\nimport React from 'react'\n\nimport { FileTreeFolder, type FileTreeFolderProps } from './FileTreeFolder'\nimport { FileTreeItem, type FileTreeItemProps } from './FileTreeItem'\n\nexport type FileTreeEntry =\n | {\n folder: Omit<FileTreeFolderProps, 'children'>\n items?: FileTreeEntry[]\n item?: never\n }\n | {\n item: FileTreeItemProps\n folder?: never\n items?: never\n }\n\nexport interface FileTreeProps extends Omit<FlexProps, 'children'> {\n classNames?: {\n root?: string\n folders?: FileTreeFolderProps['classNames']\n items?: FileTreeItemProps['classNames']\n }\n styles?: {\n root?: React.CSSProperties\n folders?: FileTreeFolderProps['styles']\n items?: FileTreeItemProps['styles']\n }\n items?: FileTreeEntry[]\n}\n\nexport const FileTree = React.forwardRef<HTMLDivElement, FileTreeProps>(\n ({ className, classNames, styles, items = [], ...props }, ref) => {\n const { global } = useNSUI()\n\n const renderEntries = (entries: FileTreeEntry[]) =>\n entries.map((entry, index) => {\n if (entry.folder) {\n return (\n <FileTreeFolder\n key={index}\n {...entry.folder}\n classNames={{\n ...classNames?.folders,\n ...entry.folder.classNames\n }}\n styles={{\n ...styles?.folders,\n ...entry.folder.styles\n }}\n >\n {entry.items && renderEntries(entry.items)}\n </FileTreeFolder>\n )\n }\n\n return (\n <FileTreeItem\n key={index}\n {...entry.item}\n classNames={{\n ...classNames?.items,\n ...entry.item.classNames\n }}\n styles={{\n ...styles?.items,\n ...entry.item.styles\n }}\n />\n )\n })\n\n return (\n <Flex\n ref={ref}\n direction=\"column\"\n className={cn(`${global?.prefixCls}-file-tree`, className, classNames?.root)}\n style={styles?.root}\n {...props}\n >\n {renderEntries(items)}\n </Flex>\n )\n }\n)\n\nFileTree.displayName = 'FileTree'\n"]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@negative-space/file-tree",
3
+ "version": "1.0.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "A lightweight and flexible file tree component for React",
8
+ "keywords": [
9
+ "components",
10
+ "file-tree",
11
+ "navigation",
12
+ "negative-space",
13
+ "nsui",
14
+ "react",
15
+ "ui"
16
+ ],
17
+ "license": "MIT",
18
+ "main": "dist/index.js",
19
+ "module": "dist/index.mjs",
20
+ "types": "dist/index.d.ts",
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/negative-space-ui/nsui",
27
+ "directory": "packages/ui/file-tree"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/negative-space-ui/nsui/issues"
31
+ },
32
+ "dependencies": {
33
+ "@negative-space/button": "2.9.3",
34
+ "@negative-space/flex": "1.3.2",
35
+ "@negative-space/system": "1.5.2"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "^19.2.3"
39
+ },
40
+ "clean-package": "../../../../clean-package.config.json",
41
+ "scripts": {
42
+ "build": "tsup",
43
+ "clean": "rimraf dist .turbo dist"
44
+ }
45
+ }