@noya-app/noya-file-explorer 0.0.16 → 0.0.17

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.mjs CHANGED
@@ -38,10 +38,10 @@ var require_access = __commonJS({
38
38
  const accessed = _getPath(node, indexPath, options);
39
39
  return accessed[accessed.length - 1];
40
40
  }
41
- let path5 = indexPath.slice();
42
- while (path5.length > 0) {
43
- let index = path5.shift();
44
- const children = options.getChildren(node, path5);
41
+ let path7 = indexPath.slice();
42
+ while (path7.length > 0) {
43
+ let index = path7.shift();
44
+ const children = options.getChildren(node, path7);
45
45
  const child = children[index];
46
46
  if (!child) {
47
47
  return void 0;
@@ -54,12 +54,12 @@ var require_access = __commonJS({
54
54
  return _getPath(node, indexPath, options).slice(0, -1);
55
55
  }
56
56
  function _getPath(node, indexPath, options) {
57
- let path5 = indexPath.slice();
57
+ let path7 = indexPath.slice();
58
58
  let result = [node];
59
- while (path5.length > 0) {
60
- let index = path5.shift();
59
+ while (path7.length > 0) {
60
+ let index = path7.shift();
61
61
  const context = options.includeTraversalContext ? makeTraversalContext(result) : void 0;
62
- const children = options.getChildren(node, path5, context);
62
+ const children = options.getChildren(node, path7, context);
63
63
  const child = children[index];
64
64
  if (!child) {
65
65
  return result;
@@ -74,20 +74,20 @@ var require_access = __commonJS({
74
74
  const accessed = accessPath(node, indexPath, options);
75
75
  return accessed[accessed.length - 1];
76
76
  }
77
- let path5 = indexPath.slice();
78
- while (path5.length > 0) {
79
- let index = path5.shift();
80
- node = options.getChildren(node, path5)[index];
77
+ let path7 = indexPath.slice();
78
+ while (path7.length > 0) {
79
+ let index = path7.shift();
80
+ node = options.getChildren(node, path7)[index];
81
81
  }
82
82
  return node;
83
83
  }
84
84
  function accessPath(node, indexPath, options) {
85
- let path5 = indexPath.slice();
85
+ let path7 = indexPath.slice();
86
86
  let result = [node];
87
- while (path5.length > 0) {
88
- let index = path5.shift();
87
+ while (path7.length > 0) {
88
+ let index = path7.shift();
89
89
  const context = options.includeTraversalContext ? makeTraversalContext(result) : void 0;
90
- node = options.getChildren(node, path5, context)[index];
90
+ node = options.getChildren(node, path7, context)[index];
91
91
  result.push(node);
92
92
  }
93
93
  return result;
@@ -129,9 +129,9 @@ var require_ancestors = __commonJS({
129
129
  "../../node_modules/tree-visit/lib/ancestors.js"(exports) {
130
130
  "use strict";
131
131
  Object.defineProperty(exports, "__esModule", { value: true });
132
- exports.ancestorPaths = ancestorPaths2;
132
+ exports.ancestorPaths = ancestorPaths3;
133
133
  var sort_1 = require_sort();
134
- function ancestorPaths2(paths, options) {
134
+ function ancestorPaths3(paths, options) {
135
135
  var _a;
136
136
  const result = /* @__PURE__ */ new Map();
137
137
  const compare = (_a = options === null || options === void 0 ? void 0 : options.compare) !== null && _a !== void 0 ? _a : sort_1.comparePathsByComponent;
@@ -601,40 +601,40 @@ var require_transformPath = __commonJS({
601
601
  Object.defineProperty(exports, "__esModule", { value: true });
602
602
  exports.transformPath = transformPath;
603
603
  var sort_1 = require_sort();
604
- function commonAncestor(path5, otherPath) {
605
- const length = Math.min(path5.length, otherPath.length);
604
+ function commonAncestor(path7, otherPath) {
605
+ const length = Math.min(path7.length, otherPath.length);
606
606
  for (let i = 0; i < length; i++) {
607
- if (path5[i] !== otherPath[i]) {
608
- return path5.slice(0, i);
607
+ if (path7[i] !== otherPath[i]) {
608
+ return path7.slice(0, i);
609
609
  }
610
610
  }
611
- return path5.slice(0, length);
611
+ return path7.slice(0, length);
612
612
  }
613
- function transformPath(path5, operation, otherPath, count = 1) {
614
- if (otherPath.length > path5.length || (0, sort_1.comparePathsByComponent)(otherPath, path5) > 0) {
615
- return path5;
613
+ function transformPath(path7, operation, otherPath, count = 1) {
614
+ if (otherPath.length > path7.length || (0, sort_1.comparePathsByComponent)(otherPath, path7) > 0) {
615
+ return path7;
616
616
  }
617
617
  if (otherPath.length === 0 && operation === "remove") {
618
618
  return void 0;
619
619
  }
620
- const common = commonAncestor(path5, otherPath);
621
- const adjustmentIndex = common.length === path5.length || common.length === otherPath.length ? common.length - 1 : common.length;
622
- const pathValue = path5[adjustmentIndex];
620
+ const common = commonAncestor(path7, otherPath);
621
+ const adjustmentIndex = common.length === path7.length || common.length === otherPath.length ? common.length - 1 : common.length;
622
+ const pathValue = path7[adjustmentIndex];
623
623
  const otherPathValue = otherPath[adjustmentIndex];
624
624
  if (operation === "insert" && otherPathValue <= pathValue) {
625
- const newPath = [...path5];
625
+ const newPath = [...path7];
626
626
  newPath[adjustmentIndex] += count;
627
627
  return newPath;
628
628
  } else if (operation === "remove") {
629
629
  if (otherPathValue === pathValue) {
630
630
  return void 0;
631
631
  } else if (otherPathValue < pathValue) {
632
- const newPath = [...path5];
632
+ const newPath = [...path7];
633
633
  newPath[adjustmentIndex] -= count;
634
634
  return newPath;
635
635
  }
636
636
  }
637
- return path5;
637
+ return path7;
638
638
  }
639
639
  }
640
640
  });
@@ -800,15 +800,15 @@ var require_operation = __commonJS({
800
800
  switch (operation.type) {
801
801
  case "insert": {
802
802
  const otherPath = parentPath.concat(operation.index);
803
- return transformedPaths.map((path5) => path5 ? (0, transformPath_1.transformPath)(path5, "insert", otherPath, operation.nodes.length) : void 0);
803
+ return transformedPaths.map((path7) => path7 ? (0, transformPath_1.transformPath)(path7, "insert", otherPath, operation.nodes.length) : void 0);
804
804
  }
805
805
  case "remove": {
806
806
  const otherPaths = [...operation.indexes].reverse().map((index) => parentPath.concat(index));
807
- return transformedPaths.map((path5) => {
807
+ return transformedPaths.map((path7) => {
808
808
  for (const otherPath of otherPaths) {
809
- path5 = path5 ? (0, transformPath_1.transformPath)(path5, "remove", otherPath) : void 0;
809
+ path7 = path7 ? (0, transformPath_1.transformPath)(path7, "remove", otherPath) : void 0;
810
810
  }
811
- return path5;
811
+ return path7;
812
812
  });
813
813
  }
814
814
  case "removeThenInsert": {
@@ -945,22 +945,22 @@ var require_splice = __commonJS({
945
945
  return _spliceWithPathTracking(node, options);
946
946
  }
947
947
  function _spliceWithPathTracking(node, options) {
948
- const { path: path5, deleteCount = 0, nodes, track } = options;
949
- if (path5.length === 0) {
948
+ const { path: path7, deleteCount = 0, nodes, track } = options;
949
+ if (path7.length === 0) {
950
950
  throw new Error(`Can't splice at the root`);
951
951
  }
952
- const pathsToRemove = getPathsToRemove(path5, deleteCount);
953
- const operations = (0, operation_1.getInsertionOperations)(path5, nodes, (0, operation_1.getRemovalOperations)(pathsToRemove));
952
+ const pathsToRemove = getPathsToRemove(path7, deleteCount);
953
+ const operations = (0, operation_1.getInsertionOperations)(path7, nodes, (0, operation_1.getRemovalOperations)(pathsToRemove));
954
954
  const transformedPaths = track ? (0, operation_1.transformPathsByOperations)(track, operations) : [];
955
955
  return {
956
956
  node: (0, operation_1.applyOperations)(node, operations, options),
957
957
  paths: transformedPaths
958
958
  };
959
959
  }
960
- function getPathsToRemove(path5, deleteCount) {
960
+ function getPathsToRemove(path7, deleteCount) {
961
961
  let pathsToRemove = [];
962
- let parentPath = path5.slice(0, -1);
963
- let index = path5[path5.length - 1];
962
+ let parentPath = path7.slice(0, -1);
963
+ let index = path7[path7.length - 1];
964
964
  for (let i = 0; i < deleteCount; i++) {
965
965
  pathsToRemove.push(parentPath.concat(index + i));
966
966
  }
@@ -1111,7 +1111,8 @@ import {
1111
1111
  FileExplorerLayout,
1112
1112
  FileExplorerUploadButton,
1113
1113
  formatByteSize,
1114
- MediaThumbnail
1114
+ MediaThumbnail,
1115
+ useOpenConfirmationDialog
1115
1116
  } from "@noya-app/noya-designsystem";
1116
1117
  import {
1117
1118
  DownloadIcon,
@@ -1232,7 +1233,15 @@ import { path as path4 } from "imfs";
1232
1233
  import React from "react";
1233
1234
 
1234
1235
  // src/utils/files.ts
1236
+ var import_tree_visit3 = __toESM(require_lib());
1237
+ import { path as path3 } from "imfs";
1238
+
1239
+ // src/utils/resourceUtils.ts
1235
1240
  var import_tree_visit2 = __toESM(require_lib());
1241
+ import {
1242
+ createResourceTree,
1243
+ rootResource
1244
+ } from "@noya-app/noya-schemas";
1236
1245
  import { path as path2 } from "imfs";
1237
1246
  var getVisibleItems = ({
1238
1247
  expandedMap,
@@ -1243,7 +1252,7 @@ var getVisibleItems = ({
1243
1252
  showRootItem
1244
1253
  }) => {
1245
1254
  const filteredItems = [];
1246
- const relativeRootItem = tree.find(rootMediaItem, (item) => item.id === rootItemId) ?? rootMediaItem;
1255
+ const relativeRootItem = tree.find(rootResource, (item) => item.id === rootItemId) ?? rootResource;
1247
1256
  tree.visit(relativeRootItem, (item) => {
1248
1257
  if (relativeRootItem.id === item.id) {
1249
1258
  if (showRootItem) {
@@ -1251,16 +1260,16 @@ var getVisibleItems = ({
1251
1260
  }
1252
1261
  return;
1253
1262
  }
1254
- if (item.kind === "noyaFile" && fileKindFilter === "all") {
1263
+ if (item.type === "file" && fileKindFilter === "all") {
1255
1264
  filteredItems.push(item);
1256
1265
  }
1257
- if (item.kind === "file" && fileKindFilter === "all") {
1266
+ if (item.type === "asset" && (fileKindFilter === "assets" || fileKindFilter === "all")) {
1258
1267
  filteredItems.push(item);
1259
1268
  }
1260
- if (item.kind === "asset" && (fileKindFilter === "assets" || fileKindFilter === "all")) {
1269
+ if (item.type === "directory" && (fileKindFilter === "directories" || fileKindFilter === "all")) {
1261
1270
  filteredItems.push(item);
1262
1271
  }
1263
- if (item.kind === "folder" && (fileKindFilter === "directories" || fileKindFilter === "all")) {
1272
+ if (item.type === "resource" && (fileKindFilter === "resources" || fileKindFilter === "all")) {
1264
1273
  filteredItems.push(item);
1265
1274
  }
1266
1275
  if (!expandedMap[item.id] || !showAllDescendants) return "skip";
@@ -1272,7 +1281,7 @@ var basenameValidator = (basename) => {
1272
1281
  const invalidCharsRegex = /[/\\<>:"|?*]/;
1273
1282
  return !invalidCharsRegex.test(basename);
1274
1283
  };
1275
- var validateMediaItemRename = ({
1284
+ var validateResourceRename = ({
1276
1285
  basename,
1277
1286
  selectedItemPath,
1278
1287
  media
@@ -1290,7 +1299,7 @@ var movePathsIntoTarget = ({
1290
1299
  tree
1291
1300
  }) => {
1292
1301
  const ancestors = (0, import_tree_visit2.ancestorPaths)(
1293
- sourceItemPaths.map((path5) => path5.split("/"))
1302
+ sourceItemPaths.map((path7) => path7.split("/"))
1294
1303
  );
1295
1304
  const mediaClone = { ...media };
1296
1305
  for (const ancestor of ancestors) {
@@ -1308,7 +1317,7 @@ var movePathsIntoTarget = ({
1308
1317
  ancestorPath,
1309
1318
  newAncestorPath
1310
1319
  );
1311
- const newPathIsValid = validateMediaItemRename({
1320
+ const newPathIsValid = validateResourceRename({
1312
1321
  basename: path2.basename(descendantPath),
1313
1322
  selectedItemPath: newDescendantPath,
1314
1323
  media
@@ -1327,17 +1336,17 @@ var moveUpAFolder = ({
1327
1336
  selectedIds
1328
1337
  }) => {
1329
1338
  const indexPath = tree.findPath(
1330
- rootMediaItem,
1339
+ rootResource,
1331
1340
  (item) => item.id === selectedIds[0]
1332
1341
  );
1333
1342
  if (!indexPath) return;
1334
1343
  const grandparentFolder = tree.access(
1335
- rootMediaItem,
1344
+ rootResource,
1336
1345
  indexPath.slice(0, indexPath.length - 2)
1337
1346
  );
1338
1347
  const grandparentFolderPath = tree.idToPathMap.get(grandparentFolder.id);
1339
1348
  if (!grandparentFolderPath) return;
1340
- const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((path5) => Boolean(path5));
1349
+ const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
1341
1350
  return movePathsIntoTarget({
1342
1351
  media,
1343
1352
  targetItemPath: grandparentFolderPath,
@@ -1366,7 +1375,7 @@ var updateExpandedMap = ({
1366
1375
  const newExpandedMap = { ...expandedMap };
1367
1376
  const inner = (item2, expanded2) => {
1368
1377
  if (!expandable) return {};
1369
- if (item2.id === rootMediaItem.id) return {};
1378
+ if (item2.id === rootResource.id) return {};
1370
1379
  if (!expanded2) {
1371
1380
  const children = tree.getChildren(item2, []);
1372
1381
  children.forEach((child) => inner(child, false));
@@ -1376,13 +1385,13 @@ var updateExpandedMap = ({
1376
1385
  inner(item, expanded);
1377
1386
  return newExpandedMap;
1378
1387
  };
1379
- var deleteMediaItems = ({
1388
+ var deleteResources = ({
1380
1389
  selectedIds,
1381
1390
  media,
1382
1391
  tree
1383
1392
  }) => {
1384
1393
  const itemsToDelete = selectedIds.flatMap((mediaItemId) => {
1385
- const mediaItem = tree.mediaItemsWithRoot.find(
1394
+ const mediaItem = tree.resourcesWithRoot.find(
1386
1395
  (item) => item.id === mediaItemId
1387
1396
  );
1388
1397
  if (!mediaItem) return [];
@@ -1403,7 +1412,7 @@ var moveMediaInsideFolder = ({
1403
1412
  }) => {
1404
1413
  const targetItemPath = tree.idToPathMap.get(targetItemId);
1405
1414
  if (!targetItemPath) return media;
1406
- const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((path5) => Boolean(path5));
1415
+ const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
1407
1416
  return movePathsIntoTarget({
1408
1417
  media,
1409
1418
  sourceItemPaths,
@@ -1411,16 +1420,13 @@ var moveMediaInsideFolder = ({
1411
1420
  tree
1412
1421
  });
1413
1422
  };
1414
- var getParentDirectories = (mediaMap, folderId) => {
1415
- const tree = createMediaItemTree(mediaMap);
1416
- const indexPath = tree.findPath(
1417
- rootMediaItem,
1418
- (item) => item.id === folderId
1419
- );
1420
- if (!indexPath) return [rootMediaItem];
1421
- return tree.accessPath(rootMediaItem, indexPath);
1423
+ var getParentDirectories = (resourceMap, folderId) => {
1424
+ const tree = createResourceTree(resourceMap);
1425
+ const indexPath = tree.findPath(rootResource, (item) => item.id === folderId);
1426
+ if (!indexPath) return [rootResource];
1427
+ return tree.accessPath(rootResource, indexPath);
1422
1428
  };
1423
- var renameMediaItemAndDescendantPaths = ({
1429
+ var renameResourceAndDescendantPaths = ({
1424
1430
  newName,
1425
1431
  selectedItemPath,
1426
1432
  media,
@@ -1438,175 +1444,280 @@ var renameMediaItemAndDescendantPaths = ({
1438
1444
  selectedItemPath,
1439
1445
  newItemPath
1440
1446
  );
1441
- mediaClone[newDescendantPath] = mediaClone[descendantPath];
1447
+ mediaClone[newDescendantPath] = {
1448
+ ...mediaClone[descendantPath],
1449
+ path: newDescendantPath
1450
+ };
1442
1451
  delete mediaClone[descendantPath];
1443
1452
  }
1444
1453
  return mediaClone;
1445
1454
  };
1446
1455
 
1447
- // src/utils/handleFileDrop.ts
1448
- import { path as path3 } from "imfs";
1449
- function isDirectoryEntry(entry) {
1450
- return entry.isDirectory;
1451
- }
1452
- function isFileEntry(entry) {
1453
- return entry.isFile;
1454
- }
1455
- async function handleDataTransfer({
1456
- dataTransfer,
1457
- rootItemPath,
1456
+ // src/utils/files.ts
1457
+ var mediaGetVisibleItems = ({
1458
+ expandedMap,
1459
+ fileKindFilter,
1460
+ rootItemId,
1461
+ tree,
1462
+ showAllDescendants,
1463
+ showRootItem
1464
+ }) => {
1465
+ const filteredItems = [];
1466
+ const relativeRootItem = tree.find(rootMediaItem, (item) => item.id === rootItemId) ?? rootMediaItem;
1467
+ tree.visit(relativeRootItem, (item) => {
1468
+ if (relativeRootItem.id === item.id) {
1469
+ if (showRootItem) {
1470
+ filteredItems.push(item);
1471
+ }
1472
+ return;
1473
+ }
1474
+ if (item.kind === "noyaFile" && fileKindFilter === "all") {
1475
+ filteredItems.push(item);
1476
+ }
1477
+ if (item.kind === "file" && fileKindFilter === "all") {
1478
+ filteredItems.push(item);
1479
+ }
1480
+ if (item.kind === "asset" && (fileKindFilter === "assets" || fileKindFilter === "all")) {
1481
+ filteredItems.push(item);
1482
+ }
1483
+ if (item.kind === "folder" && (fileKindFilter === "directories" || fileKindFilter === "all")) {
1484
+ filteredItems.push(item);
1485
+ }
1486
+ if (!expandedMap[item.id] || !showAllDescendants) return "skip";
1487
+ });
1488
+ return filteredItems;
1489
+ };
1490
+ var mediaValidateMediaItemRename = ({
1491
+ basename,
1492
+ selectedItemPath,
1493
+ media
1494
+ }) => {
1495
+ if (!basenameValidator(basename)) return false;
1496
+ const newItemPath = path3.join(path3.dirname(selectedItemPath), basename);
1497
+ const newPathExists = media[newItemPath];
1498
+ if (newPathExists) return false;
1499
+ return true;
1500
+ };
1501
+ var mediaMovePathsIntoTarget = ({
1458
1502
  media,
1459
- uploadAsset
1460
- }) {
1461
- try {
1462
- const dataTransferItems = Array.from(dataTransfer.items ?? []);
1463
- const supportsEntries = dataTransferItems.some(
1464
- (item) => typeof item?.webkitGetAsEntry === "function"
1503
+ sourceItemPaths,
1504
+ targetItemPath,
1505
+ tree
1506
+ }) => {
1507
+ const ancestors = (0, import_tree_visit3.ancestorPaths)(
1508
+ sourceItemPaths.map((path7) => path7.split("/"))
1509
+ );
1510
+ const mediaClone = { ...media };
1511
+ for (const ancestor of ancestors) {
1512
+ const ancestorPath = ancestor.join("/");
1513
+ const ancestorItem = mediaClone[ancestorPath];
1514
+ const newAncestorPath = path3.join(
1515
+ targetItemPath,
1516
+ path3.basename(ancestorPath)
1465
1517
  );
1466
- const collectFromEntry = async (entry, basePath) => {
1467
- if (!entry) return [];
1468
- if (isFileEntry(entry)) {
1469
- const file = await new Promise(
1470
- (resolve) => entry.file((f) => resolve(f))
1471
- );
1472
- return [
1473
- {
1474
- file,
1475
- relativePath: path3.join(basePath, file.name)
1476
- }
1477
- ];
1478
- }
1479
- if (isDirectoryEntry(entry)) {
1480
- const reader = entry.createReader();
1481
- const readAll = async () => {
1482
- const all = [];
1483
- while (true) {
1484
- const entries = await new Promise(
1485
- (resolve) => reader.readEntries((ents) => resolve(ents))
1486
- );
1487
- if (!entries.length) break;
1488
- all.push(...entries);
1489
- }
1490
- return all;
1491
- };
1492
- const children = await readAll();
1493
- const results = await Promise.all(
1494
- children.map(
1495
- (child) => collectFromEntry(child, path3.join(basePath, entry.name))
1496
- )
1497
- );
1498
- return results.flat();
1499
- }
1500
- return [];
1501
- };
1502
- let dropped = [];
1503
- if (supportsEntries) {
1504
- const topLevelEntries = dataTransferItems.flatMap((item) => {
1505
- const entry = item.webkitGetAsEntry?.();
1506
- if (!entry) return [];
1507
- return [entry];
1508
- });
1509
- const nested = await Promise.all(
1510
- topLevelEntries.map((entry) => collectFromEntry(entry, ""))
1518
+ if (!ancestorItem) continue;
1519
+ const descendantPaths = tree.flat(ancestorItem).map((item) => tree.idToPathMap.get(item.id));
1520
+ for (const descendantPath of descendantPaths) {
1521
+ if (!descendantPath) continue;
1522
+ const newDescendantPath = descendantPath.replace(
1523
+ ancestorPath,
1524
+ newAncestorPath
1511
1525
  );
1512
- dropped = nested.flat();
1513
- } else {
1514
- const files = Array.from(dataTransfer.files);
1515
- if (files.length === 0) return;
1516
- dropped = files.map((file) => ({
1517
- file,
1518
- // Best effort: try webkitRelativePath; fall back to name
1519
- relativePath: file.webkitRelativePath && file.webkitRelativePath.length > 0 ? file.webkitRelativePath : file.name
1520
- }));
1521
- }
1522
- if (dropped.length === 0) return;
1523
- const folderRelativePaths = /* @__PURE__ */ new Set();
1524
- for (const { relativePath } of dropped) {
1525
- const dir = path3.dirname(relativePath);
1526
- if (dir && dir !== ".") {
1527
- const parts = dir.split("/").filter(Boolean);
1528
- let acc = "";
1529
- for (const part of parts) {
1530
- acc = acc ? path3.join(acc, part) : part;
1531
- folderRelativePaths.add(acc);
1532
- }
1526
+ const newPathIsValid = mediaValidateMediaItemRename({
1527
+ basename: path3.basename(descendantPath),
1528
+ selectedItemPath: newDescendantPath,
1529
+ media
1530
+ });
1531
+ if (newPathIsValid) {
1532
+ mediaClone[newDescendantPath] = mediaClone[descendantPath];
1533
+ delete mediaClone[descendantPath];
1533
1534
  }
1534
1535
  }
1535
- const folderEntries = Array.from(folderRelativePaths).map((rel) => path3.join(rootItemPath, rel)).filter((full) => !media[full]).map((full) => [full, createMediaFolder()]);
1536
- const uploadResults = await Promise.all(
1537
- dropped.map(
1538
- async ({ file, relativePath }) => {
1539
- const asset = await uploadAsset(file);
1540
- return [
1541
- path3.join(rootItemPath, relativePath),
1542
- createMediaAsset({ assetId: asset.id })
1543
- ];
1544
- }
1545
- )
1546
- );
1547
- return {
1548
- ...media,
1549
- ...Object.fromEntries([...folderEntries, ...uploadResults])
1550
- };
1551
- } catch (error) {
1552
- console.error("Failed to upload dropped files:", error);
1553
1536
  }
1554
- }
1555
-
1556
- // src/MediaCollection.tsx
1557
- var extensionToContentType = {
1558
- svg: "image/svg+xml",
1559
- png: "image/png",
1560
- jpeg: "image/jpeg"
1537
+ return mediaClone;
1561
1538
  };
1562
- function encodeFileContentForThumbnail(pathProp, item) {
1563
- const extension = path4.extname(pathProp).slice(1);
1564
- const contentType = extensionToContentType[extension];
1565
- if (contentType) {
1566
- if (item.encoding === "base64") {
1567
- return {
1568
- contentType,
1569
- url: `data:${contentType};base64,${item.content}`
1570
- };
1539
+ var mediaMoveUpAFolder = ({
1540
+ tree,
1541
+ media,
1542
+ selectedIds
1543
+ }) => {
1544
+ const indexPath = tree.findPath(
1545
+ rootMediaItem,
1546
+ (item) => item.id === selectedIds[0]
1547
+ );
1548
+ if (!indexPath) return;
1549
+ const grandparentFolder = tree.access(
1550
+ rootMediaItem,
1551
+ indexPath.slice(0, indexPath.length - 2)
1552
+ );
1553
+ const grandparentFolderPath = tree.idToPathMap.get(grandparentFolder.id);
1554
+ if (!grandparentFolderPath) return;
1555
+ const sourceItemPaths = selectedIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
1556
+ return mediaMovePathsIntoTarget({
1557
+ media,
1558
+ targetItemPath: grandparentFolderPath,
1559
+ sourceItemPaths,
1560
+ tree
1561
+ });
1562
+ };
1563
+ var mediaGetDepthMap = (item, tree, showAllDescendants) => {
1564
+ const depthMap = {};
1565
+ tree.visit(item, (item2, indexPath) => {
1566
+ if (showAllDescendants) {
1567
+ depthMap[item2.id] = Math.max(indexPath.length - 1, 0);
1571
1568
  } else {
1572
- try {
1573
- return {
1574
- contentType,
1575
- url: `data:${contentType},${encodeURIComponent(item.content)}`
1576
- };
1577
- } catch (error) {
1578
- console.warn("Failed to encode content:", error);
1579
- return { contentType };
1580
- }
1581
- }
1582
- }
1583
- return void 0;
1584
- }
1585
- var MediaThumbnailInternal = memoGeneric(
1586
- ({
1587
- item,
1588
- selected,
1589
- size,
1590
- path: pathProp,
1591
- renderThumbnailIcon
1592
- }) => {
1593
- const asset = useAsset(item.kind === "asset" ? item.assetId : void 0);
1594
- const isRoot = item.id === rootMediaItem.id;
1595
- const isFolder = item.kind === "folder";
1596
- const isFile = item.kind === "file";
1597
- let contentType;
1598
- let url;
1599
- if (asset) {
1600
- contentType = asset.contentType;
1601
- url = asset.url;
1602
- } else if (isFile && pathProp) {
1603
- const encoded = encodeFileContentForThumbnail(pathProp, item);
1604
- if (encoded) {
1605
- contentType = encoded.contentType;
1606
- url = encoded.url;
1607
- }
1569
+ depthMap[item2.id] = 0;
1570
+ }
1571
+ });
1572
+ return depthMap;
1573
+ };
1574
+ var mediaUpdateExpandedMap = ({
1575
+ item,
1576
+ expanded,
1577
+ expandable,
1578
+ expandedMap,
1579
+ tree
1580
+ }) => {
1581
+ const newExpandedMap = { ...expandedMap };
1582
+ const inner = (item2, expanded2) => {
1583
+ if (!expandable) return {};
1584
+ if (item2.id === rootMediaItem.id) return {};
1585
+ if (!expanded2) {
1586
+ const children = tree.getChildren(item2, []);
1587
+ children.forEach((child) => inner(child, false));
1588
+ }
1589
+ newExpandedMap[item2.id] = expanded2;
1590
+ };
1591
+ inner(item, expanded);
1592
+ return newExpandedMap;
1593
+ };
1594
+ var mediaDeleteMediaItems = ({
1595
+ selectedIds,
1596
+ media,
1597
+ tree
1598
+ }) => {
1599
+ const itemsToDelete = selectedIds.flatMap((mediaItemId) => {
1600
+ const mediaItem = tree.mediaItemsWithRoot.find(
1601
+ (item) => item.id === mediaItemId
1602
+ );
1603
+ if (!mediaItem) return [];
1604
+ return tree.flat(mediaItem);
1605
+ });
1606
+ const itemKeysToDelete = new Set(
1607
+ itemsToDelete.map((item) => tree.idToPathMap.get(item.id))
1608
+ );
1609
+ return Object.fromEntries(
1610
+ Object.entries(media).filter(([key]) => !itemKeysToDelete.has(key))
1611
+ );
1612
+ };
1613
+ var mediaMoveMediaInsideFolder = ({
1614
+ sourceItemIds,
1615
+ targetItemId,
1616
+ media,
1617
+ tree
1618
+ }) => {
1619
+ const targetItemPath = tree.idToPathMap.get(targetItemId);
1620
+ if (!targetItemPath) return media;
1621
+ const sourceItemPaths = sourceItemIds.map((id) => tree.idToPathMap.get(id)).filter((path7) => Boolean(path7));
1622
+ return mediaMovePathsIntoTarget({
1623
+ media,
1624
+ sourceItemPaths,
1625
+ targetItemPath,
1626
+ tree
1627
+ });
1628
+ };
1629
+ var mediaGetParentDirectories = (mediaMap, folderId) => {
1630
+ const tree = createMediaItemTree(mediaMap);
1631
+ const indexPath = tree.findPath(
1632
+ rootMediaItem,
1633
+ (item) => item.id === folderId
1634
+ );
1635
+ if (!indexPath) return [rootMediaItem];
1636
+ return tree.accessPath(rootMediaItem, indexPath);
1637
+ };
1638
+ var mediaRenameMediaItemAndDescendantPaths = ({
1639
+ newName,
1640
+ selectedItemPath,
1641
+ media,
1642
+ tree
1643
+ }) => {
1644
+ const mediaClone = { ...media };
1645
+ const selectedItem = mediaClone[selectedItemPath];
1646
+ if (!selectedItem) return mediaClone;
1647
+ const parentPath = path3.dirname(selectedItemPath);
1648
+ const newItemPath = path3.join(parentPath, newName);
1649
+ const descendants = tree.flat(selectedItem).map((item) => tree.idToPathMap.get(item.id));
1650
+ for (const descendantPath of descendants) {
1651
+ if (!descendantPath) continue;
1652
+ const newDescendantPath = descendantPath.replace(
1653
+ selectedItemPath,
1654
+ newItemPath
1655
+ );
1656
+ mediaClone[newDescendantPath] = mediaClone[descendantPath];
1657
+ delete mediaClone[descendantPath];
1658
+ }
1659
+ return mediaClone;
1660
+ };
1661
+
1662
+ // src/MediaCollection.tsx
1663
+ var extensionToContentType = {
1664
+ svg: "image/svg+xml",
1665
+ png: "image/png",
1666
+ jpeg: "image/jpeg"
1667
+ };
1668
+ function encodeFileContentForThumbnail(pathProp, item) {
1669
+ const extension = path4.extname(pathProp).slice(1);
1670
+ const contentType = extensionToContentType[extension];
1671
+ if (contentType) {
1672
+ if (item.encoding === "base64") {
1673
+ return {
1674
+ contentType,
1675
+ url: `data:${contentType};base64,${item.content}`
1676
+ };
1677
+ } else {
1678
+ try {
1679
+ return {
1680
+ contentType,
1681
+ url: `data:${contentType},${encodeURIComponent(item.content)}`
1682
+ };
1683
+ } catch (error) {
1684
+ console.warn("Failed to encode content:", error);
1685
+ return { contentType };
1686
+ }
1687
+ }
1688
+ }
1689
+ return void 0;
1690
+ }
1691
+ var MediaThumbnailInternal = memoGeneric(
1692
+ ({
1693
+ item,
1694
+ selected,
1695
+ size,
1696
+ path: pathProp,
1697
+ renderThumbnailIcon
1698
+ }) => {
1699
+ const asset = useAsset(item.kind === "asset" ? item.assetId : void 0);
1700
+ const isRoot = item.id === rootMediaItem.id;
1701
+ const isFolder = item.kind === "folder";
1702
+ const isFile = item.kind === "file";
1703
+ let contentType;
1704
+ let url;
1705
+ let width;
1706
+ let height;
1707
+ if (asset) {
1708
+ contentType = asset.contentType;
1709
+ url = asset.url;
1710
+ width = asset.width ?? void 0;
1711
+ height = asset.height ?? void 0;
1712
+ } else if (isFile && pathProp) {
1713
+ const encoded = encodeFileContentForThumbnail(pathProp, item);
1714
+ if (encoded) {
1715
+ contentType = encoded.contentType;
1716
+ url = encoded.url;
1717
+ }
1608
1718
  }
1609
1719
  const fileName = pathProp ? path4.basename(pathProp) : void 0;
1720
+ const dimensions = width && height ? { width, height } : void 0;
1610
1721
  return /* @__PURE__ */ React.createElement(
1611
1722
  MediaThumbnail,
1612
1723
  {
@@ -1616,7 +1727,8 @@ var MediaThumbnailInternal = memoGeneric(
1616
1727
  selected,
1617
1728
  size,
1618
1729
  fileName,
1619
- renderThumbnailIcon
1730
+ renderThumbnailIcon,
1731
+ dimensions
1620
1732
  }
1621
1733
  );
1622
1734
  }
@@ -1650,7 +1762,8 @@ var MediaCollection = memo(
1650
1762
  sharedDragProps,
1651
1763
  onClickItem,
1652
1764
  renderThumbnailIcon,
1653
- onDidDeleteItems
1765
+ onDidDeleteItems,
1766
+ onAssetsUploaded
1654
1767
  }, ref) {
1655
1768
  const setMedia = useCallback(
1656
1769
  (...args) => {
@@ -1691,7 +1804,7 @@ var MediaCollection = memo(
1691
1804
  const assets = useAssets();
1692
1805
  const [expandedMap, setExpandedMap] = useState({});
1693
1806
  const visibleItems = useMemo(
1694
- () => getVisibleItems({
1807
+ () => mediaGetVisibleItems({
1695
1808
  expandedMap,
1696
1809
  fileKindFilter,
1697
1810
  rootItemId,
@@ -1709,7 +1822,7 @@ var MediaCollection = memo(
1709
1822
  ]
1710
1823
  );
1711
1824
  const depthMap = useMemo(
1712
- () => getDepthMap(rootMediaItem, treeWithTempItem, showAllDescendants),
1825
+ () => mediaGetDepthMap(rootMediaItem, treeWithTempItem, showAllDescendants),
1713
1826
  [treeWithTempItem, showAllDescendants]
1714
1827
  );
1715
1828
  const collectionRef = useRef(null);
@@ -1748,17 +1861,23 @@ var MediaCollection = memo(
1748
1861
  },
1749
1862
  [expandedMap, expandable]
1750
1863
  );
1864
+ const openConfirmationDialog = useOpenConfirmationDialog();
1751
1865
  const handleDelete = useCallback(
1752
- (selectedIds2) => {
1866
+ async (selectedIds2) => {
1867
+ const ok = await openConfirmationDialog({
1868
+ title: "Delete items",
1869
+ description: "Are you sure you want to delete these items? This action cannot be undone."
1870
+ });
1871
+ if (!ok) return;
1753
1872
  const deletedItems = Object.entries(media).flatMap(
1754
- ([path5, item]) => {
1873
+ ([path7, item]) => {
1755
1874
  if (selectedIds2.includes(item.id)) {
1756
- return [[path5, item]];
1875
+ return [[path7, item]];
1757
1876
  }
1758
1877
  return [];
1759
1878
  }
1760
1879
  );
1761
- const newMedia = deleteMediaItems({
1880
+ const newMedia = mediaDeleteMediaItems({
1762
1881
  selectedIds: selectedIds2,
1763
1882
  media,
1764
1883
  tree
@@ -1767,7 +1886,14 @@ var MediaCollection = memo(
1767
1886
  setMedia({ name: "Delete items", timestamp: Date.now() }, newMedia);
1768
1887
  onDidDeleteItems?.(deletedItems);
1769
1888
  },
1770
- [media, setMedia, setSelectedIds, tree, onDidDeleteItems]
1889
+ [
1890
+ media,
1891
+ setMedia,
1892
+ setSelectedIds,
1893
+ tree,
1894
+ onDidDeleteItems,
1895
+ openConfirmationDialog
1896
+ ]
1771
1897
  );
1772
1898
  const onRename = useCallback(
1773
1899
  (selectedItem, newName) => {
@@ -1776,7 +1902,7 @@ var MediaCollection = memo(
1776
1902
  selectedItem.id
1777
1903
  );
1778
1904
  if (!selectedItemPath) return;
1779
- const renameIsValid = validateMediaItemRename({
1905
+ const renameIsValid = mediaValidateMediaItemRename({
1780
1906
  basename: newName,
1781
1907
  selectedItemPath,
1782
1908
  media: temp.media
@@ -1785,7 +1911,7 @@ var MediaCollection = memo(
1785
1911
  setTempItem(void 0);
1786
1912
  return;
1787
1913
  }
1788
- const mediaWithRenamedDescendantPaths = renameMediaItemAndDescendantPaths({
1914
+ const mediaWithRenamedDescendantPaths = mediaRenameMediaItemAndDescendantPaths({
1789
1915
  newName,
1790
1916
  selectedItemPath,
1791
1917
  media: temp.media,
@@ -1836,7 +1962,7 @@ var MediaCollection = memo(
1836
1962
  );
1837
1963
  const handleMoveUpAFolder = useCallback(
1838
1964
  (selectedIds2) => {
1839
- const newMedia = moveUpAFolder({
1965
+ const newMedia = mediaMoveUpAFolder({
1840
1966
  tree,
1841
1967
  media,
1842
1968
  selectedIds: selectedIds2
@@ -1863,23 +1989,28 @@ var MediaCollection = memo(
1863
1989
  };
1864
1990
  });
1865
1991
  setIsUploading(true);
1866
- const newMediaMap = await Promise.all(uploadPromises);
1992
+ const uploadedAssets = await Promise.all(uploadPromises);
1993
+ const newMediaMap = Object.fromEntries(
1994
+ uploadedAssets.map(({ assetPath, asset }) => [assetPath, asset])
1995
+ );
1867
1996
  setMedia(
1868
1997
  { name: "Add media items", timestamp: Date.now() },
1869
1998
  {
1870
1999
  ...media,
1871
- ...Object.fromEntries(
1872
- newMediaMap.map(({ assetPath, asset }) => [assetPath, asset])
1873
- )
2000
+ ...newMediaMap
1874
2001
  }
1875
2002
  );
2003
+ onAssetsUploaded?.(newMediaMap);
1876
2004
  } catch (error) {
1877
- console.error("Failed to upload files:", error);
2005
+ if (error instanceof Error && error.name === "AbortError") {
2006
+ } else {
2007
+ console.error("Failed to upload files:", error);
2008
+ }
1878
2009
  } finally {
1879
2010
  setIsUploading(false);
1880
2011
  }
1881
2012
  },
1882
- [tree.idToPathMap, setMedia, media, assetManager]
2013
+ [tree.idToPathMap, setMedia, media, assetManager, onAssetsUploaded]
1883
2014
  );
1884
2015
  const handleDownload = useCallback(
1885
2016
  async (selectedItems) => {
@@ -1923,7 +2054,10 @@ var MediaCollection = memo(
1923
2054
  }
1924
2055
  );
1925
2056
  } catch (error) {
1926
- console.error("Failed to upload file:", error);
2057
+ if (error instanceof Error && error.name === "AbortError") {
2058
+ } else {
2059
+ console.error("Failed to upload files:", error);
2060
+ }
1927
2061
  }
1928
2062
  },
1929
2063
  [media, setMedia, assetManager, tree]
@@ -1936,7 +2070,7 @@ var MediaCollection = memo(
1936
2070
  );
1937
2071
  const handleMoveMediaInsideFolder = useCallback(
1938
2072
  (sourceItem, targetItem) => {
1939
- const newMedia = moveMediaInsideFolder({
2073
+ const newMedia = mediaMoveMediaInsideFolder({
1940
2074
  sourceItemIds: [sourceItem.id],
1941
2075
  targetItemId: targetItem.id,
1942
2076
  media,
@@ -2055,7 +2189,7 @@ var MediaCollection = memo(
2055
2189
  const handleSetExpanded = useCallback(
2056
2190
  (item, expanded) => {
2057
2191
  setExpandedMap(
2058
- (prev) => updateExpandedMap({
2192
+ (prev) => mediaUpdateExpandedMap({
2059
2193
  item,
2060
2194
  expanded,
2061
2195
  expandable,
@@ -2225,22 +2359,6 @@ var MediaCollection = memo(
2225
2359
  if (position === "inside") {
2226
2360
  handleMoveMediaInsideFolder(sourceItem, targetItem);
2227
2361
  }
2228
- },
2229
- onFilesDrop: async (event) => {
2230
- event.preventDefault();
2231
- const rootItemPath = tree.idToPathMap.get(rootItemId);
2232
- if (!rootItemPath) return;
2233
- const newMedia = await handleDataTransfer({
2234
- dataTransfer: event.dataTransfer,
2235
- rootItemPath,
2236
- media,
2237
- uploadAsset: (file) => assetManager.create(file)
2238
- });
2239
- if (!newMedia) return;
2240
- setMedia(
2241
- { name: "Add media files", timestamp: Date.now() },
2242
- newMedia
2243
- );
2244
2362
  }
2245
2363
  }
2246
2364
  )
@@ -2266,28 +2384,1032 @@ function acceptsMediaItemDrop(parameters) {
2266
2384
  }
2267
2385
  return true;
2268
2386
  }
2387
+
2388
+ // src/ResourceExplorer.tsx
2389
+ import {
2390
+ ActionMenu as ActionMenu2,
2391
+ Chip,
2392
+ createSectionedMenu as createSectionedMenu2,
2393
+ cssVars as cssVars2,
2394
+ FileExplorerCollection as FileExplorerCollection2,
2395
+ FileExplorerDetail as FileExplorerDetail2,
2396
+ FileExplorerEmptyState as FileExplorerEmptyState2,
2397
+ FileExplorerLayout as FileExplorerLayout2,
2398
+ FileExplorerUploadButton as FileExplorerUploadButton2,
2399
+ formatByteSize as formatByteSize2,
2400
+ MediaThumbnail as MediaThumbnail2,
2401
+ useOpenConfirmationDialog as useOpenConfirmationDialog2
2402
+ } from "@noya-app/noya-designsystem";
2403
+ import {
2404
+ DownloadIcon as DownloadIcon2,
2405
+ FolderIcon as FolderIcon2,
2406
+ InputIcon as InputIcon2,
2407
+ OpenInNewWindowIcon as OpenInNewWindowIcon2,
2408
+ ResetIcon as ResetIcon2,
2409
+ TrashIcon as TrashIcon2,
2410
+ UpdateIcon as UpdateIcon2,
2411
+ UploadIcon as UploadIcon2
2412
+ } from "@noya-app/noya-icons";
2413
+ import {
2414
+ useAsset as useAsset2,
2415
+ useAssetManager as useAssetManager2,
2416
+ useAssets as useAssets2
2417
+ } from "@noya-app/noya-multiplayer-react";
2418
+ import {
2419
+ createAssetResource as createAssetResource2,
2420
+ createDirectoryResource as createDirectoryResource2,
2421
+ createResourceTree as createResourceTree2,
2422
+ diffResourceMaps,
2423
+ PLACEHOLDER_ITEM_NAME as PLACEHOLDER_ITEM_NAME2,
2424
+ rootResource as rootResource2,
2425
+ rootResourceName
2426
+ } from "@noya-app/noya-schemas";
2427
+ import { Base64 as Base642, groupBy as groupBy2, isDeepEqual as isDeepEqual2, uuid as uuid3 } from "@noya-app/noya-utils";
2428
+ import {
2429
+ AutoSizer,
2430
+ downloadUrl as downloadUrl2,
2431
+ memoGeneric as memoGeneric2,
2432
+ useControlledOrUncontrolled as useControlledOrUncontrolled2
2433
+ } from "@noya-app/react-utils";
2434
+ import { fileOpen as fileOpen2 } from "browser-fs-access";
2435
+ import {
2436
+ forwardRef as forwardRef2,
2437
+ memo as memo2,
2438
+ useCallback as useCallback2,
2439
+ useEffect as useEffect2,
2440
+ useImperativeHandle as useImperativeHandle2,
2441
+ useMemo as useMemo2,
2442
+ useRef as useRef2,
2443
+ useState as useState2
2444
+ } from "react";
2445
+ import { path as path6 } from "imfs";
2446
+ import React2 from "react";
2447
+
2448
+ // src/utils/handleFileDrop.ts
2449
+ import {
2450
+ createAssetResource,
2451
+ createDirectoryResource
2452
+ } from "@noya-app/noya-schemas";
2453
+ import { Base64, uuid as uuid2 } from "@noya-app/noya-utils";
2454
+ import { path as path5 } from "imfs";
2455
+ function isDirectoryEntry(entry) {
2456
+ return entry.isDirectory;
2457
+ }
2458
+ function isFileEntry(entry) {
2459
+ return entry.isFile;
2460
+ }
2461
+ async function handleDataTransfer({
2462
+ accessibleByFileId,
2463
+ dataTransfer,
2464
+ rootItemPath,
2465
+ resourceMap
2466
+ }) {
2467
+ try {
2468
+ const dataTransferItems = Array.from(dataTransfer.items ?? []);
2469
+ const supportsEntries = dataTransferItems.some(
2470
+ (item) => typeof item?.webkitGetAsEntry === "function"
2471
+ );
2472
+ const collectFromEntry = async (entry, basePath) => {
2473
+ if (!entry) return [];
2474
+ if (isFileEntry(entry)) {
2475
+ const file = await new Promise(
2476
+ (resolve) => entry.file((f) => resolve(f))
2477
+ );
2478
+ return [
2479
+ {
2480
+ file,
2481
+ relativePath: path5.join(basePath, file.name)
2482
+ }
2483
+ ];
2484
+ }
2485
+ if (isDirectoryEntry(entry)) {
2486
+ const reader = entry.createReader();
2487
+ const readAll = async () => {
2488
+ const all = [];
2489
+ while (true) {
2490
+ const entries = await new Promise(
2491
+ (resolve) => reader.readEntries((ents) => resolve(ents))
2492
+ );
2493
+ if (!entries.length) break;
2494
+ all.push(...entries);
2495
+ }
2496
+ return all;
2497
+ };
2498
+ const children = await readAll();
2499
+ const results = await Promise.all(
2500
+ children.map(
2501
+ (child) => collectFromEntry(child, path5.join(basePath, entry.name))
2502
+ )
2503
+ );
2504
+ return results.flat();
2505
+ }
2506
+ return [];
2507
+ };
2508
+ let dropped = [];
2509
+ if (supportsEntries) {
2510
+ const topLevelEntries = dataTransferItems.flatMap((item) => {
2511
+ const entry = item.webkitGetAsEntry?.();
2512
+ if (!entry) return [];
2513
+ return [entry];
2514
+ });
2515
+ const nested = await Promise.all(
2516
+ topLevelEntries.map((entry) => collectFromEntry(entry, ""))
2517
+ );
2518
+ dropped = nested.flat();
2519
+ } else {
2520
+ const files = Array.from(dataTransfer.files);
2521
+ if (files.length === 0) return;
2522
+ dropped = files.map((file) => ({
2523
+ file,
2524
+ // Best effort: try webkitRelativePath; fall back to name
2525
+ relativePath: file.webkitRelativePath && file.webkitRelativePath.length > 0 ? file.webkitRelativePath : file.name
2526
+ }));
2527
+ }
2528
+ if (dropped.length === 0) return;
2529
+ const folderRelativePaths = /* @__PURE__ */ new Set();
2530
+ for (const { relativePath } of dropped) {
2531
+ const dir = path5.dirname(relativePath);
2532
+ if (dir && dir !== ".") {
2533
+ const parts = dir.split("/").filter(Boolean);
2534
+ let acc = "";
2535
+ for (const part of parts) {
2536
+ acc = acc ? path5.join(acc, part) : part;
2537
+ folderRelativePaths.add(acc);
2538
+ }
2539
+ }
2540
+ }
2541
+ const folderEntries = Array.from(folderRelativePaths).map((rel) => path5.join(rootItemPath, rel)).filter((full) => !resourceMap[full]).map((full) => [
2542
+ full,
2543
+ createDirectoryResource({
2544
+ id: uuid2(),
2545
+ path: full,
2546
+ accessibleByFileId,
2547
+ stableId: uuid2()
2548
+ })
2549
+ ]);
2550
+ const uploadResults = await Promise.all(
2551
+ dropped.map(
2552
+ async ({ file, relativePath }) => {
2553
+ return [
2554
+ path5.join(rootItemPath, relativePath),
2555
+ createAssetResource({
2556
+ id: uuid2(),
2557
+ asset: {
2558
+ content: Base64.encode(await file.arrayBuffer()),
2559
+ contentType: file.type,
2560
+ encoding: "base64"
2561
+ },
2562
+ path: path5.join(rootItemPath, relativePath),
2563
+ accessibleByFileId,
2564
+ stableId: uuid2()
2565
+ })
2566
+ ];
2567
+ }
2568
+ )
2569
+ );
2570
+ return {
2571
+ ...resourceMap,
2572
+ ...Object.fromEntries([...folderEntries, ...uploadResults])
2573
+ };
2574
+ } catch (error) {
2575
+ console.error("Failed to upload dropped files:", error);
2576
+ }
2577
+ }
2578
+
2579
+ // src/ResourceExplorer.tsx
2580
+ var gridThumbnailDimension = {
2581
+ width: 800,
2582
+ height: 800
2583
+ };
2584
+ var ResourceThumbnail = memoGeneric2(
2585
+ ({
2586
+ item,
2587
+ selected,
2588
+ size,
2589
+ path: pathProp,
2590
+ renderThumbnailIcon,
2591
+ className,
2592
+ url: urlProp,
2593
+ contentType: contentTypeProp,
2594
+ viewType
2595
+ }) => {
2596
+ const asset = useAsset2(item.type === "asset" ? item.assetId : void 0);
2597
+ const isRoot = item.id === rootResource2.id;
2598
+ const isFolder = item.type === "directory";
2599
+ let contentType;
2600
+ let url;
2601
+ if (asset) {
2602
+ contentType = asset.contentType;
2603
+ url = asset.url;
2604
+ } else if (urlProp) {
2605
+ url = urlProp;
2606
+ contentType = contentTypeProp;
2607
+ }
2608
+ const fileName = pathProp ? path6.basename(pathProp) : void 0;
2609
+ return /* @__PURE__ */ React2.createElement(
2610
+ MediaThumbnail2,
2611
+ {
2612
+ contentType,
2613
+ iconName: isRoot ? "HomeIcon" : isFolder ? "FolderIcon" : void 0,
2614
+ url,
2615
+ selected,
2616
+ size,
2617
+ fileName,
2618
+ renderThumbnailIcon,
2619
+ dimensions: viewType === "grid" ? gridThumbnailDimension : void 0,
2620
+ className
2621
+ }
2622
+ );
2623
+ }
2624
+ );
2625
+ var ResourceExplorer = memo2(
2626
+ forwardRef2(
2627
+ function ResourceExplorer2({
2628
+ parentFileId,
2629
+ sortableId,
2630
+ onSelectionChange,
2631
+ selectedIds: selectedIdsProp,
2632
+ media,
2633
+ setMedia: setMediaProp,
2634
+ readOnly = false,
2635
+ viewType = "list",
2636
+ fileKindFilter = "all",
2637
+ showRootItem = false,
2638
+ initialExpanded,
2639
+ expandable = true,
2640
+ renamable = true,
2641
+ onDoubleClickItem,
2642
+ rootItemId = rootResource2.id,
2643
+ title,
2644
+ size = "medium",
2645
+ right,
2646
+ renderAction: renderActionProp,
2647
+ className,
2648
+ showUploadButton = true,
2649
+ showAllDescendants = true,
2650
+ scrollable = false,
2651
+ sortable = false,
2652
+ renderEmptyState,
2653
+ sharedDragProps,
2654
+ onClickItem,
2655
+ renderThumbnailIcon,
2656
+ onDidDeleteItems,
2657
+ onAssetsUploaded,
2658
+ itemClassName,
2659
+ itemStyle,
2660
+ publishedResources,
2661
+ virtualized = false,
2662
+ renderUser
2663
+ }, ref) {
2664
+ const setMedia = useCallback2(
2665
+ (...args) => {
2666
+ setMediaProp?.(...args);
2667
+ },
2668
+ [setMediaProp]
2669
+ );
2670
+ const tree = useMemo2(() => createResourceTree2(media), [media]);
2671
+ const [tempItem, setTempItem] = useState2(
2672
+ void 0
2673
+ );
2674
+ const mediaWithTempItem = useMemo2(
2675
+ () => ({
2676
+ ...media,
2677
+ ...tempItem ? { [tempItem[0]]: tempItem[1] } : {}
2678
+ }),
2679
+ [media, tempItem]
2680
+ );
2681
+ const treeWithTempItem = useMemo2(
2682
+ () => createResourceTree2(mediaWithTempItem),
2683
+ [mediaWithTempItem]
2684
+ );
2685
+ const temp = useMemo2(
2686
+ () => ({
2687
+ media: mediaWithTempItem,
2688
+ tree: treeWithTempItem
2689
+ }),
2690
+ [mediaWithTempItem, treeWithTempItem]
2691
+ );
2692
+ const [selectedIds, setSelectedIds] = useControlledOrUncontrolled2({
2693
+ defaultValue: [],
2694
+ value: selectedIdsProp,
2695
+ onChange: onSelectionChange
2696
+ });
2697
+ const assetManager = useAssetManager2();
2698
+ const assets = useAssets2();
2699
+ const [expandedMap, setExpandedMap] = useState2({});
2700
+ const visibleItems = useMemo2(
2701
+ () => getVisibleItems({
2702
+ expandedMap,
2703
+ fileKindFilter,
2704
+ rootItemId,
2705
+ tree: treeWithTempItem,
2706
+ showAllDescendants,
2707
+ showRootItem
2708
+ }),
2709
+ [
2710
+ expandedMap,
2711
+ fileKindFilter,
2712
+ rootItemId,
2713
+ treeWithTempItem,
2714
+ showAllDescendants,
2715
+ showRootItem
2716
+ ]
2717
+ );
2718
+ const depthMap = useMemo2(
2719
+ () => getDepthMap(rootResource2, treeWithTempItem, showAllDescendants),
2720
+ [treeWithTempItem, showAllDescendants]
2721
+ );
2722
+ const collectionRef = useRef2(null);
2723
+ const selectedResources = useMemo2(
2724
+ () => treeWithTempItem.resourcesWithRoot.filter(
2725
+ (item) => selectedIds.includes(item.id)
2726
+ ),
2727
+ [treeWithTempItem, selectedIds]
2728
+ );
2729
+ const groupedItems = groupBy2(selectedResources, (item) => item.type);
2730
+ const selectedAssetItems = groupedItems.asset ?? [];
2731
+ const selectedFolderItems = groupedItems.folder ?? [];
2732
+ const singleItemSelected = selectedResources.length === 1;
2733
+ const onlyAssetsSelected = selectedAssetItems.length > 0 && selectedAssetItems.length === selectedResources.length;
2734
+ const onlyFoldersSelected = selectedFolderItems.length > 0 && selectedFolderItems.length === selectedResources.length;
2735
+ const onlySingleFolderSelected = onlyFoldersSelected && selectedFolderItems.length === 1;
2736
+ const onlySingleAssetSelected = onlyAssetsSelected && selectedAssetItems.length === 1;
2737
+ const rootSelected = selectedIds.includes(rootResource2.id);
2738
+ const sameParentSelected = selectedResources.every((item) => {
2739
+ const itemPath = tree.idToPathMap.get(item.id);
2740
+ const firstSelectedPath = tree.idToPathMap.get(selectedIds[0]);
2741
+ if (!itemPath || !firstSelectedPath) return false;
2742
+ return itemPath.startsWith(path6.dirname(firstSelectedPath));
2743
+ });
2744
+ useEffect2(() => {
2745
+ if (initialExpanded) {
2746
+ setExpandedMap(initialExpanded);
2747
+ }
2748
+ }, [initialExpanded]);
2749
+ const getExpanded = useCallback2(
2750
+ (item) => {
2751
+ if (!expandable) return void 0;
2752
+ if (item.type !== "directory") return void 0;
2753
+ if (item.id === rootResource2.id) return void 0;
2754
+ return expandedMap[item.id] ?? false;
2755
+ },
2756
+ [expandedMap, expandable]
2757
+ );
2758
+ const openConfirmationDialog = useOpenConfirmationDialog2();
2759
+ const handleDelete = useCallback2(
2760
+ async (selectedIds2) => {
2761
+ const ok = await openConfirmationDialog({
2762
+ title: "Delete items",
2763
+ description: "Are you sure you want to delete these items? This action cannot be undone."
2764
+ });
2765
+ if (!ok) return;
2766
+ const deletedItems = Object.entries(media).flatMap(
2767
+ ([path7, item]) => {
2768
+ if (selectedIds2.includes(item.id)) {
2769
+ return [[path7, item]];
2770
+ }
2771
+ return [];
2772
+ }
2773
+ );
2774
+ const newMedia = deleteResources({
2775
+ selectedIds: selectedIds2,
2776
+ media,
2777
+ tree
2778
+ });
2779
+ setSelectedIds([rootResource2.id]);
2780
+ setMedia({ name: "Delete items", timestamp: Date.now() }, newMedia);
2781
+ onDidDeleteItems?.(deletedItems);
2782
+ },
2783
+ [
2784
+ media,
2785
+ setMedia,
2786
+ setSelectedIds,
2787
+ tree,
2788
+ onDidDeleteItems,
2789
+ openConfirmationDialog
2790
+ ]
2791
+ );
2792
+ const onRename = useCallback2(
2793
+ (selectedItem, newName) => {
2794
+ if (!renamable) return;
2795
+ const selectedItemPath = treeWithTempItem.idToPathMap.get(
2796
+ selectedItem.id
2797
+ );
2798
+ if (!selectedItemPath) return;
2799
+ const renameIsValid = validateResourceRename({
2800
+ basename: newName,
2801
+ selectedItemPath,
2802
+ media: temp.media
2803
+ });
2804
+ if (!renameIsValid) {
2805
+ setTempItem(void 0);
2806
+ return;
2807
+ }
2808
+ const mediaWithRenamedDescendantPaths = renameResourceAndDescendantPaths({
2809
+ newName,
2810
+ selectedItemPath,
2811
+ media: temp.media,
2812
+ tree: temp.tree
2813
+ });
2814
+ setMedia(
2815
+ { name: "Rename media item", timestamp: Date.now() },
2816
+ mediaWithRenamedDescendantPaths
2817
+ );
2818
+ setTempItem(void 0);
2819
+ },
2820
+ [
2821
+ renamable,
2822
+ setMedia,
2823
+ temp.media,
2824
+ temp.tree,
2825
+ treeWithTempItem.idToPathMap
2826
+ ]
2827
+ );
2828
+ const handleAddFolder = useCallback2(
2829
+ (currentFolderId) => {
2830
+ const currentFolderPath = tree.idToPathMap.get(currentFolderId);
2831
+ if (!currentFolderPath) return;
2832
+ const newFolderPath = path6.join(
2833
+ currentFolderPath,
2834
+ PLACEHOLDER_ITEM_NAME2
2835
+ );
2836
+ const newFolder = createDirectoryResource2({
2837
+ path: newFolderPath,
2838
+ accessibleByFileId: parentFileId,
2839
+ id: newFolderPath,
2840
+ stableId: uuid3()
2841
+ });
2842
+ setTempItem([newFolderPath, newFolder]);
2843
+ setTimeout(() => {
2844
+ collectionRef.current?.editName(newFolder.id);
2845
+ }, 50);
2846
+ },
2847
+ [parentFileId, tree]
2848
+ );
2849
+ const handleMoveUpAFolder = useCallback2(
2850
+ (selectedIds2) => {
2851
+ const newMedia = moveUpAFolder({
2852
+ tree,
2853
+ media,
2854
+ selectedIds: selectedIds2
2855
+ });
2856
+ if (!newMedia) return;
2857
+ setMedia({ name: "Move items", timestamp: Date.now() }, newMedia);
2858
+ },
2859
+ [media, tree, setMedia]
2860
+ );
2861
+ const [isUploading, setIsUploading] = useState2(false);
2862
+ const handleUpload = useCallback2(
2863
+ async (selectedId) => {
2864
+ try {
2865
+ const files = await fileOpen2({ multiple: true });
2866
+ if (!files || !Array.isArray(files) || files.length === 0) return;
2867
+ const parentPath = tree.idToPathMap.get(selectedId);
2868
+ if (!parentPath) return;
2869
+ const uploadPromises = files.map(async (file) => {
2870
+ const assetPath = path6.join(parentPath, path6.basename(file.name));
2871
+ return {
2872
+ assetPath,
2873
+ asset: createAssetResource2({
2874
+ id: uuid3(),
2875
+ asset: {
2876
+ content: Base642.encode(await file.arrayBuffer()),
2877
+ contentType: file.type,
2878
+ encoding: "base64"
2879
+ },
2880
+ path: assetPath,
2881
+ accessibleByFileId: parentFileId,
2882
+ stableId: uuid3()
2883
+ })
2884
+ };
2885
+ });
2886
+ setIsUploading(true);
2887
+ const uploadedAssets = await Promise.all(uploadPromises);
2888
+ const newMediaMap = Object.fromEntries(
2889
+ uploadedAssets.map(({ assetPath, asset }) => [assetPath, asset])
2890
+ );
2891
+ setMedia(
2892
+ { name: "Add media items", timestamp: Date.now() },
2893
+ {
2894
+ ...media,
2895
+ ...newMediaMap
2896
+ }
2897
+ );
2898
+ onAssetsUploaded?.(newMediaMap);
2899
+ } catch (error) {
2900
+ if (error instanceof Error && error.name === "AbortError") {
2901
+ } else {
2902
+ console.error("Failed to upload files:", error);
2903
+ }
2904
+ } finally {
2905
+ setIsUploading(false);
2906
+ }
2907
+ },
2908
+ [tree, setMedia, media, onAssetsUploaded, parentFileId]
2909
+ );
2910
+ const handleDownload = useCallback2(
2911
+ async (selectedItems) => {
2912
+ const downloadPromises = selectedItems.filter((item) => item.type === "asset").map(async (item) => {
2913
+ const asset = assets.find((a) => a.id === item.assetId);
2914
+ if (!asset?.url) return;
2915
+ return downloadUrl2(asset.url, tree.getNameForId(item.id));
2916
+ });
2917
+ await Promise.all(downloadPromises);
2918
+ },
2919
+ [assets, tree]
2920
+ );
2921
+ const handlePreview = useCallback2(
2922
+ async (selectedItems) => {
2923
+ const previewPromises = selectedItems.filter((item) => item.type === "asset").map(async (item) => {
2924
+ const asset = assets.find((a) => a.id === item.assetId);
2925
+ if (!asset?.url) return;
2926
+ return window?.open(asset.url, "_blank");
2927
+ });
2928
+ await Promise.all(previewPromises);
2929
+ },
2930
+ [assets]
2931
+ );
2932
+ const handleReplace = useCallback2(
2933
+ async (selectedItem) => {
2934
+ try {
2935
+ const file = await fileOpen2();
2936
+ if (!file) return;
2937
+ const asset = await assetManager.create(file);
2938
+ const oldFile = selectedItem;
2939
+ const oldFilePath = tree.idToPathMap.get(oldFile.id);
2940
+ if (!oldFilePath || oldFile.type !== "asset") return;
2941
+ setMedia(
2942
+ { name: "Replace media file", timestamp: Date.now() },
2943
+ {
2944
+ ...media,
2945
+ [oldFilePath]: createAssetResource2({
2946
+ ...oldFile,
2947
+ assetId: asset.id
2948
+ })
2949
+ }
2950
+ );
2951
+ } catch (error) {
2952
+ if (error instanceof Error && error.name === "AbortError") {
2953
+ } else {
2954
+ console.error("Failed to upload files:", error);
2955
+ }
2956
+ }
2957
+ },
2958
+ [media, setMedia, assetManager, tree]
2959
+ );
2960
+ const handleRename = useCallback2(
2961
+ (selectedItemId) => {
2962
+ collectionRef.current?.editName(selectedItemId);
2963
+ },
2964
+ [collectionRef]
2965
+ );
2966
+ const handleMoveMediaInsideFolder = useCallback2(
2967
+ (sourceItems, targetItem) => {
2968
+ const newMedia = moveMediaInsideFolder({
2969
+ sourceItemIds: sourceItems.map((item) => item.id),
2970
+ targetItemId: targetItem.id,
2971
+ media,
2972
+ tree
2973
+ });
2974
+ setMedia(
2975
+ {
2976
+ name: "Move media file inside folder",
2977
+ timestamp: Date.now()
2978
+ },
2979
+ newMedia
2980
+ );
2981
+ },
2982
+ [media, setMedia, tree]
2983
+ );
2984
+ const assetContextMenuItems = useMemo2(() => {
2985
+ return createSectionedMenu2(
2986
+ [
2987
+ !rootSelected && singleItemSelected && {
2988
+ title: "Rename",
2989
+ value: "rename",
2990
+ icon: /* @__PURE__ */ React2.createElement(InputIcon2, null)
2991
+ },
2992
+ onlySingleAssetSelected && {
2993
+ title: "Replace",
2994
+ value: "replace",
2995
+ icon: /* @__PURE__ */ React2.createElement(UpdateIcon2, null)
2996
+ },
2997
+ !rootSelected && {
2998
+ title: "Delete",
2999
+ value: "delete",
3000
+ icon: /* @__PURE__ */ React2.createElement(TrashIcon2, null)
3001
+ }
3002
+ ],
3003
+ [
3004
+ onlySingleFolderSelected && {
3005
+ title: "Upload Files",
3006
+ value: "upload",
3007
+ icon: /* @__PURE__ */ React2.createElement(UploadIcon2, null)
3008
+ },
3009
+ onlySingleFolderSelected && {
3010
+ title: "Add Folder",
3011
+ value: "addFolder",
3012
+ icon: /* @__PURE__ */ React2.createElement(FolderIcon2, null)
3013
+ },
3014
+ onlyAssetsSelected && tree.resourcesWithRoot.length > 0 && {
3015
+ title: "Download",
3016
+ value: "download",
3017
+ icon: /* @__PURE__ */ React2.createElement(DownloadIcon2, null)
3018
+ },
3019
+ onlySingleAssetSelected && {
3020
+ title: "Preview",
3021
+ value: "preview",
3022
+ icon: /* @__PURE__ */ React2.createElement(OpenInNewWindowIcon2, null)
3023
+ }
3024
+ ],
3025
+ [
3026
+ !rootSelected && sameParentSelected && {
3027
+ title: "Move up a folder",
3028
+ value: "move",
3029
+ icon: /* @__PURE__ */ React2.createElement(ResetIcon2, null)
3030
+ }
3031
+ ]
3032
+ );
3033
+ }, [
3034
+ rootSelected,
3035
+ singleItemSelected,
3036
+ onlySingleAssetSelected,
3037
+ onlySingleFolderSelected,
3038
+ onlyAssetsSelected,
3039
+ tree.resourcesWithRoot.length,
3040
+ sameParentSelected
3041
+ ]);
3042
+ const handleMenuAction = useCallback2(
3043
+ async (action, selectedItems) => {
3044
+ if (selectedItems.length === 0) return;
3045
+ switch (action) {
3046
+ case "rename":
3047
+ handleRename(selectedItems[0].id);
3048
+ return;
3049
+ case "delete":
3050
+ handleDelete(selectedIds);
3051
+ return;
3052
+ case "replace":
3053
+ handleReplace(selectedItems[0]);
3054
+ return;
3055
+ case "upload":
3056
+ handleUpload(selectedItems[0].id);
3057
+ return;
3058
+ case "addFolder":
3059
+ handleAddFolder(selectedItems[0].id);
3060
+ return;
3061
+ case "preview":
3062
+ handlePreview(selectedItems);
3063
+ return;
3064
+ case "download":
3065
+ handleDownload(selectedItems);
3066
+ return;
3067
+ case "move":
3068
+ handleMoveUpAFolder(selectedIds);
3069
+ return;
3070
+ }
3071
+ },
3072
+ [
3073
+ handleRename,
3074
+ handleDelete,
3075
+ selectedIds,
3076
+ handleReplace,
3077
+ handleUpload,
3078
+ handleAddFolder,
3079
+ handlePreview,
3080
+ handleDownload,
3081
+ handleMoveUpAFolder
3082
+ ]
3083
+ );
3084
+ const handleSetExpanded = useCallback2(
3085
+ (item, expanded) => {
3086
+ setExpandedMap(
3087
+ (prev) => updateExpandedMap({
3088
+ item,
3089
+ expanded,
3090
+ expandable,
3091
+ expandedMap: prev,
3092
+ tree
3093
+ })
3094
+ );
3095
+ },
3096
+ [expandable, tree]
3097
+ );
3098
+ const renderAction = useMemo2(() => {
3099
+ if (renderActionProp) return renderActionProp;
3100
+ return ({
3101
+ selected,
3102
+ onOpenChange
3103
+ }) => /* @__PURE__ */ React2.createElement(
3104
+ "div",
3105
+ {
3106
+ style: {
3107
+ minWidth: "75px",
3108
+ display: "flex",
3109
+ justifyContent: "flex-end"
3110
+ }
3111
+ },
3112
+ /* @__PURE__ */ React2.createElement(
3113
+ ActionMenu2,
3114
+ {
3115
+ menuItems: assetContextMenuItems,
3116
+ onSelect: (action) => handleMenuAction(action, selectedResources),
3117
+ selected,
3118
+ onOpenChange,
3119
+ variant: viewType === "grid" ? "normal" : "bare",
3120
+ style: {
3121
+ backgroundColor: selected ? cssVars2.colors.selectedListItemBackground : "transparent",
3122
+ color: selected ? cssVars2.colors.selectedListItemText : void 0
3123
+ }
3124
+ }
3125
+ )
3126
+ );
3127
+ }, [
3128
+ assetContextMenuItems,
3129
+ handleMenuAction,
3130
+ renderActionProp,
3131
+ selectedResources,
3132
+ viewType
3133
+ ]);
3134
+ useImperativeHandle2(ref, () => ({
3135
+ upload: (selectedId) => handleUpload(selectedId),
3136
+ delete: handleDelete,
3137
+ download: handleDownload,
3138
+ rename: handleRename,
3139
+ addFolder: handleAddFolder,
3140
+ moveUpAFolder: handleMoveUpAFolder,
3141
+ replace: handleReplace,
3142
+ preview: handlePreview,
3143
+ moveMediaInsideFolder: handleMoveMediaInsideFolder,
3144
+ getItemAtIndex: (index) => visibleItems[index]
3145
+ }));
3146
+ const diffResources = useMemo2(() => {
3147
+ if (!publishedResources) return;
3148
+ const diff = diffResourceMaps(publishedResources, media, "stableId");
3149
+ return {
3150
+ added: new Set(
3151
+ diff.addedResources.map((resource) => resource.stableId)
3152
+ ),
3153
+ removed: new Set(
3154
+ diff.removedResources.map((resource) => resource.stableId)
3155
+ ),
3156
+ modified: new Set(
3157
+ diff.modifiedResources.map((resource) => resource.stableId)
3158
+ )
3159
+ };
3160
+ }, [media, publishedResources]);
3161
+ const keyExtractor = useCallback2((item) => item.id, []);
3162
+ const renderCollection = (virtualizedSize) => /* @__PURE__ */ React2.createElement(
3163
+ FileExplorerCollection2,
3164
+ {
3165
+ ref: collectionRef,
3166
+ sortableId,
3167
+ scrollable,
3168
+ sharedDragProps,
3169
+ items: visibleItems,
3170
+ viewType,
3171
+ size,
3172
+ getId: keyExtractor,
3173
+ getName: (file) => {
3174
+ if (file.id === tempItem?.[1].id) {
3175
+ return "";
3176
+ }
3177
+ return treeWithTempItem.getNameForId(file.id);
3178
+ },
3179
+ expandable,
3180
+ sortable,
3181
+ getPlaceholder: (item) => {
3182
+ switch (item.type) {
3183
+ case "directory":
3184
+ return "Enter folder name";
3185
+ case "resource":
3186
+ case "asset":
3187
+ case "file":
3188
+ return "Enter file name";
3189
+ }
3190
+ },
3191
+ getExpanded,
3192
+ setExpanded: handleSetExpanded,
3193
+ getRenamable: (item) => {
3194
+ if (item.id === rootResource2.id) return false;
3195
+ return true;
3196
+ },
3197
+ getDepth: (item) => depthMap[item.id],
3198
+ menuItems: assetContextMenuItems,
3199
+ onSelectMenuItem: handleMenuAction,
3200
+ onSelectionChange: setSelectedIds,
3201
+ onClickItem,
3202
+ onClick: () => {
3203
+ setSelectedIds([]);
3204
+ },
3205
+ onDoubleClickItem,
3206
+ onRename,
3207
+ renamable,
3208
+ selectedIds,
3209
+ itemClassName,
3210
+ itemStyle,
3211
+ virtualized: virtualizedSize,
3212
+ renderThumbnail: (props) => /* @__PURE__ */ React2.createElement(
3213
+ ResourceThumbnail,
3214
+ {
3215
+ ...props,
3216
+ path: tree.idToPathMap.get(props.item.id),
3217
+ renderThumbnailIcon,
3218
+ viewType
3219
+ }
3220
+ ),
3221
+ renderAction,
3222
+ renderRight: (file) => {
3223
+ if (file.type !== "asset") return null;
3224
+ const publishStatus = getPublishStatus({
3225
+ resource: file,
3226
+ diff: diffResources
3227
+ });
3228
+ return /* @__PURE__ */ React2.createElement(
3229
+ "div",
3230
+ {
3231
+ style: { display: "flex", alignItems: "center", gap: "1.5px" }
3232
+ },
3233
+ publishStatus && /* @__PURE__ */ React2.createElement(
3234
+ Chip,
3235
+ {
3236
+ colorScheme: publishStatus === "Modified" ? "info" : publishStatus === "Added" ? "secondary" : "primary"
3237
+ },
3238
+ publishStatus
3239
+ ),
3240
+ renderUser?.(file)
3241
+ );
3242
+ },
3243
+ renderDetail: (file, selected) => {
3244
+ if (file.type !== "asset") return null;
3245
+ const asset = assets.find((a) => a.id === file.assetId);
3246
+ if (!asset) return null;
3247
+ return /* @__PURE__ */ React2.createElement(
3248
+ FileExplorerDetail2,
3249
+ {
3250
+ selected,
3251
+ size,
3252
+ style: { minWidth: "75px", textAlign: "right" }
3253
+ },
3254
+ formatByteSize2(asset.size)
3255
+ );
3256
+ },
3257
+ renderEmptyState: () => renderEmptyState?.() ?? /* @__PURE__ */ React2.createElement(FileExplorerEmptyState2, null),
3258
+ itemRoleDescription: "clickable file item",
3259
+ getDropTargetParentIndex: (overIndex) => {
3260
+ const item = visibleItems[overIndex];
3261
+ const parentIndex = visibleItems.findIndex(
3262
+ (i) => i.id === tree.getParentIdForId(item.id)
3263
+ );
3264
+ return parentIndex === -1 ? void 0 : parentIndex;
3265
+ },
3266
+ acceptsDrop: ({
3267
+ sourceIndex,
3268
+ targetIndex,
3269
+ position,
3270
+ sourceListId,
3271
+ targetListId
3272
+ }) => {
3273
+ if (sourceListId !== targetListId) {
3274
+ return false;
3275
+ }
3276
+ if (sourceListId !== sortableId || targetListId !== sortableId) {
3277
+ return false;
3278
+ }
3279
+ const sourceItem = visibleItems[sourceIndex];
3280
+ const targetItem = visibleItems[targetIndex];
3281
+ return acceptsResourceDrop({
3282
+ position,
3283
+ sourceItem,
3284
+ targetItem,
3285
+ tree
3286
+ });
3287
+ },
3288
+ onMoveItem: ({
3289
+ sourceListId,
3290
+ sourceIndex,
3291
+ targetListId,
3292
+ targetIndex,
3293
+ position
3294
+ }) => {
3295
+ if (sourceListId !== sortableId || targetListId !== sortableId || position !== "inside") {
3296
+ return;
3297
+ }
3298
+ const selectedItems = visibleItems.filter(
3299
+ (item) => selectedIds.includes(item.id)
3300
+ );
3301
+ const sourceItem = visibleItems[sourceIndex];
3302
+ const itemsToMove = selectedIds.includes(sourceItem.id) ? selectedItems : [sourceItem];
3303
+ const targetItem = visibleItems[targetIndex];
3304
+ handleMoveMediaInsideFolder(itemsToMove, targetItem);
3305
+ },
3306
+ onFilesDrop: async (event) => {
3307
+ event.preventDefault();
3308
+ const rootItemPath = tree.idToPathMap.get(rootItemId);
3309
+ if (!rootItemPath) return;
3310
+ const newMedia = await handleDataTransfer({
3311
+ dataTransfer: event.dataTransfer,
3312
+ rootItemPath,
3313
+ resourceMap: media,
3314
+ accessibleByFileId: parentFileId
3315
+ });
3316
+ if (!newMedia) return;
3317
+ setMedia(
3318
+ { name: "Add media files", timestamp: Date.now() },
3319
+ newMedia
3320
+ );
3321
+ }
3322
+ }
3323
+ );
3324
+ return /* @__PURE__ */ React2.createElement(
3325
+ FileExplorerLayout2,
3326
+ {
3327
+ title: title ?? rootResourceName,
3328
+ right: !readOnly && /* @__PURE__ */ React2.createElement(
3329
+ FileExplorerUploadButton2,
3330
+ {
3331
+ showUploadButton,
3332
+ onUpload: () => handleUpload(rootResource2.id),
3333
+ isUploading
3334
+ },
3335
+ right
3336
+ ),
3337
+ className
3338
+ },
3339
+ virtualized ? /* @__PURE__ */ React2.createElement(AutoSizer, null, ({ width, height }) => (
3340
+ // add 24px to account for the -mx-3 on the Collection component
3341
+ renderCollection({ width: width + 24, height })
3342
+ )) : renderCollection(void 0)
3343
+ );
3344
+ }
3345
+ )
3346
+ );
3347
+ function acceptsResourceDrop(parameters) {
3348
+ const { position, sourceItem, targetItem, tree } = parameters;
3349
+ if (position !== "inside" || targetItem.type === "asset") {
3350
+ return false;
3351
+ }
3352
+ const sourcePath = tree.findPath(
3353
+ rootResource2,
3354
+ (item) => item.id === sourceItem.id
3355
+ );
3356
+ const targetPath = tree.findPath(
3357
+ rootResource2,
3358
+ (item) => item.id === targetItem.id
3359
+ );
3360
+ if (!sourcePath || !targetPath) return false;
3361
+ if (isDeepEqual2(sourcePath, targetPath.slice(0, sourcePath.length))) {
3362
+ return false;
3363
+ }
3364
+ return true;
3365
+ }
3366
+ function getPublishStatus({
3367
+ resource,
3368
+ diff
3369
+ }) {
3370
+ if (!diff) return void 0;
3371
+ return diff.modified.has(resource.stableId) ? "Modified" : diff.added.has(resource.stableId) ? "Added" : diff.removed.has(resource.stableId) ? "Removed" : (
3372
+ // We don't have to check for the specific ID, since if anything had been published
3373
+ // but removed, it will be in the removed set
3374
+ "Published"
3375
+ );
3376
+ }
2269
3377
  export {
2270
3378
  MediaCollection,
2271
3379
  PLACEHOLDER_ITEM_NAME,
3380
+ ResourceExplorer,
3381
+ ResourceThumbnail,
2272
3382
  acceptsMediaItemDrop,
3383
+ acceptsResourceDrop,
2273
3384
  basenameValidator,
2274
3385
  createMediaAsset,
2275
3386
  createMediaFile,
2276
3387
  createMediaFolder,
2277
3388
  createMediaItem,
2278
3389
  createMediaItemTree,
2279
- deleteMediaItems,
3390
+ deleteResources,
2280
3391
  getDepthMap,
2281
3392
  getParentDirectories,
2282
3393
  getVisibleItems,
3394
+ gridThumbnailDimension,
3395
+ mediaDeleteMediaItems,
3396
+ mediaGetDepthMap,
3397
+ mediaGetParentDirectories,
3398
+ mediaGetVisibleItems,
3399
+ mediaMoveMediaInsideFolder,
3400
+ mediaMovePathsIntoTarget,
3401
+ mediaMoveUpAFolder,
3402
+ mediaRenameMediaItemAndDescendantPaths,
3403
+ mediaUpdateExpandedMap,
3404
+ mediaValidateMediaItemRename,
2283
3405
  moveMediaInsideFolder,
2284
3406
  movePathsIntoTarget,
2285
3407
  moveUpAFolder,
2286
- renameMediaItemAndDescendantPaths,
3408
+ renameResourceAndDescendantPaths,
2287
3409
  rootMediaItem,
2288
3410
  rootMediaItemName,
2289
3411
  rootMediaItemPath,
2290
3412
  updateExpandedMap,
2291
- validateMediaItemRename
3413
+ validateResourceRename
2292
3414
  };
2293
3415
  //# sourceMappingURL=index.mjs.map