@uipath/apollo-wind 2.62.0 → 2.64.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/dist/components/forms/aria-ids.cjs +38 -0
- package/dist/components/forms/aria-ids.d.ts +2 -0
- package/dist/components/forms/aria-ids.js +4 -0
- package/dist/components/forms/demo-mocks.cjs +0 -448
- package/dist/components/forms/demo-mocks.js +0 -448
- package/dist/components/forms/field-control.cjs +21 -17
- package/dist/components/forms/field-control.d.ts +3 -1
- package/dist/components/forms/field-control.js +21 -17
- package/dist/components/forms/field-renderer.cjs +65 -37
- package/dist/components/forms/field-renderer.js +66 -38
- package/dist/components/forms/form-designer.cjs +204 -3
- package/dist/components/forms/form-designer.js +204 -3
- package/dist/components/forms/form-examples.cjs +3 -190
- package/dist/components/forms/form-examples.d.ts +0 -10
- package/dist/components/forms/form-examples.js +3 -184
- package/dist/components/forms/form-schema.d.ts +6 -0
- package/dist/components/forms/metadata-form.cjs +9 -1
- package/dist/components/forms/metadata-form.d.ts +8 -1
- package/dist/components/forms/metadata-form.js +9 -1
- package/dist/components/forms/mode-aware-field.cjs +11 -6
- package/dist/components/forms/mode-aware-field.d.ts +2 -0
- package/dist/components/forms/mode-aware-field.js +11 -6
- package/dist/components/forms/string-list-field.cjs +5 -4
- package/dist/components/forms/string-list-field.d.ts +4 -2
- package/dist/components/forms/string-list-field.js +5 -4
- package/dist/components/ui/folder-picker/components/folder-breadcrumb.cjs +72 -0
- package/dist/components/ui/folder-picker/components/folder-breadcrumb.d.ts +14 -0
- package/dist/components/ui/folder-picker/components/folder-breadcrumb.js +38 -0
- package/dist/components/ui/folder-picker/components/folder-picker-empty-state.cjs +75 -0
- package/dist/components/ui/folder-picker/components/folder-picker-empty-state.d.ts +26 -0
- package/dist/components/ui/folder-picker/components/folder-picker-empty-state.js +41 -0
- package/dist/components/ui/folder-picker/components/folder-picker-footer.cjs +70 -0
- package/dist/components/ui/folder-picker/components/folder-picker-footer.d.ts +20 -0
- package/dist/components/ui/folder-picker/components/folder-picker-footer.js +36 -0
- package/dist/components/ui/folder-picker/components/folder-picker-search.cjs +79 -0
- package/dist/components/ui/folder-picker/components/folder-picker-search.d.ts +14 -0
- package/dist/components/ui/folder-picker/components/folder-picker-search.js +45 -0
- package/dist/components/ui/folder-picker/components/folder-row.cjs +107 -0
- package/dist/components/ui/folder-picker/components/folder-row.d.ts +27 -0
- package/dist/components/ui/folder-picker/components/folder-row.js +73 -0
- package/dist/components/ui/folder-picker/folder-picker.cjs +465 -0
- package/dist/components/ui/folder-picker/folder-picker.d.ts +34 -0
- package/dist/components/ui/folder-picker/folder-picker.js +425 -0
- package/dist/components/ui/folder-picker/index.cjs +42 -0
- package/dist/components/ui/folder-picker/index.d.ts +2 -0
- package/dist/components/ui/folder-picker/index.js +2 -0
- package/dist/components/ui/folder-picker/types.cjs +44 -0
- package/dist/components/ui/folder-picker/types.d.ts +97 -0
- package/dist/components/ui/folder-picker/types.js +4 -0
- package/dist/components/ui/index.cjs +26 -26
- package/dist/components/ui/json-tree-view/JsonTree.types.d.ts +13 -0
- package/dist/components/ui/json-tree-view/JsonTreeRow.cjs +2 -1
- package/dist/components/ui/json-tree-view/JsonTreeRow.js +2 -1
- package/dist/components/ui/json-tree-view/JsonTypeBadge.cjs +43 -6
- package/dist/components/ui/json-tree-view/JsonTypeBadge.d.ts +6 -3
- package/dist/components/ui/json-tree-view/JsonTypeBadge.js +44 -7
- package/dist/components/ui/json-tree-view/index.d.ts +1 -1
- package/dist/components/ui/json-tree-view/strings.cjs +1 -0
- package/dist/components/ui/json-tree-view/strings.d.ts +10 -2
- package/dist/components/ui/json-tree-view/strings.js +1 -0
- package/dist/components/ui/prompt-value-control.cjs +3 -1
- package/dist/components/ui/prompt-value-control.d.ts +5 -0
- package/dist/components/ui/prompt-value-control.js +3 -1
- package/dist/components/ui/variable-value-control.cjs +3 -1
- package/dist/components/ui/variable-value-control.d.ts +5 -0
- package/dist/components/ui/variable-value-control.js +3 -1
- package/dist/index.cjs +13 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -1
- package/dist/styles.css +41 -0
- package/package.json +1 -1
- package/dist/templates/Forms/form-builder-example.d.ts +0 -1
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { FolderOpen, X } from "lucide-react";
|
|
4
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../popover.js";
|
|
6
|
+
import { cn } from "../../../lib/index.js";
|
|
7
|
+
import { FolderBreadcrumb } from "./components/folder-breadcrumb.js";
|
|
8
|
+
import { FolderPickerEmptyState } from "./components/folder-picker-empty-state.js";
|
|
9
|
+
import { FolderPickerFooter } from "./components/folder-picker-footer.js";
|
|
10
|
+
import { FolderPickerSearch } from "./components/folder-picker-search.js";
|
|
11
|
+
import { FolderRow } from "./components/folder-row.js";
|
|
12
|
+
import { cacheKey, isValidSegment, joinPath } from "./types.js";
|
|
13
|
+
const listedDraft = (current, entries, segments)=>entries.some((entry)=>!entry.disabled && joinPath([
|
|
14
|
+
...segments,
|
|
15
|
+
entry.name
|
|
16
|
+
]) === current) ? current : null;
|
|
17
|
+
function FolderPickerContent({ onLoadChildren, onSelect, onCancel, initialPath, rootLabel = 'Root', breadcrumbLabel, searchPlaceholder = 'Search...', clearSearchLabel, initialSearch = '', emptyText = 'No subfolders.', noMatchText, openFolderLabel, loadingText = 'Loading…', loadErrorText = 'Could not load this folder.', retryLabel = 'Retry', listLabel = 'Folders', footerLeading, cancelLabel = 'Cancel', selectLabel = 'Select', className }) {
|
|
18
|
+
const initialSegments = useMemo(()=>(initialPath ?? '').split('/').filter(Boolean), [
|
|
19
|
+
initialPath
|
|
20
|
+
]);
|
|
21
|
+
const [pathStack, setPathStack] = useState(()=>initialSegments.slice(0, -1));
|
|
22
|
+
const [draft, setDraft] = useState(()=>initialSegments.length > 0 ? joinPath(initialSegments) : null);
|
|
23
|
+
const [search, setSearch] = useState(initialSearch);
|
|
24
|
+
const [levels, setLevels] = useState(()=>new Map());
|
|
25
|
+
const [loadingPath, setLoadingPath] = useState(()=>joinPath(initialSegments.slice(0, -1)));
|
|
26
|
+
const [error, setError] = useState(null);
|
|
27
|
+
const [activeName, setActiveName] = useState(()=>initialSegments[initialSegments.length - 1] ?? null);
|
|
28
|
+
const rowRefs = useRef(new Map());
|
|
29
|
+
const listRef = useRef(null);
|
|
30
|
+
const rootRef = useRef(null);
|
|
31
|
+
const focusAfterNavigateRef = useRef(false);
|
|
32
|
+
const requestRef = useRef(0);
|
|
33
|
+
const mountedRef = useRef(true);
|
|
34
|
+
useEffect(()=>{
|
|
35
|
+
mountedRef.current = true;
|
|
36
|
+
return ()=>{
|
|
37
|
+
mountedRef.current = false;
|
|
38
|
+
};
|
|
39
|
+
}, []);
|
|
40
|
+
const loadLevel = useCallback(async (segments, { keepDraft = false, keepSearch = false, nextActive } = {})=>{
|
|
41
|
+
const key = cacheKey(segments);
|
|
42
|
+
const requestId = ++requestRef.current;
|
|
43
|
+
const cached = levels.get(key);
|
|
44
|
+
if (cached) {
|
|
45
|
+
setLoadingPath(null);
|
|
46
|
+
setError(null);
|
|
47
|
+
setPathStack(segments);
|
|
48
|
+
if (void 0 !== nextActive) setActiveName(nextActive);
|
|
49
|
+
if (keepDraft) setDraft((current)=>listedDraft(current, cached, segments));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
setLoadingPath(joinPath(segments));
|
|
53
|
+
setError(null);
|
|
54
|
+
try {
|
|
55
|
+
const loaded = await onLoadChildren(segments);
|
|
56
|
+
if (!mountedRef.current || requestRef.current !== requestId) return;
|
|
57
|
+
const seen = new Set();
|
|
58
|
+
const entries = loaded.filter((entry)=>{
|
|
59
|
+
if (!isValidSegment(entry.name) || seen.has(entry.name)) return false;
|
|
60
|
+
seen.add(entry.name);
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
63
|
+
if (entries.length < loaded.length) console.warn('FolderPicker: dropped entries whose name is empty, contains "/" or repeats a sibling, which paths cannot represent.');
|
|
64
|
+
setLevels((current)=>new Map(current).set(key, entries));
|
|
65
|
+
setPathStack(segments);
|
|
66
|
+
if (void 0 !== nextActive) setActiveName(nextActive);
|
|
67
|
+
if (keepDraft) setDraft((current)=>listedDraft(current, entries, segments));
|
|
68
|
+
else {
|
|
69
|
+
setDraft(null);
|
|
70
|
+
if (!keepSearch) setSearch('');
|
|
71
|
+
}
|
|
72
|
+
} catch (cause) {
|
|
73
|
+
if (!mountedRef.current || requestRef.current !== requestId) return;
|
|
74
|
+
if (keepDraft) setDraft(null);
|
|
75
|
+
setError({
|
|
76
|
+
message: cause instanceof Error && cause.message ? cause.message : loadErrorText,
|
|
77
|
+
segments
|
|
78
|
+
});
|
|
79
|
+
} finally{
|
|
80
|
+
if (mountedRef.current && requestRef.current === requestId) setLoadingPath(null);
|
|
81
|
+
}
|
|
82
|
+
}, [
|
|
83
|
+
levels,
|
|
84
|
+
onLoadChildren,
|
|
85
|
+
loadErrorText
|
|
86
|
+
]);
|
|
87
|
+
const initialStack = useRef(pathStack);
|
|
88
|
+
const didLoadInitial = useRef(false);
|
|
89
|
+
useEffect(()=>{
|
|
90
|
+
if (didLoadInitial.current) return;
|
|
91
|
+
didLoadInitial.current = true;
|
|
92
|
+
loadLevel(initialStack.current, {
|
|
93
|
+
keepDraft: true
|
|
94
|
+
});
|
|
95
|
+
}, [
|
|
96
|
+
loadLevel
|
|
97
|
+
]);
|
|
98
|
+
const handleEscape = (event)=>{
|
|
99
|
+
if ('Escape' !== event.key || !search) return;
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
event.stopPropagation();
|
|
102
|
+
setSearch('');
|
|
103
|
+
};
|
|
104
|
+
const navigateTo = (segments)=>{
|
|
105
|
+
if (loadingPath === joinPath(segments)) return;
|
|
106
|
+
setDraft(null);
|
|
107
|
+
setSearch('');
|
|
108
|
+
const isAncestor = segments.every((segment, index)=>pathStack[index] === segment);
|
|
109
|
+
loadLevel(segments, {
|
|
110
|
+
nextActive: isAncestor ? pathStack[segments.length] ?? null : null
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const currentKey = cacheKey(pathStack);
|
|
114
|
+
const entries = levels.get(currentKey) ?? [];
|
|
115
|
+
const isLoadingCurrentLevel = null !== loadingPath && !levels.has(currentKey);
|
|
116
|
+
const levelError = levels.has(currentKey) ? null : error?.message ?? null;
|
|
117
|
+
const drillError = levels.has(currentKey) ? error?.message ?? null : null;
|
|
118
|
+
const normalizedQuery = search.trim().toLowerCase();
|
|
119
|
+
const visibleEntries = normalizedQuery ? entries.filter((entry)=>(entry.label ?? entry.name).toLowerCase().includes(normalizedQuery)) : entries;
|
|
120
|
+
const visibleDraft = visibleEntries.some((entry)=>joinPath([
|
|
121
|
+
...pathStack,
|
|
122
|
+
entry.name
|
|
123
|
+
]) === draft) ? draft : null;
|
|
124
|
+
const effectiveSelection = levels.has(currentKey) ? visibleDraft ?? (pathStack.length > 0 ? joinPath(pathStack) : null) : null;
|
|
125
|
+
const focusableEntries = visibleEntries.filter((entry)=>!entry.disabled);
|
|
126
|
+
const activeEntryName = focusableEntries.find((entry)=>entry.name === activeName)?.name ?? focusableEntries[0]?.name ?? null;
|
|
127
|
+
useEffect(()=>{
|
|
128
|
+
if (!focusAfterNavigateRef.current || null !== loadingPath) return;
|
|
129
|
+
focusAfterNavigateRef.current = false;
|
|
130
|
+
const tree = listRef.current;
|
|
131
|
+
const focused = tree?.ownerDocument.activeElement;
|
|
132
|
+
const focusLost = !focused || focused === tree?.ownerDocument.body;
|
|
133
|
+
const onRowOrFallback = focused === tree || focused?.getAttribute('role') === 'treeitem';
|
|
134
|
+
if (!focusLost && !(onRowOrFallback && tree?.contains(focused))) return;
|
|
135
|
+
const row = null === activeEntryName ? void 0 : rowRefs.current.get(activeEntryName);
|
|
136
|
+
(row ?? listRef.current)?.focus();
|
|
137
|
+
});
|
|
138
|
+
const syncedPath = useRef(initialPath);
|
|
139
|
+
useEffect(()=>{
|
|
140
|
+
if (syncedPath.current === initialPath) return;
|
|
141
|
+
syncedPath.current = initialPath;
|
|
142
|
+
const root = rootRef.current;
|
|
143
|
+
if (root?.contains(root.ownerDocument.activeElement)) focusAfterNavigateRef.current = true;
|
|
144
|
+
setDraft(initialSegments.length > 0 ? joinPath(initialSegments) : null);
|
|
145
|
+
setSearch('');
|
|
146
|
+
loadLevel(initialSegments.slice(0, -1), {
|
|
147
|
+
keepDraft: true,
|
|
148
|
+
nextActive: initialSegments[initialSegments.length - 1] ?? null
|
|
149
|
+
});
|
|
150
|
+
}, [
|
|
151
|
+
initialPath,
|
|
152
|
+
initialSegments,
|
|
153
|
+
loadLevel
|
|
154
|
+
]);
|
|
155
|
+
const focusRow = (name)=>{
|
|
156
|
+
setActiveName(name);
|
|
157
|
+
rowRefs.current.get(name)?.focus();
|
|
158
|
+
};
|
|
159
|
+
const openFolder = (segments)=>{
|
|
160
|
+
focusAfterNavigateRef.current = true;
|
|
161
|
+
navigateTo(segments);
|
|
162
|
+
};
|
|
163
|
+
const handleTreeKeyDown = (event)=>{
|
|
164
|
+
const target = event.target;
|
|
165
|
+
if (target !== listRef.current && 'treeitem' !== target.getAttribute('role')) return;
|
|
166
|
+
const index = target === listRef.current ? -1 : focusableEntries.findIndex((entry)=>entry.name === activeEntryName);
|
|
167
|
+
let next;
|
|
168
|
+
switch(event.key){
|
|
169
|
+
case 'ArrowDown':
|
|
170
|
+
next = focusableEntries[Math.min(index + 1, focusableEntries.length - 1)];
|
|
171
|
+
break;
|
|
172
|
+
case 'ArrowUp':
|
|
173
|
+
next = focusableEntries[Math.max(index - 1, 0)];
|
|
174
|
+
break;
|
|
175
|
+
case 'Home':
|
|
176
|
+
next = focusableEntries[0];
|
|
177
|
+
break;
|
|
178
|
+
case 'End':
|
|
179
|
+
next = focusableEntries[focusableEntries.length - 1];
|
|
180
|
+
break;
|
|
181
|
+
case 'ArrowLeft':
|
|
182
|
+
if (0 === pathStack.length) return;
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
openFolder(pathStack.slice(0, -1));
|
|
185
|
+
return;
|
|
186
|
+
default:
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
event.preventDefault();
|
|
190
|
+
if (next) focusRow(next.name);
|
|
191
|
+
};
|
|
192
|
+
const crumbs = [
|
|
193
|
+
{
|
|
194
|
+
key: '/',
|
|
195
|
+
label: rootLabel,
|
|
196
|
+
stack: []
|
|
197
|
+
},
|
|
198
|
+
...pathStack.map((segment, index)=>{
|
|
199
|
+
const stack = pathStack.slice(0, index + 1);
|
|
200
|
+
const parent = levels.get(cacheKey(pathStack.slice(0, index)));
|
|
201
|
+
const label = parent?.find((entry)=>entry.name === segment)?.label ?? segment;
|
|
202
|
+
return {
|
|
203
|
+
key: joinPath(stack),
|
|
204
|
+
label,
|
|
205
|
+
stack
|
|
206
|
+
};
|
|
207
|
+
})
|
|
208
|
+
];
|
|
209
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
210
|
+
ref: rootRef,
|
|
211
|
+
"data-slot": "folder-picker",
|
|
212
|
+
className: cn('flex min-w-0 flex-col overflow-hidden', className),
|
|
213
|
+
onKeyDown: handleEscape,
|
|
214
|
+
children: [
|
|
215
|
+
/*#__PURE__*/ jsx(FolderBreadcrumb, {
|
|
216
|
+
crumbs: crumbs,
|
|
217
|
+
onJump: openFolder,
|
|
218
|
+
label: breadcrumbLabel
|
|
219
|
+
}),
|
|
220
|
+
/*#__PURE__*/ jsx(FolderPickerSearch, {
|
|
221
|
+
value: search,
|
|
222
|
+
onChange: setSearch,
|
|
223
|
+
placeholder: searchPlaceholder,
|
|
224
|
+
clearLabel: clearSearchLabel
|
|
225
|
+
}),
|
|
226
|
+
/*#__PURE__*/ jsxs("div", {
|
|
227
|
+
ref: listRef,
|
|
228
|
+
role: "group",
|
|
229
|
+
"aria-label": listLabel,
|
|
230
|
+
tabIndex: null === activeEntryName ? 0 : -1,
|
|
231
|
+
className: "max-h-56 min-h-0 flex-1 overflow-y-auto py-1 outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
|
|
232
|
+
onKeyDown: handleTreeKeyDown,
|
|
233
|
+
children: [
|
|
234
|
+
0 === visibleEntries.length && /*#__PURE__*/ jsx(FolderPickerEmptyState, {
|
|
235
|
+
error: levelError,
|
|
236
|
+
loading: isLoadingCurrentLevel,
|
|
237
|
+
query: search.trim(),
|
|
238
|
+
emptyText: emptyText,
|
|
239
|
+
noMatchText: noMatchText,
|
|
240
|
+
loadingText: loadingText,
|
|
241
|
+
retryLabel: retryLabel,
|
|
242
|
+
onRetry: ()=>{
|
|
243
|
+
if (!error) return;
|
|
244
|
+
listRef.current?.focus();
|
|
245
|
+
focusAfterNavigateRef.current = true;
|
|
246
|
+
if (cacheKey(error.segments) === currentKey) loadLevel(pathStack, {
|
|
247
|
+
keepSearch: true
|
|
248
|
+
});
|
|
249
|
+
else navigateTo(error.segments);
|
|
250
|
+
}
|
|
251
|
+
}),
|
|
252
|
+
drillError && /*#__PURE__*/ jsx("div", {
|
|
253
|
+
role: "alert",
|
|
254
|
+
className: "px-3 py-2 text-xs text-destructive",
|
|
255
|
+
children: drillError
|
|
256
|
+
}),
|
|
257
|
+
(visibleEntries.length > 0 || isLoadingCurrentLevel) && /*#__PURE__*/ jsx("div", {
|
|
258
|
+
role: "tree",
|
|
259
|
+
"aria-label": listLabel,
|
|
260
|
+
"aria-busy": isLoadingCurrentLevel || void 0,
|
|
261
|
+
children: visibleEntries.map((entry)=>{
|
|
262
|
+
const segments = [
|
|
263
|
+
...pathStack,
|
|
264
|
+
entry.name
|
|
265
|
+
];
|
|
266
|
+
const fullPath = joinPath(segments);
|
|
267
|
+
const isSelected = draft === fullPath;
|
|
268
|
+
return /*#__PURE__*/ jsx(FolderRow, {
|
|
269
|
+
entry: entry,
|
|
270
|
+
level: pathStack.length + 1,
|
|
271
|
+
selected: isSelected,
|
|
272
|
+
active: entry.name === activeEntryName,
|
|
273
|
+
loading: loadingPath === fullPath,
|
|
274
|
+
rowRef: (node)=>{
|
|
275
|
+
if (node) rowRefs.current.set(entry.name, node);
|
|
276
|
+
else rowRefs.current.delete(entry.name);
|
|
277
|
+
},
|
|
278
|
+
onFocus: ()=>setActiveName(entry.name),
|
|
279
|
+
onToggleSelect: ()=>setDraft(isSelected ? null : fullPath),
|
|
280
|
+
onOpen: ()=>openFolder(segments),
|
|
281
|
+
openLabel: openFolderLabel
|
|
282
|
+
}, fullPath);
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
]
|
|
286
|
+
}),
|
|
287
|
+
/*#__PURE__*/ jsx(FolderPickerFooter, {
|
|
288
|
+
leading: footerLeading,
|
|
289
|
+
onCancel: onCancel,
|
|
290
|
+
onSelect: ()=>effectiveSelection && onSelect(effectiveSelection),
|
|
291
|
+
selectDisabled: !effectiveSelection,
|
|
292
|
+
cancelLabel: cancelLabel,
|
|
293
|
+
selectLabel: selectLabel
|
|
294
|
+
})
|
|
295
|
+
]
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
function keepFolderSearchOnEscape(event) {
|
|
299
|
+
const target = event.target;
|
|
300
|
+
if (!(target instanceof Element)) return;
|
|
301
|
+
const search = target.closest('[data-slot="folder-picker"]')?.querySelector('input[data-slot="folder-picker-search"]');
|
|
302
|
+
if (search?.value) event.preventDefault();
|
|
303
|
+
}
|
|
304
|
+
function FolderPicker({ value = '', placeholder = 'Select a folder…', disabled = false, clearable = true, clearAriaLabel = 'Clear folder', dialogLabel = 'Choose a folder', children, align = 'start', open: controlledOpen, onOpenChange, trailingAdornment, contentClassName, className, id, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, onSelect, ...contentProps }) {
|
|
305
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
|
|
306
|
+
const requestedOpen = controlledOpen ?? uncontrolledOpen;
|
|
307
|
+
const open = requestedOpen && !disabled;
|
|
308
|
+
const closedByDisable = disabled && requestedOpen;
|
|
309
|
+
useEffect(()=>{
|
|
310
|
+
if (!closedByDisable) return;
|
|
311
|
+
setUncontrolledOpen(false);
|
|
312
|
+
onOpenChange?.(false);
|
|
313
|
+
}, [
|
|
314
|
+
closedByDisable
|
|
315
|
+
]);
|
|
316
|
+
const contentRef = useRef(null);
|
|
317
|
+
const browsePath = useRef(value);
|
|
318
|
+
if (open) browsePath.current = value;
|
|
319
|
+
const triggerRef = useRef(null);
|
|
320
|
+
const trailingRef = useRef(null);
|
|
321
|
+
const [trailingWidth, setTrailingWidth] = useState(0);
|
|
322
|
+
const showClear = clearable && Boolean(value) && !disabled && !children;
|
|
323
|
+
const showAdornment = Boolean(trailingAdornment) && !children;
|
|
324
|
+
const hasTrailing = showAdornment || showClear;
|
|
325
|
+
useLayoutEffect(()=>{
|
|
326
|
+
const el = trailingRef.current;
|
|
327
|
+
if (!el) return void setTrailingWidth(0);
|
|
328
|
+
setTrailingWidth(el.offsetWidth);
|
|
329
|
+
if ("u" < typeof ResizeObserver) return;
|
|
330
|
+
const observer = new ResizeObserver(()=>setTrailingWidth(el.offsetWidth));
|
|
331
|
+
observer.observe(el);
|
|
332
|
+
return ()=>observer.disconnect();
|
|
333
|
+
}, [
|
|
334
|
+
hasTrailing
|
|
335
|
+
]);
|
|
336
|
+
const setOpen = (nextOpen)=>{
|
|
337
|
+
if (nextOpen && disabled) return;
|
|
338
|
+
if (void 0 === controlledOpen) setUncontrolledOpen(nextOpen);
|
|
339
|
+
onOpenChange?.(nextOpen);
|
|
340
|
+
};
|
|
341
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
342
|
+
className: cn('group relative min-w-0', className),
|
|
343
|
+
children: [
|
|
344
|
+
/*#__PURE__*/ jsxs(Popover, {
|
|
345
|
+
open: open,
|
|
346
|
+
onOpenChange: setOpen,
|
|
347
|
+
children: [
|
|
348
|
+
/*#__PURE__*/ jsx(PopoverTrigger, {
|
|
349
|
+
asChild: true,
|
|
350
|
+
disabled: disabled,
|
|
351
|
+
children: children ?? /*#__PURE__*/ jsxs("button", {
|
|
352
|
+
ref: triggerRef,
|
|
353
|
+
type: "button",
|
|
354
|
+
disabled: disabled,
|
|
355
|
+
id: id,
|
|
356
|
+
"aria-labelledby": ariaLabelledBy,
|
|
357
|
+
"aria-describedby": ariaDescribedBy,
|
|
358
|
+
role: "combobox",
|
|
359
|
+
"aria-haspopup": "dialog",
|
|
360
|
+
"aria-expanded": open,
|
|
361
|
+
style: trailingWidth > 0 ? {
|
|
362
|
+
paddingRight: trailingWidth + 20
|
|
363
|
+
} : void 0,
|
|
364
|
+
className: cn('flex h-9 w-full min-w-0 cursor-pointer items-center gap-2 rounded-md border border-input bg-transparent pl-3 pr-3 text-left text-base transition-colors md:text-sm', 'focus:outline-none focus:ring-2 focus:ring-ring focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring', 'disabled:cursor-not-allowed disabled:opacity-50', 'future:h-10 future:rounded-xl future:border-0 future:bg-surface-overlay future:px-4 future:font-normal future:hover:bg-surface-hover'),
|
|
365
|
+
children: [
|
|
366
|
+
/*#__PURE__*/ jsx(FolderOpen, {
|
|
367
|
+
size: 16,
|
|
368
|
+
className: "shrink-0 text-foreground-muted"
|
|
369
|
+
}),
|
|
370
|
+
/*#__PURE__*/ jsx("span", {
|
|
371
|
+
className: cn('min-w-0 flex-1 truncate', value ? 'text-foreground' : 'text-foreground-subtle'),
|
|
372
|
+
children: value || placeholder
|
|
373
|
+
})
|
|
374
|
+
]
|
|
375
|
+
})
|
|
376
|
+
}),
|
|
377
|
+
/*#__PURE__*/ jsx(PopoverContent, {
|
|
378
|
+
"aria-label": dialogLabel,
|
|
379
|
+
align: align,
|
|
380
|
+
sideOffset: 4,
|
|
381
|
+
className: cn('w-(--radix-popover-trigger-width) min-w-72 overflow-hidden p-0', contentClassName),
|
|
382
|
+
ref: contentRef,
|
|
383
|
+
onOpenAutoFocus: (event)=>{
|
|
384
|
+
event.preventDefault();
|
|
385
|
+
contentRef.current?.querySelector('input')?.focus();
|
|
386
|
+
},
|
|
387
|
+
onEscapeKeyDown: keepFolderSearchOnEscape,
|
|
388
|
+
children: /*#__PURE__*/ jsx(FolderPickerContent, {
|
|
389
|
+
...contentProps,
|
|
390
|
+
initialPath: browsePath.current,
|
|
391
|
+
onCancel: ()=>setOpen(false),
|
|
392
|
+
onSelect: (path)=>{
|
|
393
|
+
onSelect(path);
|
|
394
|
+
setOpen(false);
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
})
|
|
398
|
+
]
|
|
399
|
+
}),
|
|
400
|
+
hasTrailing && /*#__PURE__*/ jsxs("span", {
|
|
401
|
+
ref: trailingRef,
|
|
402
|
+
className: "pointer-events-none absolute inset-y-0 right-2 flex items-center gap-0.5",
|
|
403
|
+
children: [
|
|
404
|
+
showClear && /*#__PURE__*/ jsx("button", {
|
|
405
|
+
type: "button",
|
|
406
|
+
"aria-label": clearAriaLabel,
|
|
407
|
+
className: "pointer-events-auto grid size-4 cursor-pointer place-items-center rounded text-foreground-muted opacity-0 transition-opacity hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100",
|
|
408
|
+
onClick: ()=>{
|
|
409
|
+
triggerRef.current?.focus();
|
|
410
|
+
onSelect('');
|
|
411
|
+
},
|
|
412
|
+
children: /*#__PURE__*/ jsx(X, {
|
|
413
|
+
size: 11
|
|
414
|
+
})
|
|
415
|
+
}),
|
|
416
|
+
showAdornment && /*#__PURE__*/ jsx("span", {
|
|
417
|
+
className: "pointer-events-auto flex items-center",
|
|
418
|
+
children: trailingAdornment
|
|
419
|
+
})
|
|
420
|
+
]
|
|
421
|
+
})
|
|
422
|
+
]
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
export { FolderPicker, FolderPickerContent, keepFolderSearchOnEscape };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
FolderPickerContent: ()=>external_folder_picker_cjs_namespaceObject.FolderPickerContent,
|
|
28
|
+
FolderPicker: ()=>external_folder_picker_cjs_namespaceObject.FolderPicker,
|
|
29
|
+
keepFolderSearchOnEscape: ()=>external_folder_picker_cjs_namespaceObject.keepFolderSearchOnEscape
|
|
30
|
+
});
|
|
31
|
+
const external_folder_picker_cjs_namespaceObject = require("./folder-picker.cjs");
|
|
32
|
+
exports.FolderPicker = __webpack_exports__.FolderPicker;
|
|
33
|
+
exports.FolderPickerContent = __webpack_exports__.FolderPickerContent;
|
|
34
|
+
exports.keepFolderSearchOnEscape = __webpack_exports__.keepFolderSearchOnEscape;
|
|
35
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
36
|
+
"FolderPicker",
|
|
37
|
+
"FolderPickerContent",
|
|
38
|
+
"keepFolderSearchOnEscape"
|
|
39
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
40
|
+
Object.defineProperty(exports, '__esModule', {
|
|
41
|
+
value: true
|
|
42
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
cacheKey: ()=>cacheKey,
|
|
28
|
+
isValidSegment: ()=>isValidSegment,
|
|
29
|
+
joinPath: ()=>joinPath
|
|
30
|
+
});
|
|
31
|
+
const joinPath = (segments)=>`/${segments.join('/')}`;
|
|
32
|
+
const cacheKey = (segments)=>JSON.stringify(segments);
|
|
33
|
+
const isValidSegment = (name)=>'' !== name && !name.includes('/');
|
|
34
|
+
exports.cacheKey = __webpack_exports__.cacheKey;
|
|
35
|
+
exports.isValidSegment = __webpack_exports__.isValidSegment;
|
|
36
|
+
exports.joinPath = __webpack_exports__.joinPath;
|
|
37
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
38
|
+
"cacheKey",
|
|
39
|
+
"isValidSegment",
|
|
40
|
+
"joinPath"
|
|
41
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
42
|
+
Object.defineProperty(exports, '__esModule', {
|
|
43
|
+
value: true
|
|
44
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
export interface FolderPickerEntry {
|
|
3
|
+
/**
|
|
4
|
+
* Segment name as it appears in the path. Unique among its siblings, and
|
|
5
|
+
* non-empty without a `/`, since paths are `/`-joined strings. An entry that
|
|
6
|
+
* breaks this, or repeats an earlier sibling's name, is dropped with a
|
|
7
|
+
* warning rather than collide with another path.
|
|
8
|
+
*/
|
|
9
|
+
name: string;
|
|
10
|
+
/** Row label. Defaults to `name`. */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** False marks a known leaf, which hides its open affordance. Unknown by default. */
|
|
13
|
+
hasChildren?: boolean;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Loads one level of the tree. The root is requested with an empty path.
|
|
18
|
+
* Resolved levels are cached, so navigating back up does not re-request.
|
|
19
|
+
*/
|
|
20
|
+
export type FolderPickerLoadChildren = (path: string[]) => Promise<FolderPickerEntry[]>;
|
|
21
|
+
export interface FolderPickerContentProps {
|
|
22
|
+
/** Loads a level of the tree. Called for the root when the content mounts. */
|
|
23
|
+
onLoadChildren: FolderPickerLoadChildren;
|
|
24
|
+
/** Confirms a folder path, such as `/Finance/Invoices`. */
|
|
25
|
+
onSelect: (path: string) => void;
|
|
26
|
+
/** Closes the surface without confirming. */
|
|
27
|
+
onCancel?: () => void;
|
|
28
|
+
/** Browsing resumes at this path's parent, with the path itself highlighted. */
|
|
29
|
+
initialPath?: string;
|
|
30
|
+
/** Label for the breadcrumb's first segment. */
|
|
31
|
+
rootLabel?: string;
|
|
32
|
+
/** Accessible name for the breadcrumb's navigation landmark. */
|
|
33
|
+
breadcrumbLabel?: string;
|
|
34
|
+
searchPlaceholder?: string;
|
|
35
|
+
/** Accessible name for the search's clear control. */
|
|
36
|
+
clearSearchLabel?: string;
|
|
37
|
+
/** Seeds the search box, as VariablePicker's `initialQuery` does. */
|
|
38
|
+
initialSearch?: string;
|
|
39
|
+
emptyText?: string;
|
|
40
|
+
/** Shown when the search matches no folder in the level being browsed. */
|
|
41
|
+
noMatchText?: (query: string) => string;
|
|
42
|
+
/** Accessible name for a row's Open control, given the row's label. */
|
|
43
|
+
openFolderLabel?: (label: string) => string;
|
|
44
|
+
/** Shown while a level that has never resolved is loading. */
|
|
45
|
+
loadingText?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Shown when a load fails without a message of its own: a rejection that is
|
|
48
|
+
* not an `Error`, or one whose message is empty. Otherwise that message is
|
|
49
|
+
* shown as given.
|
|
50
|
+
*/
|
|
51
|
+
loadErrorText?: string;
|
|
52
|
+
/** Action offered when the level being browsed failed to load. */
|
|
53
|
+
retryLabel?: string;
|
|
54
|
+
/** Accessible name for the folder list. */
|
|
55
|
+
listLabel?: string;
|
|
56
|
+
/** Content for the footer's leading slot, such as a count or an "Add new" link. */
|
|
57
|
+
footerLeading?: ReactNode;
|
|
58
|
+
cancelLabel?: string;
|
|
59
|
+
selectLabel?: string;
|
|
60
|
+
className?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface FolderPickerProps extends Omit<FolderPickerContentProps, 'onCancel' | 'initialPath' | 'className'> {
|
|
63
|
+
/** Selected folder path, or an empty string. */
|
|
64
|
+
value?: string;
|
|
65
|
+
placeholder?: string;
|
|
66
|
+
disabled?: boolean;
|
|
67
|
+
/** Hides the field's hover-revealed clear control. */
|
|
68
|
+
clearable?: boolean;
|
|
69
|
+
clearAriaLabel?: string;
|
|
70
|
+
/** Accessible name for the popover, which is a dialog. */
|
|
71
|
+
dialogLabel?: string;
|
|
72
|
+
/**
|
|
73
|
+
* A single element Radix can anchor the popover to. Replaces the default
|
|
74
|
+
* field, along with its clear control and `trailingAdornment`.
|
|
75
|
+
*/
|
|
76
|
+
children?: ReactElement;
|
|
77
|
+
align?: 'start' | 'center' | 'end';
|
|
78
|
+
open?: boolean;
|
|
79
|
+
onOpenChange?: (open: boolean) => void;
|
|
80
|
+
/**
|
|
81
|
+
* Rendered inside the default field at its trailing edge, such as a
|
|
82
|
+
* field-mode menu. Ignored with custom `children`, which own their layout.
|
|
83
|
+
*/
|
|
84
|
+
trailingAdornment?: ReactNode;
|
|
85
|
+
/** Applied to the default trigger, so a `<label htmlFor>` pointing at it associates correctly. */
|
|
86
|
+
id?: string;
|
|
87
|
+
/** Id of the element naming this control, forwarded to the default trigger. */
|
|
88
|
+
'aria-labelledby'?: string;
|
|
89
|
+
'aria-describedby'?: string;
|
|
90
|
+
contentClassName?: string;
|
|
91
|
+
className?: string;
|
|
92
|
+
}
|
|
93
|
+
export declare const joinPath: (segments: string[]) => string;
|
|
94
|
+
/** Collision-free, unlike a `/`-join, should a segment ever contain a `/`. */
|
|
95
|
+
export declare const cacheKey: (segments: string[]) => string;
|
|
96
|
+
/** A name that survives the round trip through a `/`-joined path. */
|
|
97
|
+
export declare const isValidSegment: (name: string) => boolean;
|