@floegence/floe-webapp-core 0.35.36 → 0.35.38
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/dist/components/ui/DirectoryInput.d.ts +4 -1
- package/dist/components/ui/DirectoryInput.js +34 -29
- package/dist/components/ui/DirectoryPicker.js +23 -12
- package/dist/components/ui/FileSavePicker.js +56 -48
- package/dist/components/ui/index.d.ts +1 -1
- package/dist/components/ui/picker/PickerBase.d.ts +29 -2
- package/dist/components/ui/picker/PickerBase.js +353 -234
- package/dist/styles.css +1 -1
- package/dist/ui.css +137 -124
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PickerEnsurePath } from './picker/PickerBase';
|
|
1
2
|
import type { FileItem } from '../file-browser/types';
|
|
2
3
|
export type DirectoryInputSize = 'sm' | 'md' | 'lg';
|
|
3
4
|
export interface DirectoryInputProps {
|
|
@@ -8,7 +9,9 @@ export interface DirectoryInputProps {
|
|
|
8
9
|
/** File tree data for the picker */
|
|
9
10
|
files: FileItem[];
|
|
10
11
|
/** Callback to load directory contents (for lazy loading) */
|
|
11
|
-
onExpand?: (path: string) => void
|
|
12
|
+
onExpand?: (path: string) => void | Promise<void>;
|
|
13
|
+
/** Async resolver that guarantees a target path exists in the current tree snapshot. */
|
|
14
|
+
ensurePath?: PickerEnsurePath;
|
|
12
15
|
/** Placeholder text when no directory is selected */
|
|
13
16
|
placeholder?: string;
|
|
14
17
|
/** Optional home directory path for display */
|
|
@@ -2,9 +2,9 @@ import { insert as o, createComponent as a, memo as k, effect as y, className as
|
|
|
2
2
|
import { splitProps as $, createSignal as C, createEffect as f, on as _, Show as g } from "solid-js";
|
|
3
3
|
import { cn as u } from "../../utils/cn.js";
|
|
4
4
|
import { usePickerTree as T, PickerBreadcrumb as F, PickerFolderTree as L } from "./picker/PickerBase.js";
|
|
5
|
-
import { Folder as z, ChevronRight as
|
|
6
|
-
var
|
|
7
|
-
const
|
|
5
|
+
import { Folder as z, ChevronRight as N } from "../icons/index.js";
|
|
6
|
+
var R = /* @__PURE__ */ c('<div class="border border-input rounded-b-md overflow-hidden bg-background shadow-sm border-t-0"><div class="px-2 py-1 border-b border-border/50 bg-muted/30">'), B = /* @__PURE__ */ c('<p class="mt-1 text-[11px] text-error"role=alert>'), D = /* @__PURE__ */ c('<p class="mt-1 text-[11px] text-muted-foreground">'), H = /* @__PURE__ */ c("<div><button type=button><span>");
|
|
7
|
+
const M = {
|
|
8
8
|
sm: {
|
|
9
9
|
container: "h-7 px-2",
|
|
10
10
|
icon: "w-3.5 h-3.5",
|
|
@@ -22,75 +22,80 @@ const I = {
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
function A(b) {
|
|
25
|
-
const [e] = $(b, ["value", "onChange", "files", "onExpand", "placeholder", "homePath", "homeLabel", "initialPath", "disabled", "size", "error", "helperText", "class", "treeMaxHeight", "defaultExpanded"]), [d, v] = C(e.defaultExpanded !== !1), P = () => e.size ?? "md", i = () =>
|
|
25
|
+
const [e] = $(b, ["value", "onChange", "files", "onExpand", "ensurePath", "placeholder", "homePath", "homeLabel", "initialPath", "disabled", "size", "error", "helperText", "class", "treeMaxHeight", "defaultExpanded"]), [d, v] = C(e.defaultExpanded !== !1), P = () => e.size ?? "md", i = () => M[P()];
|
|
26
26
|
f(() => {
|
|
27
27
|
d() && e.files.length === 0 && e.onExpand && e.onExpand("/");
|
|
28
28
|
});
|
|
29
|
-
const
|
|
29
|
+
const r = T({
|
|
30
30
|
initialPath: () => e.initialPath ?? "/",
|
|
31
31
|
open: () => !0,
|
|
32
32
|
files: () => e.files,
|
|
33
|
-
onExpand: (
|
|
33
|
+
onExpand: (n) => e.onExpand?.(n),
|
|
34
|
+
// eslint-disable-next-line solid/reactivity -- ensurePath is a static callback
|
|
35
|
+
ensurePath: e.ensurePath,
|
|
34
36
|
homeLabel: () => e.homeLabel,
|
|
35
37
|
homePath: () => e.homePath
|
|
36
38
|
});
|
|
37
|
-
f(_(
|
|
39
|
+
f(_(r.selectedPath, (n) => {
|
|
38
40
|
if (!d()) return;
|
|
39
|
-
const l =
|
|
41
|
+
const l = r.toDisplayPath(n);
|
|
40
42
|
e.onChange?.(l);
|
|
41
43
|
}));
|
|
42
44
|
const E = () => {
|
|
43
45
|
if (e.disabled) return;
|
|
44
|
-
const
|
|
45
|
-
!
|
|
46
|
+
const n = d();
|
|
47
|
+
!n && e.files.length === 0 && e.onExpand && e.onExpand("/"), v(!n);
|
|
46
48
|
}, w = () => e.value ? e.homePath && e.value.startsWith(e.homePath) ? "~" + (e.value.slice(e.homePath.length) || "") : e.value : null;
|
|
47
49
|
return (() => {
|
|
48
|
-
var
|
|
50
|
+
var n = H(), l = n.firstChild, h = l.firstChild;
|
|
49
51
|
return l.$$click = E, o(l, a(z, {
|
|
50
52
|
get class() {
|
|
51
53
|
return u("text-muted-foreground flex-shrink-0", i().icon);
|
|
52
54
|
}
|
|
53
|
-
}), h), o(h, () => w() || e.placeholder || "Select a directory..."), o(l, a(
|
|
55
|
+
}), h), o(h, () => w() || e.placeholder || "Select a directory..."), o(l, a(N, {
|
|
54
56
|
get class() {
|
|
55
57
|
return u("text-muted-foreground flex-shrink-0 transition-transform duration-150", i().icon, d() && "rotate-90");
|
|
56
58
|
}
|
|
57
|
-
}), null), o(
|
|
59
|
+
}), null), o(n, a(g, {
|
|
58
60
|
get when() {
|
|
59
61
|
return d();
|
|
60
62
|
},
|
|
61
63
|
get children() {
|
|
62
|
-
var t =
|
|
64
|
+
var t = R(), s = t.firstChild;
|
|
63
65
|
return o(s, a(F, {
|
|
64
66
|
get segments() {
|
|
65
|
-
return
|
|
67
|
+
return r.breadcrumbSegments;
|
|
66
68
|
},
|
|
67
69
|
get onClick() {
|
|
68
|
-
return
|
|
70
|
+
return r.handleBreadcrumbClick;
|
|
69
71
|
}
|
|
70
72
|
})), o(t, a(L, {
|
|
71
73
|
get rootFolders() {
|
|
72
|
-
return
|
|
74
|
+
return r.rootFolders;
|
|
73
75
|
},
|
|
74
76
|
get selectedPath() {
|
|
75
|
-
return
|
|
77
|
+
return r.selectedPath;
|
|
76
78
|
},
|
|
77
79
|
get expandedPaths() {
|
|
78
|
-
return
|
|
80
|
+
return r.expandedPaths;
|
|
81
|
+
},
|
|
82
|
+
get revealNonce() {
|
|
83
|
+
return r.revealNonce;
|
|
79
84
|
},
|
|
80
85
|
get onToggle() {
|
|
81
|
-
return
|
|
86
|
+
return r.toggleExpand;
|
|
82
87
|
},
|
|
83
88
|
get onSelect() {
|
|
84
|
-
return
|
|
89
|
+
return r.handleSelectFolder;
|
|
85
90
|
},
|
|
86
91
|
get onSelectRoot() {
|
|
87
|
-
return
|
|
92
|
+
return r.handleSelectRoot;
|
|
88
93
|
},
|
|
89
94
|
get isSelectable() {
|
|
90
|
-
return
|
|
95
|
+
return r.isSelectable;
|
|
91
96
|
},
|
|
92
97
|
get homeLabel() {
|
|
93
|
-
return
|
|
98
|
+
return r.homeLabel;
|
|
94
99
|
},
|
|
95
100
|
class: "border-0 rounded-none",
|
|
96
101
|
get style() {
|
|
@@ -100,20 +105,20 @@ function A(b) {
|
|
|
100
105
|
}
|
|
101
106
|
}), null), t;
|
|
102
107
|
}
|
|
103
|
-
}), null), o(
|
|
108
|
+
}), null), o(n, a(g, {
|
|
104
109
|
get when() {
|
|
105
110
|
return e.error;
|
|
106
111
|
},
|
|
107
112
|
get children() {
|
|
108
|
-
var t =
|
|
113
|
+
var t = B();
|
|
109
114
|
return o(t, () => e.error), t;
|
|
110
115
|
}
|
|
111
|
-
}), null), o(
|
|
116
|
+
}), null), o(n, a(g, {
|
|
112
117
|
get when() {
|
|
113
118
|
return k(() => !!e.helperText)() && !e.error;
|
|
114
119
|
},
|
|
115
120
|
get children() {
|
|
116
|
-
var t =
|
|
121
|
+
var t = D();
|
|
117
122
|
return o(t, () => e.helperText), t;
|
|
118
123
|
}
|
|
119
124
|
}), null), y((t) => {
|
|
@@ -123,7 +128,7 @@ function A(b) {
|
|
|
123
128
|
e: void 0,
|
|
124
129
|
t: void 0,
|
|
125
130
|
a: void 0
|
|
126
|
-
}),
|
|
131
|
+
}), n;
|
|
127
132
|
})();
|
|
128
133
|
}
|
|
129
134
|
S(["click"]);
|
|
@@ -3,11 +3,11 @@ import { Show as d } from "solid-js";
|
|
|
3
3
|
import { cn as m } from "../../utils/cn.js";
|
|
4
4
|
import { Dialog as s } from "./Dialog.js";
|
|
5
5
|
import { Button as o } from "./Button.js";
|
|
6
|
-
import { deferNonBlocking as
|
|
7
|
-
import { usePickerTree as
|
|
8
|
-
var b = /* @__PURE__ */ i('<div class="flex flex-col gap-2 -mt-1">'),
|
|
6
|
+
import { deferNonBlocking as P } from "../../utils/defer.js";
|
|
7
|
+
import { usePickerTree as f, PathInputBar as x, PickerBreadcrumb as C, PickerFolderTree as p, NewFolderSection as S } from "./picker/PickerBase.js";
|
|
8
|
+
var b = /* @__PURE__ */ i('<div class="flex flex-col gap-2 -mt-1">'), v = /* @__PURE__ */ i('<div class="flex items-center w-full gap-2"><span class="flex-1 text-[11px] text-muted-foreground truncate">');
|
|
9
9
|
function E(t) {
|
|
10
|
-
const e =
|
|
10
|
+
const e = f({
|
|
11
11
|
initialPath: () => t.initialPath,
|
|
12
12
|
open: () => t.open,
|
|
13
13
|
files: () => t.files,
|
|
@@ -15,12 +15,14 @@ function E(t) {
|
|
|
15
15
|
filter: t.filter ? (n) => t.filter(n) : void 0,
|
|
16
16
|
// eslint-disable-next-line solid/reactivity -- onExpand is a static callback
|
|
17
17
|
onExpand: t.onExpand,
|
|
18
|
+
// eslint-disable-next-line solid/reactivity -- ensurePath is a static callback
|
|
19
|
+
ensurePath: t.ensurePath,
|
|
18
20
|
homeLabel: () => t.homeLabel,
|
|
19
21
|
homePath: () => t.homePath
|
|
20
|
-
}),
|
|
22
|
+
}), u = () => {
|
|
21
23
|
const n = e.selectedPath(), a = t.onSelect;
|
|
22
|
-
t.onOpenChange(!1),
|
|
23
|
-
},
|
|
24
|
+
t.onOpenChange(!1), P(() => a(n));
|
|
25
|
+
}, c = () => {
|
|
24
26
|
t.onOpenChange(!1);
|
|
25
27
|
};
|
|
26
28
|
return r(s, {
|
|
@@ -38,18 +40,21 @@ function E(t) {
|
|
|
38
40
|
},
|
|
39
41
|
get footer() {
|
|
40
42
|
return (() => {
|
|
41
|
-
var n =
|
|
43
|
+
var n = v(), a = n.firstChild;
|
|
42
44
|
return l(a, () => e.toDisplayPath(e.selectedPath())), l(n, r(o, {
|
|
43
45
|
variant: "ghost",
|
|
44
46
|
size: "sm",
|
|
45
|
-
onClick:
|
|
47
|
+
onClick: c,
|
|
46
48
|
get children() {
|
|
47
49
|
return t.cancelText ?? "Cancel";
|
|
48
50
|
}
|
|
49
51
|
}), null), l(n, r(o, {
|
|
50
52
|
variant: "primary",
|
|
51
53
|
size: "sm",
|
|
52
|
-
onClick:
|
|
54
|
+
onClick: u,
|
|
55
|
+
get disabled() {
|
|
56
|
+
return e.pathPending();
|
|
57
|
+
},
|
|
53
58
|
get children() {
|
|
54
59
|
return t.confirmText ?? "Select";
|
|
55
60
|
}
|
|
@@ -65,6 +70,9 @@ function E(t) {
|
|
|
65
70
|
onInput: (a) => {
|
|
66
71
|
e.setPathInput(a), e.setPathInputError("");
|
|
67
72
|
},
|
|
73
|
+
get pending() {
|
|
74
|
+
return e.pathPending;
|
|
75
|
+
},
|
|
68
76
|
get error() {
|
|
69
77
|
return e.pathInputError;
|
|
70
78
|
},
|
|
@@ -81,7 +89,7 @@ function E(t) {
|
|
|
81
89
|
get onClick() {
|
|
82
90
|
return e.handleBreadcrumbClick;
|
|
83
91
|
}
|
|
84
|
-
}), null), l(n, r(
|
|
92
|
+
}), null), l(n, r(p, {
|
|
85
93
|
get rootFolders() {
|
|
86
94
|
return e.rootFolders;
|
|
87
95
|
},
|
|
@@ -91,6 +99,9 @@ function E(t) {
|
|
|
91
99
|
get expandedPaths() {
|
|
92
100
|
return e.expandedPaths;
|
|
93
101
|
},
|
|
102
|
+
get revealNonce() {
|
|
103
|
+
return e.revealNonce;
|
|
104
|
+
},
|
|
94
105
|
get onToggle() {
|
|
95
106
|
return e.toggleExpand;
|
|
96
107
|
},
|
|
@@ -115,7 +126,7 @@ function E(t) {
|
|
|
115
126
|
return t.onCreateFolder;
|
|
116
127
|
},
|
|
117
128
|
get children() {
|
|
118
|
-
return r(
|
|
129
|
+
return r(S, {
|
|
119
130
|
get parentPath() {
|
|
120
131
|
return e.selectedPath;
|
|
121
132
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createComponent as i, insert as a, effect as b, className as
|
|
1
|
+
import { createComponent as i, insert as a, effect as b, className as N, setAttribute as y, template as h, delegateEvents as I } from "solid-js/web";
|
|
2
2
|
import { createSignal as F, createMemo as $, createEffect as E, on as D, Show as g, For as B } from "solid-js";
|
|
3
3
|
import { cn as p } from "../../utils/cn.js";
|
|
4
4
|
import { Dialog as z } from "./Dialog.js";
|
|
@@ -7,55 +7,57 @@ import { Input as T } from "./Input.js";
|
|
|
7
7
|
import { FileItemIcon as K } from "../file-browser/FileIcons.js";
|
|
8
8
|
import { deferNonBlocking as L } from "../../utils/defer.js";
|
|
9
9
|
import { usePickerTree as O, normalizePath as R, PathInputBar as G, PickerBreadcrumb as M, PickerFolderTree as j, NewFolderSection as q } from "./picker/PickerBase.js";
|
|
10
|
-
var A = /* @__PURE__ */
|
|
10
|
+
var A = /* @__PURE__ */ h('<div class="flex flex-col gap-2 -mt-1"><div class="flex border border-border rounded overflow-hidden"style=height:260px><div class="w-1/2 min-w-0 overflow-y-auto">'), H = /* @__PURE__ */ h('<div class="flex flex-col w-full gap-2"><div class="flex items-center gap-1.5"><label class="text-xs text-muted-foreground flex-shrink-0">File name:</label><div class=flex-1></div></div><div class="flex items-center gap-2"><span class="flex-1 text-[11px] text-muted-foreground truncate">'), J = /* @__PURE__ */ h('<div class="flex items-center justify-center h-full text-xs text-muted-foreground">No files in this directory'), Q = /* @__PURE__ */ h('<span class="ml-auto text-[10px] text-muted-foreground/60 flex-shrink-0">'), U = /* @__PURE__ */ h("<button type=button><span class=truncate>");
|
|
11
11
|
function ie(e) {
|
|
12
|
-
const [u, f] = F(e.initialFileName ?? ""), [w, s] = F(""),
|
|
12
|
+
const [u, f] = F(e.initialFileName ?? ""), [w, s] = F(""), t = O({
|
|
13
13
|
initialPath: () => e.initialPath,
|
|
14
14
|
open: () => e.open,
|
|
15
15
|
files: () => e.files,
|
|
16
16
|
// eslint-disable-next-line solid/reactivity -- filter is a static callback
|
|
17
|
-
filter: e.filter ? (
|
|
17
|
+
filter: e.filter ? (r) => e.filter(r) : void 0,
|
|
18
18
|
// eslint-disable-next-line solid/reactivity -- onExpand is a static callback
|
|
19
19
|
onExpand: e.onExpand,
|
|
20
|
+
// eslint-disable-next-line solid/reactivity -- ensurePath is a static callback
|
|
21
|
+
ensurePath: e.ensurePath,
|
|
20
22
|
homeLabel: () => e.homeLabel,
|
|
21
23
|
homePath: () => e.homePath,
|
|
22
24
|
onReset: () => {
|
|
23
25
|
f(e.initialFileName ?? ""), s("");
|
|
24
26
|
}
|
|
25
27
|
}), x = $(() => {
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
+
const r = R(t.selectedPath());
|
|
29
|
+
if (r === "/")
|
|
28
30
|
return e.files.filter((o) => o.type === "file");
|
|
29
|
-
const n =
|
|
31
|
+
const n = t.folderIndex().get(r);
|
|
30
32
|
return n?.children ? n.children.filter((o) => o.type === "file") : [];
|
|
31
33
|
});
|
|
32
34
|
E(D(u, () => {
|
|
33
35
|
s("");
|
|
34
36
|
}));
|
|
35
|
-
const S = (
|
|
36
|
-
f(
|
|
37
|
+
const S = (r) => {
|
|
38
|
+
f(r.name), s("");
|
|
37
39
|
}, v = () => {
|
|
38
|
-
const
|
|
39
|
-
if (!
|
|
40
|
+
const r = u().trim();
|
|
41
|
+
if (!r) {
|
|
40
42
|
s("Filename is required");
|
|
41
43
|
return;
|
|
42
44
|
}
|
|
43
45
|
if (e.validateFileName) {
|
|
44
|
-
const l = e.validateFileName(
|
|
46
|
+
const l = e.validateFileName(r);
|
|
45
47
|
if (l) {
|
|
46
48
|
s(l);
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
|
-
const n =
|
|
51
|
-
e.onOpenChange(!1), L(() => o(n,
|
|
52
|
+
const n = t.selectedPath(), o = e.onSave;
|
|
53
|
+
e.onOpenChange(!1), L(() => o(n, r));
|
|
52
54
|
}, k = () => {
|
|
53
55
|
e.onOpenChange(!1);
|
|
54
|
-
}, _ = (
|
|
55
|
-
|
|
56
|
+
}, _ = (r) => {
|
|
57
|
+
r.key === "Enter" && (r.preventDefault(), v());
|
|
56
58
|
}, P = $(() => {
|
|
57
|
-
const
|
|
58
|
-
return n ?
|
|
59
|
+
const r = t.toDisplayPath(t.selectedPath()), n = u().trim();
|
|
60
|
+
return n ? r === "/" ? `/${n}` : `${r}/${n}` : r;
|
|
59
61
|
});
|
|
60
62
|
return i(z, {
|
|
61
63
|
get open() {
|
|
@@ -72,13 +74,13 @@ function ie(e) {
|
|
|
72
74
|
},
|
|
73
75
|
get footer() {
|
|
74
76
|
return (() => {
|
|
75
|
-
var
|
|
77
|
+
var r = H(), n = r.firstChild, o = n.firstChild, l = o.nextSibling, c = n.nextSibling, d = c.firstChild;
|
|
76
78
|
return a(l, i(T, {
|
|
77
79
|
size: "sm",
|
|
78
80
|
get value() {
|
|
79
81
|
return u();
|
|
80
82
|
},
|
|
81
|
-
onInput: (
|
|
83
|
+
onInput: (m) => f(m.currentTarget.value),
|
|
82
84
|
onKeyDown: _,
|
|
83
85
|
placeholder: "filename.ext",
|
|
84
86
|
get error() {
|
|
@@ -96,63 +98,69 @@ function ie(e) {
|
|
|
96
98
|
size: "sm",
|
|
97
99
|
onClick: v,
|
|
98
100
|
get disabled() {
|
|
99
|
-
return !u().trim();
|
|
101
|
+
return !u().trim() || t.pathPending();
|
|
100
102
|
},
|
|
101
103
|
get children() {
|
|
102
104
|
return e.confirmText ?? "Save";
|
|
103
105
|
}
|
|
104
|
-
}), null), b(() =>
|
|
106
|
+
}), null), b(() => y(d, "title", P())), r;
|
|
105
107
|
})();
|
|
106
108
|
},
|
|
107
109
|
get children() {
|
|
108
|
-
var
|
|
109
|
-
return a(
|
|
110
|
+
var r = A(), n = r.firstChild, o = n.firstChild;
|
|
111
|
+
return a(r, i(G, {
|
|
110
112
|
get value() {
|
|
111
|
-
return
|
|
113
|
+
return t.pathInput;
|
|
112
114
|
},
|
|
113
115
|
onInput: (l) => {
|
|
114
|
-
|
|
116
|
+
t.setPathInput(l), t.setPathInputError("");
|
|
117
|
+
},
|
|
118
|
+
get pending() {
|
|
119
|
+
return t.pathPending;
|
|
115
120
|
},
|
|
116
121
|
get error() {
|
|
117
|
-
return
|
|
122
|
+
return t.pathInputError;
|
|
118
123
|
},
|
|
119
124
|
get onGo() {
|
|
120
|
-
return
|
|
125
|
+
return t.handlePathInputGo;
|
|
121
126
|
},
|
|
122
127
|
get onKeyDown() {
|
|
123
|
-
return
|
|
128
|
+
return t.handlePathInputKeyDown;
|
|
124
129
|
}
|
|
125
|
-
}), n), a(
|
|
130
|
+
}), n), a(r, i(M, {
|
|
126
131
|
get segments() {
|
|
127
|
-
return
|
|
132
|
+
return t.breadcrumbSegments;
|
|
128
133
|
},
|
|
129
134
|
get onClick() {
|
|
130
|
-
return
|
|
135
|
+
return t.handleBreadcrumbClick;
|
|
131
136
|
}
|
|
132
137
|
}), n), a(n, i(j, {
|
|
133
138
|
get rootFolders() {
|
|
134
|
-
return
|
|
139
|
+
return t.rootFolders;
|
|
135
140
|
},
|
|
136
141
|
get selectedPath() {
|
|
137
|
-
return
|
|
142
|
+
return t.selectedPath;
|
|
138
143
|
},
|
|
139
144
|
get expandedPaths() {
|
|
140
|
-
return
|
|
145
|
+
return t.expandedPaths;
|
|
146
|
+
},
|
|
147
|
+
get revealNonce() {
|
|
148
|
+
return t.revealNonce;
|
|
141
149
|
},
|
|
142
150
|
get onToggle() {
|
|
143
|
-
return
|
|
151
|
+
return t.toggleExpand;
|
|
144
152
|
},
|
|
145
153
|
get onSelect() {
|
|
146
|
-
return
|
|
154
|
+
return t.handleSelectFolder;
|
|
147
155
|
},
|
|
148
156
|
get onSelectRoot() {
|
|
149
|
-
return
|
|
157
|
+
return t.handleSelectRoot;
|
|
150
158
|
},
|
|
151
159
|
get isSelectable() {
|
|
152
|
-
return
|
|
160
|
+
return t.isSelectable;
|
|
153
161
|
},
|
|
154
162
|
get homeLabel() {
|
|
155
|
-
return
|
|
163
|
+
return t.homeLabel;
|
|
156
164
|
},
|
|
157
165
|
class: "w-1/2 min-w-0 border-r border-border border-0 rounded-none",
|
|
158
166
|
style: {
|
|
@@ -181,38 +189,38 @@ function ie(e) {
|
|
|
181
189
|
return l.size != null;
|
|
182
190
|
},
|
|
183
191
|
get children() {
|
|
184
|
-
var
|
|
185
|
-
return a(
|
|
192
|
+
var m = Q();
|
|
193
|
+
return a(m, () => V(l.size)), m;
|
|
186
194
|
}
|
|
187
|
-
}), null), b(() =>
|
|
195
|
+
}), null), b(() => N(c, p("flex items-center gap-1.5 w-full text-left text-xs py-1.5 px-2 cursor-pointer", "transition-colors duration-100", "hover:bg-accent/60", "focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring", u() === l.name && "bg-accent text-accent-foreground font-medium"))), c;
|
|
188
196
|
})()
|
|
189
197
|
});
|
|
190
198
|
}
|
|
191
|
-
})), a(
|
|
199
|
+
})), a(r, i(g, {
|
|
192
200
|
get when() {
|
|
193
201
|
return e.onCreateFolder;
|
|
194
202
|
},
|
|
195
203
|
get children() {
|
|
196
204
|
return i(q, {
|
|
197
205
|
get parentPath() {
|
|
198
|
-
return
|
|
206
|
+
return t.selectedPath;
|
|
199
207
|
},
|
|
200
208
|
get onCreateFolder() {
|
|
201
209
|
return e.onCreateFolder;
|
|
202
210
|
},
|
|
203
211
|
get toDisplayPath() {
|
|
204
|
-
return
|
|
212
|
+
return t.toDisplayPath;
|
|
205
213
|
}
|
|
206
214
|
});
|
|
207
215
|
}
|
|
208
|
-
}), null),
|
|
216
|
+
}), null), r;
|
|
209
217
|
}
|
|
210
218
|
});
|
|
211
219
|
}
|
|
212
220
|
function V(e) {
|
|
213
221
|
return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : `${(e / (1024 * 1024)).toFixed(1)} MB`;
|
|
214
222
|
}
|
|
215
|
-
|
|
223
|
+
I(["click"]);
|
|
216
224
|
export {
|
|
217
225
|
ie as FileSavePicker
|
|
218
226
|
};
|
|
@@ -11,7 +11,7 @@ export { Tabs, TabPanel, type TabsProps, type TabPanelProps, type TabItem, type
|
|
|
11
11
|
export { DirectoryPicker, type DirectoryPickerProps } from './DirectoryPicker';
|
|
12
12
|
export { DirectoryInput, type DirectoryInputProps, type DirectoryInputSize, } from './DirectoryInput';
|
|
13
13
|
export { FileSavePicker, type FileSavePickerProps } from './FileSavePicker';
|
|
14
|
-
export { type BasePickerProps } from './picker/PickerBase';
|
|
14
|
+
export { type BasePickerProps, type PickerEnsurePath, type PickerEnsurePathOptions, type PickerPathResolveResult, type PickerPathResolveStatus, type PickerPathNavigateReason, } from './picker/PickerBase';
|
|
15
15
|
export { QuoteBlock, type QuoteBlockProps } from './QuoteBlock';
|
|
16
16
|
export { HighlightBlock, InfoBlock, WarningBlock, SuccessBlock, ErrorBlock, NoteBlock, TipBlock, type HighlightBlockProps, type HighlightVariant, } from './HighlightBlock';
|
|
17
17
|
export { ProcessingIndicator, type ProcessingIndicatorProps, type ProcessingIndicatorVariant, type ProcessingIndicatorStatus, } from './ProcessingIndicator';
|
|
@@ -33,7 +33,13 @@ export interface BasePickerProps {
|
|
|
33
33
|
* Use this to dynamically load children for the expanded directory.
|
|
34
34
|
* The path parameter is the internal tree path (not the display path).
|
|
35
35
|
*/
|
|
36
|
-
onExpand?: (path: string) => void
|
|
36
|
+
onExpand?: (path: string) => void | Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Async resolver used when a navigation target may exist outside the current
|
|
39
|
+
* in-memory tree snapshot. A ready result guarantees the target path and its
|
|
40
|
+
* ancestor chain are now represented in `files`.
|
|
41
|
+
*/
|
|
42
|
+
ensurePath?: PickerEnsurePath;
|
|
37
43
|
/** Filter which directories are selectable (return false to grey-out) */
|
|
38
44
|
filter?: (item: FileItem) => boolean;
|
|
39
45
|
/** Label for the home/root directory (default: 'Root') */
|
|
@@ -67,7 +73,9 @@ export interface UsePickerTreeOptions {
|
|
|
67
73
|
* Callback when user expands a directory.
|
|
68
74
|
* Use this to dynamically load children for the expanded directory.
|
|
69
75
|
*/
|
|
70
|
-
onExpand?: (path: string) => void
|
|
76
|
+
onExpand?: (path: string) => void | Promise<void>;
|
|
77
|
+
/** Async resolver that ensures a target path exists in the current tree snapshot. */
|
|
78
|
+
ensurePath?: PickerEnsurePath;
|
|
71
79
|
/** Label for the home/root directory in tree and breadcrumb (default: 'Root'). Supports accessor for reactivity. */
|
|
72
80
|
homeLabel?: string | Accessor<string | undefined>;
|
|
73
81
|
/**
|
|
@@ -84,6 +92,7 @@ export interface PickerTreeState {
|
|
|
84
92
|
toggleExpand: (path: string) => void;
|
|
85
93
|
pathInput: Accessor<string>;
|
|
86
94
|
setPathInput: (value: string) => void;
|
|
95
|
+
pathPending: Accessor<boolean>;
|
|
87
96
|
pathInputError: Accessor<string>;
|
|
88
97
|
setPathInputError: (value: string) => void;
|
|
89
98
|
folderIndex: Accessor<Map<string, FileItem>>;
|
|
@@ -95,6 +104,7 @@ export interface PickerTreeState {
|
|
|
95
104
|
handlePathInputGo: () => void;
|
|
96
105
|
handlePathInputKeyDown: (e: KeyboardEvent) => void;
|
|
97
106
|
expandToPath: (path: string) => void;
|
|
107
|
+
navigateToPath: (path: string, options: PickerEnsurePathOptions) => Promise<PickerPathResolveResult>;
|
|
98
108
|
breadcrumbSegments: Accessor<{
|
|
99
109
|
name: string;
|
|
100
110
|
path: string;
|
|
@@ -104,7 +114,20 @@ export interface PickerTreeState {
|
|
|
104
114
|
homeLabel: Accessor<string>;
|
|
105
115
|
/** Convert internal tree path to display (real filesystem) path */
|
|
106
116
|
toDisplayPath: (internalPath: string) => string;
|
|
117
|
+
/** Monotonic counter used to reveal the selected row after async navigation. */
|
|
118
|
+
revealNonce: Accessor<number>;
|
|
119
|
+
}
|
|
120
|
+
export type PickerPathResolveStatus = 'ready' | 'missing' | 'error';
|
|
121
|
+
export type PickerPathNavigateReason = 'open' | 'path-input' | 'tree-expand' | 'tree-select' | 'breadcrumb';
|
|
122
|
+
export interface PickerEnsurePathOptions {
|
|
123
|
+
reason: PickerPathNavigateReason;
|
|
124
|
+
}
|
|
125
|
+
export interface PickerPathResolveResult {
|
|
126
|
+
status: PickerPathResolveStatus;
|
|
127
|
+
resolvedPath: string;
|
|
128
|
+
message?: string;
|
|
107
129
|
}
|
|
130
|
+
export type PickerEnsurePath = (path: string, options: PickerEnsurePathOptions) => PickerPathResolveResult | Promise<PickerPathResolveResult>;
|
|
108
131
|
export declare function resolvePickerInitialPath(initialPath: string | undefined, homePath: string | undefined): string;
|
|
109
132
|
export declare function usePickerTree(opts: UsePickerTreeOptions): PickerTreeState;
|
|
110
133
|
export interface NewFolderSectionProps {
|
|
@@ -117,6 +140,7 @@ export declare function NewFolderSection(props: NewFolderSectionProps): JSX.Elem
|
|
|
117
140
|
export interface PathInputBarProps {
|
|
118
141
|
value: Accessor<string>;
|
|
119
142
|
onInput: (value: string) => void;
|
|
143
|
+
pending?: Accessor<boolean>;
|
|
120
144
|
error: Accessor<string>;
|
|
121
145
|
onGo: () => void;
|
|
122
146
|
onKeyDown: (e: KeyboardEvent) => void;
|
|
@@ -135,6 +159,7 @@ export interface PickerFolderTreeProps {
|
|
|
135
159
|
rootFolders: Accessor<FileItem[]>;
|
|
136
160
|
selectedPath: Accessor<string>;
|
|
137
161
|
expandedPaths: Accessor<Set<string>>;
|
|
162
|
+
revealNonce?: Accessor<number>;
|
|
138
163
|
onToggle: (path: string) => void;
|
|
139
164
|
onSelect: (item: FileItem) => void;
|
|
140
165
|
onSelectRoot: () => void;
|
|
@@ -151,8 +176,10 @@ export interface PickerTreeNodeProps {
|
|
|
151
176
|
depth: number;
|
|
152
177
|
selectedPath: Accessor<string>;
|
|
153
178
|
expandedPaths: Accessor<Set<string>>;
|
|
179
|
+
revealNonce?: Accessor<number>;
|
|
154
180
|
onToggle: (path: string) => void;
|
|
155
181
|
onSelect: (item: FileItem) => void;
|
|
156
182
|
isSelectable: (item: FileItem) => boolean;
|
|
183
|
+
registerRow: (path: string, el: HTMLButtonElement | null) => void;
|
|
157
184
|
}
|
|
158
185
|
export declare function PickerTreeNode(props: PickerTreeNodeProps): JSX.Element;
|