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