@uipath/apollo-wind 2.62.0 → 2.63.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/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 +14 -14
- package/dist/index.cjs +13 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -1
- package/dist/styles.css +20 -0
- package/package.json +1 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FolderPickerEntry } from '../types';
|
|
2
|
+
export interface FolderRowProps {
|
|
3
|
+
entry: FolderPickerEntry;
|
|
4
|
+
/** Depth in the tree, 1 at the root. */
|
|
5
|
+
level: number;
|
|
6
|
+
selected: boolean;
|
|
7
|
+
/** The tree's single tab stop. The parent moves it with the arrow keys. */
|
|
8
|
+
active: boolean;
|
|
9
|
+
/** This row's own contents are being fetched. */
|
|
10
|
+
loading: boolean;
|
|
11
|
+
rowRef: (node: HTMLDivElement | null) => void;
|
|
12
|
+
onFocus: () => void;
|
|
13
|
+
onToggleSelect: () => void;
|
|
14
|
+
onOpen: () => void;
|
|
15
|
+
/** Accessible name for the Open control, given the row's label. */
|
|
16
|
+
openLabel?: (label: string) => string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* One folder in the list.
|
|
20
|
+
*
|
|
21
|
+
* A `treeitem` rather than a listbox option: an option is atomic to assistive
|
|
22
|
+
* technology, which would hide the trailing Open control or make it compete
|
|
23
|
+
* with the row for focus. Clicking the row marks it with a tick as the
|
|
24
|
+
* pending choice, the chevron or a double click opens it, and a known leaf
|
|
25
|
+
* offers no way in at all.
|
|
26
|
+
*/
|
|
27
|
+
export declare function FolderRow({ entry, level, selected, active, loading, rowRef, onFocus, onToggleSelect, onOpen, openLabel, }: FolderRowProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Check, ChevronRight, Folder } from "lucide-react";
|
|
3
|
+
import { Spinner } from "../../spinner.js";
|
|
4
|
+
import { cn } from "../../../../lib/index.js";
|
|
5
|
+
function FolderRow({ entry, level, selected, active, loading, rowRef, onFocus, onToggleSelect, onOpen, openLabel = (rowLabel)=>`Open ${rowLabel}` }) {
|
|
6
|
+
const label = entry.label ?? entry.name;
|
|
7
|
+
const canOpen = !entry.disabled && false !== entry.hasChildren;
|
|
8
|
+
const canStartOpen = canOpen && !loading;
|
|
9
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
10
|
+
role: "treeitem",
|
|
11
|
+
"aria-level": level,
|
|
12
|
+
"aria-selected": selected,
|
|
13
|
+
"aria-label": label,
|
|
14
|
+
"aria-expanded": canOpen ? false : void 0,
|
|
15
|
+
"aria-disabled": entry.disabled,
|
|
16
|
+
ref: rowRef,
|
|
17
|
+
tabIndex: entry.disabled ? void 0 : active ? 0 : -1,
|
|
18
|
+
onFocus: (event)=>!entry.disabled && event.target === event.currentTarget && onFocus(),
|
|
19
|
+
className: cn('flex w-full items-center gap-2 px-3 py-1.5 text-left text-sm text-foreground transition-colors', entry.disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:bg-surface-overlay', selected && 'font-medium'),
|
|
20
|
+
onClick: (event)=>!entry.disabled && event.detail <= 1 && onToggleSelect(),
|
|
21
|
+
onDoubleClick: ()=>{
|
|
22
|
+
if (canStartOpen) onOpen();
|
|
23
|
+
else if (!entry.disabled && !selected) onToggleSelect();
|
|
24
|
+
},
|
|
25
|
+
onKeyDown: (event)=>{
|
|
26
|
+
if (entry.disabled) return;
|
|
27
|
+
if (event.target !== event.currentTarget) return;
|
|
28
|
+
if ('Enter' === event.key || ' ' === event.key) {
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
onToggleSelect();
|
|
31
|
+
} else if ('ArrowRight' === event.key && canStartOpen) {
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
onOpen();
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
children: [
|
|
37
|
+
/*#__PURE__*/ jsx("span", {
|
|
38
|
+
className: "grid size-3.5 shrink-0 place-items-center",
|
|
39
|
+
children: selected && /*#__PURE__*/ jsx(Check, {
|
|
40
|
+
className: "size-3.5 text-foreground-accent",
|
|
41
|
+
strokeWidth: 3
|
|
42
|
+
})
|
|
43
|
+
}),
|
|
44
|
+
/*#__PURE__*/ jsx(Folder, {
|
|
45
|
+
size: 14,
|
|
46
|
+
className: "shrink-0 text-foreground-muted"
|
|
47
|
+
}),
|
|
48
|
+
/*#__PURE__*/ jsx("span", {
|
|
49
|
+
className: "min-w-0 flex-1 truncate",
|
|
50
|
+
children: label
|
|
51
|
+
}),
|
|
52
|
+
false !== entry.hasChildren && /*#__PURE__*/ jsx("button", {
|
|
53
|
+
type: "button",
|
|
54
|
+
"aria-label": openLabel(label),
|
|
55
|
+
"aria-busy": loading || void 0,
|
|
56
|
+
tabIndex: -1,
|
|
57
|
+
disabled: entry.disabled,
|
|
58
|
+
className: "grid size-5 shrink-0 cursor-pointer place-items-center rounded text-foreground-muted transition-colors hover:bg-surface-overlay hover:text-foreground",
|
|
59
|
+
onClick: (event)=>{
|
|
60
|
+
event.stopPropagation();
|
|
61
|
+
if (canStartOpen) onOpen();
|
|
62
|
+
},
|
|
63
|
+
children: loading ? /*#__PURE__*/ jsx(Spinner, {
|
|
64
|
+
className: "[&_svg]:size-3.5",
|
|
65
|
+
"aria-hidden": "true"
|
|
66
|
+
}) : /*#__PURE__*/ jsx(ChevronRight, {
|
|
67
|
+
size: 14
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export { FolderRow };
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __webpack_require__ = {};
|
|
4
|
+
(()=>{
|
|
5
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
6
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: definition[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
})();
|
|
12
|
+
(()=>{
|
|
13
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.r = (exports1)=>{
|
|
17
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
18
|
+
value: 'Module'
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
21
|
+
value: true
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
})();
|
|
25
|
+
var __webpack_exports__ = {};
|
|
26
|
+
__webpack_require__.r(__webpack_exports__);
|
|
27
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
28
|
+
FolderPickerContent: ()=>FolderPickerContent,
|
|
29
|
+
FolderPicker: ()=>FolderPicker,
|
|
30
|
+
keepFolderSearchOnEscape: ()=>keepFolderSearchOnEscape
|
|
31
|
+
});
|
|
32
|
+
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
|
|
33
|
+
const external_lucide_react_namespaceObject = require("lucide-react");
|
|
34
|
+
const external_react_namespaceObject = require("react");
|
|
35
|
+
const external_popover_cjs_namespaceObject = require("../popover.cjs");
|
|
36
|
+
const index_cjs_namespaceObject = require("../../../lib/index.cjs");
|
|
37
|
+
const folder_breadcrumb_cjs_namespaceObject = require("./components/folder-breadcrumb.cjs");
|
|
38
|
+
const folder_picker_empty_state_cjs_namespaceObject = require("./components/folder-picker-empty-state.cjs");
|
|
39
|
+
const folder_picker_footer_cjs_namespaceObject = require("./components/folder-picker-footer.cjs");
|
|
40
|
+
const folder_picker_search_cjs_namespaceObject = require("./components/folder-picker-search.cjs");
|
|
41
|
+
const folder_row_cjs_namespaceObject = require("./components/folder-row.cjs");
|
|
42
|
+
const external_types_cjs_namespaceObject = require("./types.cjs");
|
|
43
|
+
const listedDraft = (current, entries, segments)=>entries.some((entry)=>!entry.disabled && (0, external_types_cjs_namespaceObject.joinPath)([
|
|
44
|
+
...segments,
|
|
45
|
+
entry.name
|
|
46
|
+
]) === current) ? current : null;
|
|
47
|
+
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 }) {
|
|
48
|
+
const initialSegments = (0, external_react_namespaceObject.useMemo)(()=>(initialPath ?? '').split('/').filter(Boolean), [
|
|
49
|
+
initialPath
|
|
50
|
+
]);
|
|
51
|
+
const [pathStack, setPathStack] = (0, external_react_namespaceObject.useState)(()=>initialSegments.slice(0, -1));
|
|
52
|
+
const [draft, setDraft] = (0, external_react_namespaceObject.useState)(()=>initialSegments.length > 0 ? (0, external_types_cjs_namespaceObject.joinPath)(initialSegments) : null);
|
|
53
|
+
const [search, setSearch] = (0, external_react_namespaceObject.useState)(initialSearch);
|
|
54
|
+
const [levels, setLevels] = (0, external_react_namespaceObject.useState)(()=>new Map());
|
|
55
|
+
const [loadingPath, setLoadingPath] = (0, external_react_namespaceObject.useState)(()=>(0, external_types_cjs_namespaceObject.joinPath)(initialSegments.slice(0, -1)));
|
|
56
|
+
const [error, setError] = (0, external_react_namespaceObject.useState)(null);
|
|
57
|
+
const [activeName, setActiveName] = (0, external_react_namespaceObject.useState)(()=>initialSegments[initialSegments.length - 1] ?? null);
|
|
58
|
+
const rowRefs = (0, external_react_namespaceObject.useRef)(new Map());
|
|
59
|
+
const listRef = (0, external_react_namespaceObject.useRef)(null);
|
|
60
|
+
const rootRef = (0, external_react_namespaceObject.useRef)(null);
|
|
61
|
+
const focusAfterNavigateRef = (0, external_react_namespaceObject.useRef)(false);
|
|
62
|
+
const requestRef = (0, external_react_namespaceObject.useRef)(0);
|
|
63
|
+
const mountedRef = (0, external_react_namespaceObject.useRef)(true);
|
|
64
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
65
|
+
mountedRef.current = true;
|
|
66
|
+
return ()=>{
|
|
67
|
+
mountedRef.current = false;
|
|
68
|
+
};
|
|
69
|
+
}, []);
|
|
70
|
+
const loadLevel = (0, external_react_namespaceObject.useCallback)(async (segments, { keepDraft = false, keepSearch = false, nextActive } = {})=>{
|
|
71
|
+
const key = (0, external_types_cjs_namespaceObject.cacheKey)(segments);
|
|
72
|
+
const requestId = ++requestRef.current;
|
|
73
|
+
const cached = levels.get(key);
|
|
74
|
+
if (cached) {
|
|
75
|
+
setLoadingPath(null);
|
|
76
|
+
setError(null);
|
|
77
|
+
setPathStack(segments);
|
|
78
|
+
if (void 0 !== nextActive) setActiveName(nextActive);
|
|
79
|
+
if (keepDraft) setDraft((current)=>listedDraft(current, cached, segments));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
setLoadingPath((0, external_types_cjs_namespaceObject.joinPath)(segments));
|
|
83
|
+
setError(null);
|
|
84
|
+
try {
|
|
85
|
+
const loaded = await onLoadChildren(segments);
|
|
86
|
+
if (!mountedRef.current || requestRef.current !== requestId) return;
|
|
87
|
+
const seen = new Set();
|
|
88
|
+
const entries = loaded.filter((entry)=>{
|
|
89
|
+
if (!(0, external_types_cjs_namespaceObject.isValidSegment)(entry.name) || seen.has(entry.name)) return false;
|
|
90
|
+
seen.add(entry.name);
|
|
91
|
+
return true;
|
|
92
|
+
});
|
|
93
|
+
if (entries.length < loaded.length) console.warn('FolderPicker: dropped entries whose name is empty, contains "/" or repeats a sibling, which paths cannot represent.');
|
|
94
|
+
setLevels((current)=>new Map(current).set(key, entries));
|
|
95
|
+
setPathStack(segments);
|
|
96
|
+
if (void 0 !== nextActive) setActiveName(nextActive);
|
|
97
|
+
if (keepDraft) setDraft((current)=>listedDraft(current, entries, segments));
|
|
98
|
+
else {
|
|
99
|
+
setDraft(null);
|
|
100
|
+
if (!keepSearch) setSearch('');
|
|
101
|
+
}
|
|
102
|
+
} catch (cause) {
|
|
103
|
+
if (!mountedRef.current || requestRef.current !== requestId) return;
|
|
104
|
+
if (keepDraft) setDraft(null);
|
|
105
|
+
setError({
|
|
106
|
+
message: cause instanceof Error && cause.message ? cause.message : loadErrorText,
|
|
107
|
+
segments
|
|
108
|
+
});
|
|
109
|
+
} finally{
|
|
110
|
+
if (mountedRef.current && requestRef.current === requestId) setLoadingPath(null);
|
|
111
|
+
}
|
|
112
|
+
}, [
|
|
113
|
+
levels,
|
|
114
|
+
onLoadChildren,
|
|
115
|
+
loadErrorText
|
|
116
|
+
]);
|
|
117
|
+
const initialStack = (0, external_react_namespaceObject.useRef)(pathStack);
|
|
118
|
+
const didLoadInitial = (0, external_react_namespaceObject.useRef)(false);
|
|
119
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
120
|
+
if (didLoadInitial.current) return;
|
|
121
|
+
didLoadInitial.current = true;
|
|
122
|
+
loadLevel(initialStack.current, {
|
|
123
|
+
keepDraft: true
|
|
124
|
+
});
|
|
125
|
+
}, [
|
|
126
|
+
loadLevel
|
|
127
|
+
]);
|
|
128
|
+
const handleEscape = (event)=>{
|
|
129
|
+
if ('Escape' !== event.key || !search) return;
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
event.stopPropagation();
|
|
132
|
+
setSearch('');
|
|
133
|
+
};
|
|
134
|
+
const navigateTo = (segments)=>{
|
|
135
|
+
if (loadingPath === (0, external_types_cjs_namespaceObject.joinPath)(segments)) return;
|
|
136
|
+
setDraft(null);
|
|
137
|
+
setSearch('');
|
|
138
|
+
const isAncestor = segments.every((segment, index)=>pathStack[index] === segment);
|
|
139
|
+
loadLevel(segments, {
|
|
140
|
+
nextActive: isAncestor ? pathStack[segments.length] ?? null : null
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
const currentKey = (0, external_types_cjs_namespaceObject.cacheKey)(pathStack);
|
|
144
|
+
const entries = levels.get(currentKey) ?? [];
|
|
145
|
+
const isLoadingCurrentLevel = null !== loadingPath && !levels.has(currentKey);
|
|
146
|
+
const levelError = levels.has(currentKey) ? null : error?.message ?? null;
|
|
147
|
+
const drillError = levels.has(currentKey) ? error?.message ?? null : null;
|
|
148
|
+
const normalizedQuery = search.trim().toLowerCase();
|
|
149
|
+
const visibleEntries = normalizedQuery ? entries.filter((entry)=>(entry.label ?? entry.name).toLowerCase().includes(normalizedQuery)) : entries;
|
|
150
|
+
const visibleDraft = visibleEntries.some((entry)=>(0, external_types_cjs_namespaceObject.joinPath)([
|
|
151
|
+
...pathStack,
|
|
152
|
+
entry.name
|
|
153
|
+
]) === draft) ? draft : null;
|
|
154
|
+
const effectiveSelection = levels.has(currentKey) ? visibleDraft ?? (pathStack.length > 0 ? (0, external_types_cjs_namespaceObject.joinPath)(pathStack) : null) : null;
|
|
155
|
+
const focusableEntries = visibleEntries.filter((entry)=>!entry.disabled);
|
|
156
|
+
const activeEntryName = focusableEntries.find((entry)=>entry.name === activeName)?.name ?? focusableEntries[0]?.name ?? null;
|
|
157
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
158
|
+
if (!focusAfterNavigateRef.current || null !== loadingPath) return;
|
|
159
|
+
focusAfterNavigateRef.current = false;
|
|
160
|
+
const tree = listRef.current;
|
|
161
|
+
const focused = tree?.ownerDocument.activeElement;
|
|
162
|
+
const focusLost = !focused || focused === tree?.ownerDocument.body;
|
|
163
|
+
const onRowOrFallback = focused === tree || focused?.getAttribute('role') === 'treeitem';
|
|
164
|
+
if (!focusLost && !(onRowOrFallback && tree?.contains(focused))) return;
|
|
165
|
+
const row = null === activeEntryName ? void 0 : rowRefs.current.get(activeEntryName);
|
|
166
|
+
(row ?? listRef.current)?.focus();
|
|
167
|
+
});
|
|
168
|
+
const syncedPath = (0, external_react_namespaceObject.useRef)(initialPath);
|
|
169
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
170
|
+
if (syncedPath.current === initialPath) return;
|
|
171
|
+
syncedPath.current = initialPath;
|
|
172
|
+
const root = rootRef.current;
|
|
173
|
+
if (root?.contains(root.ownerDocument.activeElement)) focusAfterNavigateRef.current = true;
|
|
174
|
+
setDraft(initialSegments.length > 0 ? (0, external_types_cjs_namespaceObject.joinPath)(initialSegments) : null);
|
|
175
|
+
setSearch('');
|
|
176
|
+
loadLevel(initialSegments.slice(0, -1), {
|
|
177
|
+
keepDraft: true,
|
|
178
|
+
nextActive: initialSegments[initialSegments.length - 1] ?? null
|
|
179
|
+
});
|
|
180
|
+
}, [
|
|
181
|
+
initialPath,
|
|
182
|
+
initialSegments,
|
|
183
|
+
loadLevel
|
|
184
|
+
]);
|
|
185
|
+
const focusRow = (name)=>{
|
|
186
|
+
setActiveName(name);
|
|
187
|
+
rowRefs.current.get(name)?.focus();
|
|
188
|
+
};
|
|
189
|
+
const openFolder = (segments)=>{
|
|
190
|
+
focusAfterNavigateRef.current = true;
|
|
191
|
+
navigateTo(segments);
|
|
192
|
+
};
|
|
193
|
+
const handleTreeKeyDown = (event)=>{
|
|
194
|
+
const target = event.target;
|
|
195
|
+
if (target !== listRef.current && 'treeitem' !== target.getAttribute('role')) return;
|
|
196
|
+
const index = target === listRef.current ? -1 : focusableEntries.findIndex((entry)=>entry.name === activeEntryName);
|
|
197
|
+
let next;
|
|
198
|
+
switch(event.key){
|
|
199
|
+
case 'ArrowDown':
|
|
200
|
+
next = focusableEntries[Math.min(index + 1, focusableEntries.length - 1)];
|
|
201
|
+
break;
|
|
202
|
+
case 'ArrowUp':
|
|
203
|
+
next = focusableEntries[Math.max(index - 1, 0)];
|
|
204
|
+
break;
|
|
205
|
+
case 'Home':
|
|
206
|
+
next = focusableEntries[0];
|
|
207
|
+
break;
|
|
208
|
+
case 'End':
|
|
209
|
+
next = focusableEntries[focusableEntries.length - 1];
|
|
210
|
+
break;
|
|
211
|
+
case 'ArrowLeft':
|
|
212
|
+
if (0 === pathStack.length) return;
|
|
213
|
+
event.preventDefault();
|
|
214
|
+
openFolder(pathStack.slice(0, -1));
|
|
215
|
+
return;
|
|
216
|
+
default:
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
event.preventDefault();
|
|
220
|
+
if (next) focusRow(next.name);
|
|
221
|
+
};
|
|
222
|
+
const crumbs = [
|
|
223
|
+
{
|
|
224
|
+
key: '/',
|
|
225
|
+
label: rootLabel,
|
|
226
|
+
stack: []
|
|
227
|
+
},
|
|
228
|
+
...pathStack.map((segment, index)=>{
|
|
229
|
+
const stack = pathStack.slice(0, index + 1);
|
|
230
|
+
const parent = levels.get((0, external_types_cjs_namespaceObject.cacheKey)(pathStack.slice(0, index)));
|
|
231
|
+
const label = parent?.find((entry)=>entry.name === segment)?.label ?? segment;
|
|
232
|
+
return {
|
|
233
|
+
key: (0, external_types_cjs_namespaceObject.joinPath)(stack),
|
|
234
|
+
label,
|
|
235
|
+
stack
|
|
236
|
+
};
|
|
237
|
+
})
|
|
238
|
+
];
|
|
239
|
+
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
240
|
+
ref: rootRef,
|
|
241
|
+
"data-slot": "folder-picker",
|
|
242
|
+
className: (0, index_cjs_namespaceObject.cn)('flex min-w-0 flex-col overflow-hidden', className),
|
|
243
|
+
onKeyDown: handleEscape,
|
|
244
|
+
children: [
|
|
245
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(folder_breadcrumb_cjs_namespaceObject.FolderBreadcrumb, {
|
|
246
|
+
crumbs: crumbs,
|
|
247
|
+
onJump: openFolder,
|
|
248
|
+
label: breadcrumbLabel
|
|
249
|
+
}),
|
|
250
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(folder_picker_search_cjs_namespaceObject.FolderPickerSearch, {
|
|
251
|
+
value: search,
|
|
252
|
+
onChange: setSearch,
|
|
253
|
+
placeholder: searchPlaceholder,
|
|
254
|
+
clearLabel: clearSearchLabel
|
|
255
|
+
}),
|
|
256
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
257
|
+
ref: listRef,
|
|
258
|
+
role: "group",
|
|
259
|
+
"aria-label": listLabel,
|
|
260
|
+
tabIndex: null === activeEntryName ? 0 : -1,
|
|
261
|
+
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",
|
|
262
|
+
onKeyDown: handleTreeKeyDown,
|
|
263
|
+
children: [
|
|
264
|
+
0 === visibleEntries.length && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(folder_picker_empty_state_cjs_namespaceObject.FolderPickerEmptyState, {
|
|
265
|
+
error: levelError,
|
|
266
|
+
loading: isLoadingCurrentLevel,
|
|
267
|
+
query: search.trim(),
|
|
268
|
+
emptyText: emptyText,
|
|
269
|
+
noMatchText: noMatchText,
|
|
270
|
+
loadingText: loadingText,
|
|
271
|
+
retryLabel: retryLabel,
|
|
272
|
+
onRetry: ()=>{
|
|
273
|
+
if (!error) return;
|
|
274
|
+
listRef.current?.focus();
|
|
275
|
+
focusAfterNavigateRef.current = true;
|
|
276
|
+
if ((0, external_types_cjs_namespaceObject.cacheKey)(error.segments) === currentKey) loadLevel(pathStack, {
|
|
277
|
+
keepSearch: true
|
|
278
|
+
});
|
|
279
|
+
else navigateTo(error.segments);
|
|
280
|
+
}
|
|
281
|
+
}),
|
|
282
|
+
drillError && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
283
|
+
role: "alert",
|
|
284
|
+
className: "px-3 py-2 text-xs text-destructive",
|
|
285
|
+
children: drillError
|
|
286
|
+
}),
|
|
287
|
+
(visibleEntries.length > 0 || isLoadingCurrentLevel) && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
288
|
+
role: "tree",
|
|
289
|
+
"aria-label": listLabel,
|
|
290
|
+
"aria-busy": isLoadingCurrentLevel || void 0,
|
|
291
|
+
children: visibleEntries.map((entry)=>{
|
|
292
|
+
const segments = [
|
|
293
|
+
...pathStack,
|
|
294
|
+
entry.name
|
|
295
|
+
];
|
|
296
|
+
const fullPath = (0, external_types_cjs_namespaceObject.joinPath)(segments);
|
|
297
|
+
const isSelected = draft === fullPath;
|
|
298
|
+
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(folder_row_cjs_namespaceObject.FolderRow, {
|
|
299
|
+
entry: entry,
|
|
300
|
+
level: pathStack.length + 1,
|
|
301
|
+
selected: isSelected,
|
|
302
|
+
active: entry.name === activeEntryName,
|
|
303
|
+
loading: loadingPath === fullPath,
|
|
304
|
+
rowRef: (node)=>{
|
|
305
|
+
if (node) rowRefs.current.set(entry.name, node);
|
|
306
|
+
else rowRefs.current.delete(entry.name);
|
|
307
|
+
},
|
|
308
|
+
onFocus: ()=>setActiveName(entry.name),
|
|
309
|
+
onToggleSelect: ()=>setDraft(isSelected ? null : fullPath),
|
|
310
|
+
onOpen: ()=>openFolder(segments),
|
|
311
|
+
openLabel: openFolderLabel
|
|
312
|
+
}, fullPath);
|
|
313
|
+
})
|
|
314
|
+
})
|
|
315
|
+
]
|
|
316
|
+
}),
|
|
317
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(folder_picker_footer_cjs_namespaceObject.FolderPickerFooter, {
|
|
318
|
+
leading: footerLeading,
|
|
319
|
+
onCancel: onCancel,
|
|
320
|
+
onSelect: ()=>effectiveSelection && onSelect(effectiveSelection),
|
|
321
|
+
selectDisabled: !effectiveSelection,
|
|
322
|
+
cancelLabel: cancelLabel,
|
|
323
|
+
selectLabel: selectLabel
|
|
324
|
+
})
|
|
325
|
+
]
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
function keepFolderSearchOnEscape(event) {
|
|
329
|
+
const target = event.target;
|
|
330
|
+
if (!(target instanceof Element)) return;
|
|
331
|
+
const search = target.closest('[data-slot="folder-picker"]')?.querySelector('input[data-slot="folder-picker-search"]');
|
|
332
|
+
if (search?.value) event.preventDefault();
|
|
333
|
+
}
|
|
334
|
+
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 }) {
|
|
335
|
+
const [uncontrolledOpen, setUncontrolledOpen] = (0, external_react_namespaceObject.useState)(false);
|
|
336
|
+
const requestedOpen = controlledOpen ?? uncontrolledOpen;
|
|
337
|
+
const open = requestedOpen && !disabled;
|
|
338
|
+
const closedByDisable = disabled && requestedOpen;
|
|
339
|
+
(0, external_react_namespaceObject.useEffect)(()=>{
|
|
340
|
+
if (!closedByDisable) return;
|
|
341
|
+
setUncontrolledOpen(false);
|
|
342
|
+
onOpenChange?.(false);
|
|
343
|
+
}, [
|
|
344
|
+
closedByDisable
|
|
345
|
+
]);
|
|
346
|
+
const contentRef = (0, external_react_namespaceObject.useRef)(null);
|
|
347
|
+
const browsePath = (0, external_react_namespaceObject.useRef)(value);
|
|
348
|
+
if (open) browsePath.current = value;
|
|
349
|
+
const triggerRef = (0, external_react_namespaceObject.useRef)(null);
|
|
350
|
+
const trailingRef = (0, external_react_namespaceObject.useRef)(null);
|
|
351
|
+
const [trailingWidth, setTrailingWidth] = (0, external_react_namespaceObject.useState)(0);
|
|
352
|
+
const showClear = clearable && Boolean(value) && !disabled && !children;
|
|
353
|
+
const showAdornment = Boolean(trailingAdornment) && !children;
|
|
354
|
+
const hasTrailing = showAdornment || showClear;
|
|
355
|
+
(0, external_react_namespaceObject.useLayoutEffect)(()=>{
|
|
356
|
+
const el = trailingRef.current;
|
|
357
|
+
if (!el) return void setTrailingWidth(0);
|
|
358
|
+
setTrailingWidth(el.offsetWidth);
|
|
359
|
+
if ("u" < typeof ResizeObserver) return;
|
|
360
|
+
const observer = new ResizeObserver(()=>setTrailingWidth(el.offsetWidth));
|
|
361
|
+
observer.observe(el);
|
|
362
|
+
return ()=>observer.disconnect();
|
|
363
|
+
}, [
|
|
364
|
+
hasTrailing
|
|
365
|
+
]);
|
|
366
|
+
const setOpen = (nextOpen)=>{
|
|
367
|
+
if (nextOpen && disabled) return;
|
|
368
|
+
if (void 0 === controlledOpen) setUncontrolledOpen(nextOpen);
|
|
369
|
+
onOpenChange?.(nextOpen);
|
|
370
|
+
};
|
|
371
|
+
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("div", {
|
|
372
|
+
className: (0, index_cjs_namespaceObject.cn)('group relative min-w-0', className),
|
|
373
|
+
children: [
|
|
374
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(external_popover_cjs_namespaceObject.Popover, {
|
|
375
|
+
open: open,
|
|
376
|
+
onOpenChange: setOpen,
|
|
377
|
+
children: [
|
|
378
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverTrigger, {
|
|
379
|
+
asChild: true,
|
|
380
|
+
disabled: disabled,
|
|
381
|
+
children: children ?? /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("button", {
|
|
382
|
+
ref: triggerRef,
|
|
383
|
+
type: "button",
|
|
384
|
+
disabled: disabled,
|
|
385
|
+
id: id,
|
|
386
|
+
"aria-labelledby": ariaLabelledBy,
|
|
387
|
+
"aria-describedby": ariaDescribedBy,
|
|
388
|
+
role: "combobox",
|
|
389
|
+
"aria-haspopup": "dialog",
|
|
390
|
+
"aria-expanded": open,
|
|
391
|
+
style: trailingWidth > 0 ? {
|
|
392
|
+
paddingRight: trailingWidth + 20
|
|
393
|
+
} : void 0,
|
|
394
|
+
className: (0, index_cjs_namespaceObject.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'),
|
|
395
|
+
children: [
|
|
396
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.FolderOpen, {
|
|
397
|
+
size: 16,
|
|
398
|
+
className: "shrink-0 text-foreground-muted"
|
|
399
|
+
}),
|
|
400
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
|
|
401
|
+
className: (0, index_cjs_namespaceObject.cn)('min-w-0 flex-1 truncate', value ? 'text-foreground' : 'text-foreground-subtle'),
|
|
402
|
+
children: value || placeholder
|
|
403
|
+
})
|
|
404
|
+
]
|
|
405
|
+
})
|
|
406
|
+
}),
|
|
407
|
+
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_popover_cjs_namespaceObject.PopoverContent, {
|
|
408
|
+
"aria-label": dialogLabel,
|
|
409
|
+
align: align,
|
|
410
|
+
sideOffset: 4,
|
|
411
|
+
className: (0, index_cjs_namespaceObject.cn)('w-(--radix-popover-trigger-width) min-w-72 overflow-hidden p-0', contentClassName),
|
|
412
|
+
ref: contentRef,
|
|
413
|
+
onOpenAutoFocus: (event)=>{
|
|
414
|
+
event.preventDefault();
|
|
415
|
+
contentRef.current?.querySelector('input')?.focus();
|
|
416
|
+
},
|
|
417
|
+
onEscapeKeyDown: keepFolderSearchOnEscape,
|
|
418
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(FolderPickerContent, {
|
|
419
|
+
...contentProps,
|
|
420
|
+
initialPath: browsePath.current,
|
|
421
|
+
onCancel: ()=>setOpen(false),
|
|
422
|
+
onSelect: (path)=>{
|
|
423
|
+
onSelect(path);
|
|
424
|
+
setOpen(false);
|
|
425
|
+
}
|
|
426
|
+
})
|
|
427
|
+
})
|
|
428
|
+
]
|
|
429
|
+
}),
|
|
430
|
+
hasTrailing && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)("span", {
|
|
431
|
+
ref: trailingRef,
|
|
432
|
+
className: "pointer-events-none absolute inset-y-0 right-2 flex items-center gap-0.5",
|
|
433
|
+
children: [
|
|
434
|
+
showClear && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("button", {
|
|
435
|
+
type: "button",
|
|
436
|
+
"aria-label": clearAriaLabel,
|
|
437
|
+
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",
|
|
438
|
+
onClick: ()=>{
|
|
439
|
+
triggerRef.current?.focus();
|
|
440
|
+
onSelect('');
|
|
441
|
+
},
|
|
442
|
+
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_lucide_react_namespaceObject.X, {
|
|
443
|
+
size: 11
|
|
444
|
+
})
|
|
445
|
+
}),
|
|
446
|
+
showAdornment && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("span", {
|
|
447
|
+
className: "pointer-events-auto flex items-center",
|
|
448
|
+
children: trailingAdornment
|
|
449
|
+
})
|
|
450
|
+
]
|
|
451
|
+
})
|
|
452
|
+
]
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
exports.FolderPicker = __webpack_exports__.FolderPicker;
|
|
456
|
+
exports.FolderPickerContent = __webpack_exports__.FolderPickerContent;
|
|
457
|
+
exports.keepFolderSearchOnEscape = __webpack_exports__.keepFolderSearchOnEscape;
|
|
458
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
459
|
+
"FolderPicker",
|
|
460
|
+
"FolderPickerContent",
|
|
461
|
+
"keepFolderSearchOnEscape"
|
|
462
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
463
|
+
Object.defineProperty(exports, '__esModule', {
|
|
464
|
+
value: true
|
|
465
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { FolderPickerContentProps, FolderPickerProps } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Browsing surface for embedding in a consumer-owned popover, dialog or sheet.
|
|
4
|
+
*
|
|
5
|
+
* Follows the platform chooser convention: a single click highlights a row as
|
|
6
|
+
* the pending selection, a double click or the trailing chevron opens it, the
|
|
7
|
+
* breadcrumb jumps back up, and the footer confirms. With nothing highlighted,
|
|
8
|
+
* Select confirms the folder currently being browsed, so a folder can be chosen
|
|
9
|
+
* by opening it. At the root with no highlight there is nothing valid to
|
|
10
|
+
* confirm and Select is disabled.
|
|
11
|
+
*/
|
|
12
|
+
export declare function FolderPickerContent({ onLoadChildren, onSelect, onCancel, initialPath, rootLabel, breadcrumbLabel, searchPlaceholder, clearSearchLabel, initialSearch, emptyText, noMatchText, openFolderLabel, loadingText, loadErrorText, retryLabel, listLabel, footerLeading, cancelLabel, selectLabel, className, }: FolderPickerContentProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
/**
|
|
14
|
+
* Holds a Radix surface open while the picker's search has text, so Escape
|
|
15
|
+
* clears the search instead of dismissing, wherever focus is in the picker.
|
|
16
|
+
* Radix hears Escape in the capture phase, before the picker's own handlers,
|
|
17
|
+
* so the picker cannot stop the dismissal itself. It clears the search as the
|
|
18
|
+
* key reaches it.
|
|
19
|
+
*
|
|
20
|
+
* `FolderPicker` applies it to its popover. Pass it as `onEscapeKeyDown` to a
|
|
21
|
+
* Dialog, Sheet or Popover that hosts `FolderPickerContent`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function keepFolderSearchOnEscape(event: {
|
|
24
|
+
target: EventTarget | null;
|
|
25
|
+
preventDefault(): void;
|
|
26
|
+
}): void;
|
|
27
|
+
/**
|
|
28
|
+
* Field-and-popover folder picker over a lazily loaded tree.
|
|
29
|
+
*
|
|
30
|
+
* The trigger leads with its icon and then the value, matching the date field,
|
|
31
|
+
* so an empty folder field does not read as bare chrome next to it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function FolderPicker({ value, placeholder, disabled, clearable, clearAriaLabel, dialogLabel, children, align, open: controlledOpen, onOpenChange, trailingAdornment, contentClassName, className, id, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, onSelect, ...contentProps }: FolderPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export type { FolderPickerContentProps, FolderPickerEntry, FolderPickerLoadChildren, FolderPickerProps, } from './types';
|