@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.
@@ -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 R } from "../icons/index.js";
6
- var B = /* @__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">'), D = /* @__PURE__ */ c('<p class="mt-1 text-[11px] text-error"role=alert>'), H = /* @__PURE__ */ c('<p class="mt-1 text-[11px] text-muted-foreground">'), M = /* @__PURE__ */ c("<div><button type=button><span>");
7
- const I = {
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 = () => I[P()];
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 n = T({
29
+ const r = T({
30
30
  initialPath: () => e.initialPath ?? "/",
31
31
  open: () => !0,
32
32
  files: () => e.files,
33
- onExpand: (r) => e.onExpand?.(r),
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(_(n.selectedPath, (r) => {
39
+ f(_(r.selectedPath, (n) => {
38
40
  if (!d()) return;
39
- const l = n.toDisplayPath(r);
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 r = d();
45
- !r && e.files.length === 0 && e.onExpand && e.onExpand("/"), v(!r);
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 r = M(), l = r.firstChild, h = l.firstChild;
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(R, {
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(r, a(g, {
59
+ }), null), o(n, a(g, {
58
60
  get when() {
59
61
  return d();
60
62
  },
61
63
  get children() {
62
- var t = B(), s = t.firstChild;
64
+ var t = R(), s = t.firstChild;
63
65
  return o(s, a(F, {
64
66
  get segments() {
65
- return n.breadcrumbSegments;
67
+ return r.breadcrumbSegments;
66
68
  },
67
69
  get onClick() {
68
- return n.handleBreadcrumbClick;
70
+ return r.handleBreadcrumbClick;
69
71
  }
70
72
  })), o(t, a(L, {
71
73
  get rootFolders() {
72
- return n.rootFolders;
74
+ return r.rootFolders;
73
75
  },
74
76
  get selectedPath() {
75
- return n.selectedPath;
77
+ return r.selectedPath;
76
78
  },
77
79
  get expandedPaths() {
78
- return n.expandedPaths;
80
+ return r.expandedPaths;
81
+ },
82
+ get revealNonce() {
83
+ return r.revealNonce;
79
84
  },
80
85
  get onToggle() {
81
- return n.toggleExpand;
86
+ return r.toggleExpand;
82
87
  },
83
88
  get onSelect() {
84
- return n.handleSelectFolder;
89
+ return r.handleSelectFolder;
85
90
  },
86
91
  get onSelectRoot() {
87
- return n.handleSelectRoot;
92
+ return r.handleSelectRoot;
88
93
  },
89
94
  get isSelectable() {
90
- return n.isSelectable;
95
+ return r.isSelectable;
91
96
  },
92
97
  get homeLabel() {
93
- return n.homeLabel;
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(r, a(g, {
108
+ }), null), o(n, a(g, {
104
109
  get when() {
105
110
  return e.error;
106
111
  },
107
112
  get children() {
108
- var t = D();
113
+ var t = B();
109
114
  return o(t, () => e.error), t;
110
115
  }
111
- }), null), o(r, a(g, {
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 = H();
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
- }), r;
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 f } from "../../utils/defer.js";
7
- import { usePickerTree as P, PathInputBar as x, PickerBreadcrumb as C, PickerFolderTree as S, NewFolderSection as p } from "./picker/PickerBase.js";
8
- var b = /* @__PURE__ */ i('<div class="flex flex-col gap-2 -mt-1">'), y = /* @__PURE__ */ i('<div class="flex items-center w-full gap-2"><span class="flex-1 text-[11px] text-muted-foreground truncate">');
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 = P({
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
- }), c = () => {
22
+ }), u = () => {
21
23
  const n = e.selectedPath(), a = t.onSelect;
22
- t.onOpenChange(!1), f(() => a(n));
23
- }, u = () => {
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 = y(), a = n.firstChild;
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: u,
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: c,
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(S, {
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(p, {
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 y, setAttribute as I, template as m, delegateEvents as N } from "solid-js/web";
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__ */ m('<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__ */ m('<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__ */ m('<div class="flex items-center justify-center h-full text-xs text-muted-foreground">No files in this directory'), Q = /* @__PURE__ */ m('<span class="ml-auto text-[10px] text-muted-foreground/60 flex-shrink-0">'), U = /* @__PURE__ */ m("<button type=button><span class=truncate>");
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(""), r = O({
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 ? (t) => e.filter(t) : void 0,
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 t = R(r.selectedPath());
27
- if (t === "/")
28
+ const r = R(t.selectedPath());
29
+ if (r === "/")
28
30
  return e.files.filter((o) => o.type === "file");
29
- const n = r.folderIndex().get(t);
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 = (t) => {
36
- f(t.name), s("");
37
+ const S = (r) => {
38
+ f(r.name), s("");
37
39
  }, v = () => {
38
- const t = u().trim();
39
- if (!t) {
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(t);
46
+ const l = e.validateFileName(r);
45
47
  if (l) {
46
48
  s(l);
47
49
  return;
48
50
  }
49
51
  }
50
- const n = r.selectedPath(), o = e.onSave;
51
- e.onOpenChange(!1), L(() => o(n, t));
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
- }, _ = (t) => {
55
- t.key === "Enter" && (t.preventDefault(), v());
56
+ }, _ = (r) => {
57
+ r.key === "Enter" && (r.preventDefault(), v());
56
58
  }, P = $(() => {
57
- const t = r.toDisplayPath(r.selectedPath()), n = u().trim();
58
- return n ? t === "/" ? `/${n}` : `${t}/${n}` : t;
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 t = H(), n = t.firstChild, o = n.firstChild, l = o.nextSibling, c = n.nextSibling, d = c.firstChild;
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: (h) => f(h.currentTarget.value),
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(() => I(d, "title", P())), t;
106
+ }), null), b(() => y(d, "title", P())), r;
105
107
  })();
106
108
  },
107
109
  get children() {
108
- var t = A(), n = t.firstChild, o = n.firstChild;
109
- return a(t, i(G, {
110
+ var r = A(), n = r.firstChild, o = n.firstChild;
111
+ return a(r, i(G, {
110
112
  get value() {
111
- return r.pathInput;
113
+ return t.pathInput;
112
114
  },
113
115
  onInput: (l) => {
114
- r.setPathInput(l), r.setPathInputError("");
116
+ t.setPathInput(l), t.setPathInputError("");
117
+ },
118
+ get pending() {
119
+ return t.pathPending;
115
120
  },
116
121
  get error() {
117
- return r.pathInputError;
122
+ return t.pathInputError;
118
123
  },
119
124
  get onGo() {
120
- return r.handlePathInputGo;
125
+ return t.handlePathInputGo;
121
126
  },
122
127
  get onKeyDown() {
123
- return r.handlePathInputKeyDown;
128
+ return t.handlePathInputKeyDown;
124
129
  }
125
- }), n), a(t, i(M, {
130
+ }), n), a(r, i(M, {
126
131
  get segments() {
127
- return r.breadcrumbSegments;
132
+ return t.breadcrumbSegments;
128
133
  },
129
134
  get onClick() {
130
- return r.handleBreadcrumbClick;
135
+ return t.handleBreadcrumbClick;
131
136
  }
132
137
  }), n), a(n, i(j, {
133
138
  get rootFolders() {
134
- return r.rootFolders;
139
+ return t.rootFolders;
135
140
  },
136
141
  get selectedPath() {
137
- return r.selectedPath;
142
+ return t.selectedPath;
138
143
  },
139
144
  get expandedPaths() {
140
- return r.expandedPaths;
145
+ return t.expandedPaths;
146
+ },
147
+ get revealNonce() {
148
+ return t.revealNonce;
141
149
  },
142
150
  get onToggle() {
143
- return r.toggleExpand;
151
+ return t.toggleExpand;
144
152
  },
145
153
  get onSelect() {
146
- return r.handleSelectFolder;
154
+ return t.handleSelectFolder;
147
155
  },
148
156
  get onSelectRoot() {
149
- return r.handleSelectRoot;
157
+ return t.handleSelectRoot;
150
158
  },
151
159
  get isSelectable() {
152
- return r.isSelectable;
160
+ return t.isSelectable;
153
161
  },
154
162
  get homeLabel() {
155
- return r.homeLabel;
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 h = Q();
185
- return a(h, () => V(l.size)), h;
192
+ var m = Q();
193
+ return a(m, () => V(l.size)), m;
186
194
  }
187
- }), null), b(() => y(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;
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(t, i(g, {
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 r.selectedPath;
206
+ return t.selectedPath;
199
207
  },
200
208
  get onCreateFolder() {
201
209
  return e.onCreateFolder;
202
210
  },
203
211
  get toDisplayPath() {
204
- return r.toDisplayPath;
212
+ return t.toDisplayPath;
205
213
  }
206
214
  });
207
215
  }
208
- }), null), t;
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
- N(["click"]);
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;