@flytedan/flytebot-design-system 0.13.0 → 0.14.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/index.cjs +63 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +63 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -3441,6 +3441,7 @@ interface FileBrowserPermissions {
|
|
|
3441
3441
|
canMove?: boolean;
|
|
3442
3442
|
canUpload?: boolean;
|
|
3443
3443
|
canRemoveFile?: boolean;
|
|
3444
|
+
canDeleteFolder?: boolean;
|
|
3444
3445
|
}
|
|
3445
3446
|
interface FileBrowserProps {
|
|
3446
3447
|
folders: FileBrowserFolder[];
|
|
@@ -3454,6 +3455,16 @@ interface FileBrowserProps {
|
|
|
3454
3455
|
onMoveFile?: (fileId: string, targetFolderId: string | null) => void;
|
|
3455
3456
|
onOpenFile?: (file: FileBrowserFile) => void;
|
|
3456
3457
|
onRemoveFile?: (file: FileBrowserFile) => void;
|
|
3458
|
+
/** MP-190: same contract as `onRenameFolder`/`onMoveFolder` — no fetching, no emptiness
|
|
3459
|
+
* pre-check (the host's server is the one source of truth for "empty"; see the folder
|
|
3460
|
+
* kit doc comment above), fired only once the confirm dialog is accepted. Sibling
|
|
3461
|
+
* callbacks (`onRenameFolder`, `onMoveFolder`, `onRemoveFile`) are all plain, synchronous,
|
|
3462
|
+
* void callbacks with no promise/rejection handling anywhere in this component, so this
|
|
3463
|
+
* one is void too rather than inventing an async contract none of its siblings have — a
|
|
3464
|
+
* host that needs to show the server's `folder_not_empty` refusal does so the same way it
|
|
3465
|
+
* already must for a failed rename/move/remove: by feeding the error back through its own
|
|
3466
|
+
* state, outside this component. */
|
|
3467
|
+
onDeleteFolder?: (folder: FileBrowserFolder) => void;
|
|
3457
3468
|
/** Fired with the raw picked/dropped files and the folder they landed in — FileBrowser
|
|
3458
3469
|
* does no fetching and stages nothing itself (R-8/"generic, controlled" — see MP-135):
|
|
3459
3470
|
* the host runs its own `useStagedFiles`/`FileUploadHandler` and feeds the result back
|
|
@@ -3484,7 +3495,7 @@ interface FileBrowserProps {
|
|
|
3484
3495
|
* region per pane either way (R-8): the tree pane and the main pane each own their own
|
|
3485
3496
|
* `overflow`, the head/breadcrumb bar never scrolls.
|
|
3486
3497
|
*/
|
|
3487
|
-
declare function FileBrowser({ folders, files, currentFolderId, onNavigate, onCreateFolder, onRenameFolder, onMoveFolder, onMoveFile, onOpenFile, onRemoveFile, onUpload, loading, permissions, className, }: FileBrowserProps): React.JSX.Element;
|
|
3498
|
+
declare function FileBrowser({ folders, files, currentFolderId, onNavigate, onCreateFolder, onRenameFolder, onMoveFolder, onMoveFile, onOpenFile, onRemoveFile, onDeleteFolder, onUpload, loading, permissions, className, }: FileBrowserProps): React.JSX.Element;
|
|
3488
3499
|
|
|
3489
3500
|
interface TableQuery {
|
|
3490
3501
|
/** 1-indexed. */
|
package/dist/index.d.ts
CHANGED
|
@@ -3441,6 +3441,7 @@ interface FileBrowserPermissions {
|
|
|
3441
3441
|
canMove?: boolean;
|
|
3442
3442
|
canUpload?: boolean;
|
|
3443
3443
|
canRemoveFile?: boolean;
|
|
3444
|
+
canDeleteFolder?: boolean;
|
|
3444
3445
|
}
|
|
3445
3446
|
interface FileBrowserProps {
|
|
3446
3447
|
folders: FileBrowserFolder[];
|
|
@@ -3454,6 +3455,16 @@ interface FileBrowserProps {
|
|
|
3454
3455
|
onMoveFile?: (fileId: string, targetFolderId: string | null) => void;
|
|
3455
3456
|
onOpenFile?: (file: FileBrowserFile) => void;
|
|
3456
3457
|
onRemoveFile?: (file: FileBrowserFile) => void;
|
|
3458
|
+
/** MP-190: same contract as `onRenameFolder`/`onMoveFolder` — no fetching, no emptiness
|
|
3459
|
+
* pre-check (the host's server is the one source of truth for "empty"; see the folder
|
|
3460
|
+
* kit doc comment above), fired only once the confirm dialog is accepted. Sibling
|
|
3461
|
+
* callbacks (`onRenameFolder`, `onMoveFolder`, `onRemoveFile`) are all plain, synchronous,
|
|
3462
|
+
* void callbacks with no promise/rejection handling anywhere in this component, so this
|
|
3463
|
+
* one is void too rather than inventing an async contract none of its siblings have — a
|
|
3464
|
+
* host that needs to show the server's `folder_not_empty` refusal does so the same way it
|
|
3465
|
+
* already must for a failed rename/move/remove: by feeding the error back through its own
|
|
3466
|
+
* state, outside this component. */
|
|
3467
|
+
onDeleteFolder?: (folder: FileBrowserFolder) => void;
|
|
3457
3468
|
/** Fired with the raw picked/dropped files and the folder they landed in — FileBrowser
|
|
3458
3469
|
* does no fetching and stages nothing itself (R-8/"generic, controlled" — see MP-135):
|
|
3459
3470
|
* the host runs its own `useStagedFiles`/`FileUploadHandler` and feeds the result back
|
|
@@ -3484,7 +3495,7 @@ interface FileBrowserProps {
|
|
|
3484
3495
|
* region per pane either way (R-8): the tree pane and the main pane each own their own
|
|
3485
3496
|
* `overflow`, the head/breadcrumb bar never scrolls.
|
|
3486
3497
|
*/
|
|
3487
|
-
declare function FileBrowser({ folders, files, currentFolderId, onNavigate, onCreateFolder, onRenameFolder, onMoveFolder, onMoveFile, onOpenFile, onRemoveFile, onUpload, loading, permissions, className, }: FileBrowserProps): React.JSX.Element;
|
|
3498
|
+
declare function FileBrowser({ folders, files, currentFolderId, onNavigate, onCreateFolder, onRenameFolder, onMoveFolder, onMoveFile, onOpenFile, onRemoveFile, onDeleteFolder, onUpload, loading, permissions, className, }: FileBrowserProps): React.JSX.Element;
|
|
3488
3499
|
|
|
3489
3500
|
interface TableQuery {
|
|
3490
3501
|
/** 1-indexed. */
|
package/dist/index.js
CHANGED
|
@@ -8464,6 +8464,30 @@ function BudgetReallocator({
|
|
|
8464
8464
|
setDraft(spend);
|
|
8465
8465
|
if (onCancel) onCancel();
|
|
8466
8466
|
};
|
|
8467
|
+
const trackRef = React39.useRef(null);
|
|
8468
|
+
const chipRef = React39.useRef(null);
|
|
8469
|
+
const [chipLeft, setChipLeft] = React39.useState(null);
|
|
8470
|
+
React39.useLayoutEffect(() => {
|
|
8471
|
+
const track = trackRef.current;
|
|
8472
|
+
if (!dirty || !track) {
|
|
8473
|
+
setChipLeft(null);
|
|
8474
|
+
return;
|
|
8475
|
+
}
|
|
8476
|
+
const measure = () => {
|
|
8477
|
+
const chip = chipRef.current;
|
|
8478
|
+
if (!chip) return;
|
|
8479
|
+
const trackWidth = track.clientWidth;
|
|
8480
|
+
const chipWidth = chip.offsetWidth;
|
|
8481
|
+
const half = chipWidth / 2;
|
|
8482
|
+
const desired = pct / 100 * trackWidth;
|
|
8483
|
+
setChipLeft(Math.min(Math.max(desired, half), Math.max(trackWidth - half, half)));
|
|
8484
|
+
};
|
|
8485
|
+
measure();
|
|
8486
|
+
if (typeof ResizeObserver !== "function") return;
|
|
8487
|
+
const ro = new ResizeObserver(measure);
|
|
8488
|
+
ro.observe(track);
|
|
8489
|
+
return () => ro.disconnect();
|
|
8490
|
+
}, [dirty, pct]);
|
|
8467
8491
|
return /* @__PURE__ */ jsxs64(
|
|
8468
8492
|
"div",
|
|
8469
8493
|
{
|
|
@@ -8478,9 +8502,20 @@ function BudgetReallocator({
|
|
|
8478
8502
|
/* @__PURE__ */ jsx68(CsiBadge, { band: nextBand, crp: nextCrp, size: "medium", preview: true })
|
|
8479
8503
|
] }) : null
|
|
8480
8504
|
] }),
|
|
8481
|
-
/* @__PURE__ */ jsxs64("div", { className: "fd-slider", children: [
|
|
8505
|
+
/* @__PURE__ */ jsxs64("div", { className: "fd-slider", ref: trackRef, children: [
|
|
8482
8506
|
/* @__PURE__ */ jsx68("span", { className: "fd-slider-fill", style: { width: pct + "%" } }),
|
|
8483
|
-
dirty ? /* @__PURE__ */ jsx68(
|
|
8507
|
+
dirty ? /* @__PURE__ */ jsx68(
|
|
8508
|
+
"span",
|
|
8509
|
+
{
|
|
8510
|
+
ref: chipRef,
|
|
8511
|
+
className: "fd-slider-chip",
|
|
8512
|
+
style: {
|
|
8513
|
+
left: chipLeft === null ? pct + "%" : chipLeft,
|
|
8514
|
+
background: delta < 0 ? "var(--danger-solid)" : "var(--ok-solid)"
|
|
8515
|
+
},
|
|
8516
|
+
children: (delta < 0 ? "\u2212$" : "+$") + Math.abs(delta).toLocaleString()
|
|
8517
|
+
}
|
|
8518
|
+
) : null,
|
|
8484
8519
|
/* @__PURE__ */ jsx68(
|
|
8485
8520
|
"input",
|
|
8486
8521
|
{
|
|
@@ -10648,6 +10683,7 @@ function FileBrowser({
|
|
|
10648
10683
|
onMoveFile,
|
|
10649
10684
|
onOpenFile,
|
|
10650
10685
|
onRemoveFile,
|
|
10686
|
+
onDeleteFolder,
|
|
10651
10687
|
onUpload,
|
|
10652
10688
|
loading = false,
|
|
10653
10689
|
permissions,
|
|
@@ -10659,10 +10695,12 @@ function FileBrowser({
|
|
|
10659
10695
|
const canMove = perm.canMove !== false && (!!onMoveFolder || !!onMoveFile);
|
|
10660
10696
|
const canUpload = perm.canUpload !== false && !!onUpload;
|
|
10661
10697
|
const canRemoveFile = perm.canRemoveFile !== false && !!onRemoveFile;
|
|
10698
|
+
const canDeleteFolder = perm.canDeleteFolder !== false && !!onDeleteFolder;
|
|
10662
10699
|
const [createOpen, setCreateOpen] = React48.useState(false);
|
|
10663
10700
|
const [createName, setCreateName] = React48.useState("");
|
|
10664
10701
|
const [renameTarget, setRenameTarget] = React48.useState(null);
|
|
10665
10702
|
const [renameValue, setRenameValue] = React48.useState("");
|
|
10703
|
+
const [deleteTarget, setDeleteTarget] = React48.useState(null);
|
|
10666
10704
|
const uploadInputRef = React48.useRef(null);
|
|
10667
10705
|
const crumbFolders = React48.useMemo(() => ancestorsOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
10668
10706
|
const subfolders = React48.useMemo(() => childrenOf(folders, currentFolderId), [folders, currentFolderId]);
|
|
@@ -10698,6 +10736,13 @@ function FileBrowser({
|
|
|
10698
10736
|
if (name && renameTarget && onRenameFolder) onRenameFolder(renameTarget.id, name);
|
|
10699
10737
|
setRenameTarget(null);
|
|
10700
10738
|
};
|
|
10739
|
+
const openDelete = (folder) => {
|
|
10740
|
+
setDeleteTarget(folder);
|
|
10741
|
+
};
|
|
10742
|
+
const confirmDelete = () => {
|
|
10743
|
+
if (deleteTarget && onDeleteFolder) onDeleteFolder(deleteTarget);
|
|
10744
|
+
setDeleteTarget(null);
|
|
10745
|
+
};
|
|
10701
10746
|
const content = /* @__PURE__ */ jsxs74("div", { className: ["fd-fb", className].filter(Boolean).join(" "), children: [
|
|
10702
10747
|
/* @__PURE__ */ jsxs74("div", { className: "fd-fb-head", children: [
|
|
10703
10748
|
/* @__PURE__ */ jsxs74("nav", { className: "fd-fb-crumbs", "aria-label": "Folder path", children: [
|
|
@@ -10801,7 +10846,8 @@ function FileBrowser({
|
|
|
10801
10846
|
destinations: flattenDestinations(folders, f.id),
|
|
10802
10847
|
onPick: (target) => moveIntoFolder({ kind: "folder", id: f.id }, target)
|
|
10803
10848
|
}
|
|
10804
|
-
) : null
|
|
10849
|
+
) : null,
|
|
10850
|
+
canDeleteFolder ? /* @__PURE__ */ jsx78(IconButton, { icon: "trash-simple", label: "Delete " + f.name, size: "sm", variant: "ghost", onClick: () => openDelete(f) }) : null
|
|
10805
10851
|
] })
|
|
10806
10852
|
},
|
|
10807
10853
|
f.id
|
|
@@ -10865,7 +10911,20 @@ function FileBrowser({
|
|
|
10865
10911
|
"aria-label": "Folder name",
|
|
10866
10912
|
autoFocus: true
|
|
10867
10913
|
}
|
|
10868
|
-
) })
|
|
10914
|
+
) }),
|
|
10915
|
+
/* @__PURE__ */ jsx78(
|
|
10916
|
+
Modal,
|
|
10917
|
+
{
|
|
10918
|
+
open: deleteTarget != null,
|
|
10919
|
+
title: deleteTarget ? "Delete \u201C" + deleteTarget.name + "\u201D?" : "Delete folder?",
|
|
10920
|
+
description: "This can't be undone. The folder must be empty.",
|
|
10921
|
+
onClose: () => setDeleteTarget(null),
|
|
10922
|
+
footer: /* @__PURE__ */ jsxs74(Fragment23, { children: [
|
|
10923
|
+
/* @__PURE__ */ jsx78(Button, { variant: "secondary", onClick: () => setDeleteTarget(null), children: "Cancel" }),
|
|
10924
|
+
/* @__PURE__ */ jsx78(Button, { variant: "danger", onClick: confirmDelete, children: "Delete" })
|
|
10925
|
+
] })
|
|
10926
|
+
}
|
|
10927
|
+
)
|
|
10869
10928
|
] });
|
|
10870
10929
|
if (!canUpload) return content;
|
|
10871
10930
|
return /* @__PURE__ */ jsx78(Dropzone, { className: "fd-fb-dropzone", onFiles: (picked) => onUpload && onUpload(picked, currentFolderId), label: "Drop files to upload", children: content });
|