@emailmaker/filemanager 0.10.97 → 0.10.99

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/file-manager.css CHANGED
@@ -1593,6 +1593,22 @@
1593
1593
  padding: 2px 0;
1594
1594
  min-width: 0; /* Позволяет flex-элементам сжиматься */
1595
1595
  }
1596
+
1597
+ /** Tab locked by the host (e.g. by subscription plan): still shown, but badged with a lock. */
1598
+ .em-filemanager .lockedTabIcon {
1599
+ position: relative;
1600
+ display: inline-flex;
1601
+ opacity: 0.55;
1602
+ }
1603
+
1604
+ .em-filemanager .lockedTabLock {
1605
+ position: absolute;
1606
+ right: -4px;
1607
+ bottom: -2px;
1608
+ opacity: 1;
1609
+ border-radius: 100%;
1610
+ background-color: var(--colorBgContainer);
1611
+ }
1596
1612
  @charset "UTF-8";
1597
1613
  .em-filemanager .uploadProgress {
1598
1614
  position: fixed;
@@ -1,2 +1,2 @@
1
- export{$ as DEFAULT_FILE_MANAGER_CACHE_TTL_MS,a1 as DataSourceProxyBase,L as FailedRequestCache,A as FileContent,G as FileManagerApiError,z as FileManagerApp,t as FileManagerAppWithContext,B as FileModals,C as FolderSidebar,M as MutationRegistry,a2 as PathAwareStorageAdapter,P as PixieOnlyApp,V as TRASH_FOLDER_ID,Z as TreeCache,_ as ViewCacheManager,I as buildAssetsPath,O as compareFileSystemItems,W as createSystemFolderByPathResolver,y as default,Q as defaultChildrenViewFilterMatch,R as defaultFileSystemItemComparator,a0 as defaultIsFolderNotFoundError,a3 as fetchRemoteImageBlobByUrl,K as getAssetsBase,X as getTrashFolderLookupCandidates,q as init,x as initFileManager,v as initPixieEditor,D as installResizeObserverErrorHandler,J as joinUrls,H as mapHttpStatusToErrorCode,S as matchesChildrenViewFilter,Y as normalizeSystemFolderPath,T as resolveSortParams,U as resolveViewStrategyOptions,E as uninstallResizeObserverErrorHandler,s as unmount,w as unmountPixieEditor}from"./file-manager-index-CGOCfKmf.js";import"react/jsx-runtime";import"react";import"react-dom/client";import"antd";import"@ant-design/icons";import"@ant-design/cssinjs";import"react-dom";import"@untitledui/icons";import"browser-image-compression";import"pixie";
1
+ export{a1 as DEFAULT_FILE_MANAGER_CACHE_TTL_MS,a3 as DataSourceProxyBase,L as FailedRequestCache,A as FileContent,G as FileManagerApiError,z as FileManagerApp,t as FileManagerAppWithContext,B as FileModals,C as FolderSidebar,M as MutationRegistry,a4 as PathAwareStorageAdapter,P as PixieOnlyApp,X as TRASH_FOLDER_ID,$ as TreeCache,a0 as ViewCacheManager,I as buildAssetsPath,O as compareFileSystemItems,Y as createSystemFolderByPathResolver,y as default,Q as defaultChildrenViewFilterMatch,R as defaultFileSystemItemComparator,S as defaultHasSortValue,a2 as defaultIsFolderNotFoundError,a5 as fetchRemoteImageBlobByUrl,K as getAssetsBase,Z as getTrashFolderLookupCandidates,T as hasComparableSortValue,q as init,x as initFileManager,v as initPixieEditor,D as installResizeObserverErrorHandler,J as joinUrls,H as mapHttpStatusToErrorCode,U as matchesChildrenViewFilter,_ as normalizeSystemFolderPath,V as resolveSortParams,W as resolveViewStrategyOptions,E as uninstallResizeObserverErrorHandler,s as unmount,w as unmountPixieEditor}from"./file-manager-index-D2RmKLjd.js";import"react/jsx-runtime";import"react";import"react-dom/client";import"antd";import"@ant-design/icons";import"@ant-design/cssinjs";import"react-dom";import"@untitledui/icons";import"browser-image-compression";import"pixie";
2
2
  //# sourceMappingURL=file-manager.esm.js.map
package/file-manager.js CHANGED
@@ -356,13 +356,14 @@ const FolderTree = ({ selectedFolder, onSelect, onExpand, generateMenuItems, fet
356
356
  }
357
357
  }
358
358
  }, [defaultExpandAll, mode, generateMenuItems, getAllFolderKeys, controlledExpandedKeys]);
359
- const handleTreeSelect = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(async (selectedKeys) => {
359
+ const handleTreeSelect = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)((selectedKeys) => {
360
360
  const key = selectedKeys[0];
361
361
  if (!key || key === 'empty' || key.endsWith('_input'))
362
362
  return;
363
+ // onSelect (FolderSidebar.handleTreeSelect) сам вызывает fetchChildFolders(key)
364
+ // внутри — здесь его вызывать повторно не нужно.
363
365
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(selectedKeys);
364
- await (fetchChildFolders === null || fetchChildFolders === void 0 ? void 0 : fetchChildFolders(key === 'folders' ? null : key));
365
- }, [onSelect, fetchChildFolders]);
366
+ }, [onSelect]);
366
367
  const handleTreeExpand = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(async (keys, info) => {
367
368
  var _a;
368
369
  setExpandedKeys(keys);
@@ -422,7 +423,13 @@ const FolderTree = ({ selectedFolder, onSelect, onExpand, generateMenuItems, fet
422
423
  return (0,jsx_runtime.jsx)(ExpandFolderIcon, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth });
423
424
  };
424
425
  const currentFolderIcon = renderCurrentFolderIcon();
425
- const title = ((0,jsx_runtime.jsxs)("div", { className: `${FolderTree_FolderTree_module.folderItemContainer} folder-item-container`, onClick: () => !isDisabled && onClickHandle(item.key), style: {
426
+ const title = ((0,jsx_runtime.jsxs)("div", { className: `${FolderTree_FolderTree_module.folderItemContainer} folder-item-container`, onClick: event => {
427
+ // Гасим всплытие: иначе клик по заголовку узла долетает и до нативного
428
+ // onSelect antd Tree, и handleTreeSelect срабатывает дважды на один клик.
429
+ event.stopPropagation();
430
+ if (!isDisabled)
431
+ onClickHandle(item.key);
432
+ }, style: {
426
433
  opacity: isDisabled ? 0.5 : 1,
427
434
  cursor: isDisabled ? 'not-allowed' : 'pointer',
428
435
  }, children: [(0,jsx_runtime.jsxs)("div", { className: FolderTree_FolderTree_module.folderLabel, children: [item.icon !== undefined ? item.icon : currentFolderIcon, (0,jsx_runtime.jsx)("span", { className: FolderTree_FolderTree_module.folderLabelItem, children: item.label })] }), showFileCounts && ((0,jsx_runtime.jsx)("div", { className: FolderTree_FolderTree_module.fileCount, title: filesCount === null
@@ -436,10 +443,16 @@ const FolderTree = ({ selectedFolder, onSelect, onExpand, generateMenuItems, fet
436
443
  };
437
444
  };
438
445
  const isRootExpanded = expandedKeys.includes('folders');
439
- const rootTitle = ((0,jsx_runtime.jsx)("div", { className: FolderTree_FolderTree_module.foldersTitle, onClick: () => onClickHandle('folders'), children: (0,jsx_runtime.jsxs)("div", { className: FolderTree_FolderTree_module.foldersTitleItem, children: [isRootExpanded ? ((0,jsx_runtime.jsx)(CollapseFolderIcon, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth })) : ((0,jsx_runtime.jsx)(ExpandFolderIcon, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth })), (0,jsx_runtime.jsx)("span", { className: `${FolderTree_FolderTree_module.folderLabelItem} folder-label-item`, children: ((_a = sanitizedMenuItems[0]) === null || _a === void 0 ? void 0 : _a.key) === 'folders' ? sanitizedMenuItems[0].label : t('Folders') })] }) }));
446
+ const rootTitle = ((0,jsx_runtime.jsx)("div", { className: FolderTree_FolderTree_module.foldersTitle, onClick: event => {
447
+ event.stopPropagation();
448
+ onClickHandle('folders');
449
+ }, children: (0,jsx_runtime.jsxs)("div", { className: FolderTree_FolderTree_module.foldersTitleItem, children: [isRootExpanded ? ((0,jsx_runtime.jsx)(CollapseFolderIcon, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth })) : ((0,jsx_runtime.jsx)(ExpandFolderIcon, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth })), (0,jsx_runtime.jsx)("span", { className: `${FolderTree_FolderTree_module.folderLabelItem} folder-label-item`, children: ((_a = sanitizedMenuItems[0]) === null || _a === void 0 ? void 0 : _a.key) === 'folders' ? sanitizedMenuItems[0].label : t('Folders') })] }) }));
440
450
  const buildTrashNode = () => ({
441
451
  key: 'Trash',
442
- title: ((0,jsx_runtime.jsx)("div", { className: FolderTree_FolderTree_module.foldersTitle, onClick: () => onClickHandle('Trash'), children: (0,jsx_runtime.jsxs)("div", { className: FolderTree_FolderTree_module.foldersTitleItem, children: [(0,jsx_runtime.jsx)(icons_.Trash03, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }), (0,jsx_runtime.jsx)("span", { className: FolderTree_FolderTree_module.folderLabelItem, children: t('Trash') })] }) })),
452
+ title: ((0,jsx_runtime.jsx)("div", { className: FolderTree_FolderTree_module.foldersTitle, onClick: event => {
453
+ event.stopPropagation();
454
+ onClickHandle('Trash');
455
+ }, children: (0,jsx_runtime.jsxs)("div", { className: FolderTree_FolderTree_module.foldersTitleItem, children: [(0,jsx_runtime.jsx)(icons_.Trash03, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }), (0,jsx_runtime.jsx)("span", { className: FolderTree_FolderTree_module.folderLabelItem, children: t('Trash') })] }) })),
443
456
  children: undefined,
444
457
  });
445
458
  if (isEmpty) {
@@ -39123,7 +39136,7 @@ __webpack_require__.d(__webpack_exports__, {
39123
39136
  HO: () => (/* reexport */ useSortAndFilter/* useSortAndFilter */.H)
39124
39137
  });
39125
39138
 
39126
- // UNUSED EXPORTS: FileManagerContext, useModals
39139
+ // UNUSED EXPORTS: FileManagerContext, mergeLazyRootFolders, useModals
39127
39140
 
39128
39141
  // EXTERNAL MODULE: ./src/hooks/core/context.tsx
39129
39142
  var context = __webpack_require__(8361);
@@ -41176,6 +41189,7 @@ module.exports = PluralRules;
41176
41189
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
41177
41190
  /* harmony export */ n: () => (/* binding */ useFolders)
41178
41191
  /* harmony export */ });
41192
+ /* unused harmony export mergeLazyRootFolders */
41179
41193
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5442);
41180
41194
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
41181
41195
  /* harmony import */ var _ant_design_icons__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7892);
@@ -41197,6 +41211,18 @@ module.exports = PluralRules;
41197
41211
 
41198
41212
 
41199
41213
 
41214
+ /**
41215
+ * Ленивый режим дерева (`folderTreeLoading: 'lazy'`) не обходит поддеревья — свежий
41216
+ * root-фетч содержит только корневые папки. Старые вложенные записи (с `parentId`)
41217
+ * сохраняются как есть, НО если тот же `id` уже есть в свежем корневом ответе
41218
+ * (сервер теперь считает папку корневой), старая копия вытесняется, а не дублируется
41219
+ * рядом с новой (см. DEV-дубликаты в дереве после загрузки файла в подпапку).
41220
+ */
41221
+ function mergeLazyRootFolders(prev, rootFolders) {
41222
+ const freshIds = new Set(rootFolders.map(f => f.id));
41223
+ const withoutOldRoots = prev.filter(f => f.parentId && !freshIds.has(f.id));
41224
+ return [...withoutOldRoots, ...rootFolders];
41225
+ }
41200
41226
  const useFolders = () => {
41201
41227
  var _a, _b;
41202
41228
  const { state, actions, options } = (0,_context__WEBPACK_IMPORTED_MODULE_2__/* .useFileManagerContext */ .wh)();
@@ -41244,8 +41270,7 @@ const useFolders = () => {
41244
41270
  }
41245
41271
  return fullTree;
41246
41272
  }
41247
- const withoutOldRoots = safePrev.filter(f => f.parentId);
41248
- const merged = [...withoutOldRoots, ...rootFolders];
41273
+ const merged = mergeLazyRootFolders(safePrev, rootFolders);
41249
41274
  const problematicFolders = merged.filter((folder) => folder.id === folder.parentId);
41250
41275
  if (problematicFolders.length > 0) {
41251
41276
  console.warn('Folders with cyclic dependencies detected:', problematicFolders);
@@ -43443,7 +43468,7 @@ __webpack_require__.d(__webpack_exports__, {
43443
43468
  _O: () => (/* reexport */ useViewportMetricsSync)
43444
43469
  });
43445
43470
 
43446
- // UNUSED EXPORTS: FileManagerContext, useLastDirectory, useModals
43471
+ // UNUSED EXPORTS: FileManagerContext, mergeLazyRootFolders, useLastDirectory, useModals
43447
43472
 
43448
43473
  // EXTERNAL MODULE: ./src/hooks/core/index.ts + 4 modules
43449
43474
  var core = __webpack_require__(4002);
@@ -44509,6 +44534,8 @@ module.exports = __WEBPACK_EXTERNAL_MODULE__7928__;
44509
44534
  /* harmony import */ var antd__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(550);
44510
44535
  /* harmony import */ var antd__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(antd__WEBPACK_IMPORTED_MODULE_2__);
44511
44536
  /* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(133);
44537
+ /* harmony import */ var _utils_libraryTabLock__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8546);
44538
+
44512
44539
 
44513
44540
 
44514
44541
 
@@ -44564,16 +44591,18 @@ const FileManagerProvider = ({ children, options }) => {
44564
44591
  const [currentMenuFile, setCurrentMenuFile] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)('');
44565
44592
  const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(false);
44566
44593
  const [activeLibraryItem, setActiveLibraryItem] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)(_constants__WEBPACK_IMPORTED_MODULE_3__/* .MY_FILES */ .Zz);
44594
+ /** A locked tab must never become active — otherwise the host's lock would be bypassed. */
44595
+ const isLibraryItemOpenable = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((item) => isLibraryItemEnabled(item) && !(0,_utils_libraryTabLock__WEBPACK_IMPORTED_MODULE_4__/* .isLibraryTabLocked */ .v)(item, config), [config, isLibraryItemEnabled]);
44567
44596
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
44568
44597
  if ((config === null || config === void 0 ? void 0 : config.activeLibraryItem) && setActiveLibraryItem) {
44569
- setActiveLibraryItem(isLibraryItemEnabled(config.activeLibraryItem) ? config.activeLibraryItem : _constants__WEBPACK_IMPORTED_MODULE_3__/* .MY_FILES */ .Zz);
44598
+ setActiveLibraryItem(isLibraryItemOpenable(config.activeLibraryItem) ? config.activeLibraryItem : _constants__WEBPACK_IMPORTED_MODULE_3__/* .MY_FILES */ .Zz);
44570
44599
  }
44571
- }, [config === null || config === void 0 ? void 0 : config.activeLibraryItem, isLibraryItemEnabled, setActiveLibraryItem]);
44600
+ }, [config === null || config === void 0 ? void 0 : config.activeLibraryItem, isLibraryItemOpenable, setActiveLibraryItem]);
44572
44601
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(() => {
44573
- if (!isLibraryItemEnabled(activeLibraryItem)) {
44602
+ if (!isLibraryItemOpenable(activeLibraryItem)) {
44574
44603
  setActiveLibraryItem(_constants__WEBPACK_IMPORTED_MODULE_3__/* .MY_FILES */ .Zz);
44575
44604
  }
44576
- }, [activeLibraryItem, isLibraryItemEnabled]);
44605
+ }, [activeLibraryItem, isLibraryItemOpenable]);
44577
44606
  const [pagination, setPagination] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)({
44578
44607
  current: 1,
44579
44608
  pageSize: 20,
@@ -44701,6 +44730,21 @@ const FileManagerProvider = ({ children, options }) => {
44701
44730
  };
44702
44731
 
44703
44732
 
44733
+ /***/ }),
44734
+
44735
+ /***/ 8546:
44736
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
44737
+
44738
+ "use strict";
44739
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
44740
+ /* harmony export */ v: () => (/* binding */ isLibraryTabLocked)
44741
+ /* harmony export */ });
44742
+ function isLibraryTabLocked(tab, config) {
44743
+ var _a;
44744
+ return Boolean((_a = config === null || config === void 0 ? void 0 : config.lockedTabs) === null || _a === void 0 ? void 0 : _a.includes(tab));
44745
+ }
44746
+
44747
+
44704
44748
  /***/ }),
44705
44749
 
44706
44750
  /***/ 8573:
@@ -48431,7 +48475,7 @@ var ___CSS_LOADER_API_SOURCEMAP_IMPORT___ = __webpack_require__(1354);
48431
48475
  var ___CSS_LOADER_API_IMPORT___ = __webpack_require__(6314);
48432
48476
  var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);
48433
48477
  // Module
48434
- ___CSS_LOADER_EXPORT___.push([module.id, `.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__button__Yf2rX:hover{background-color:var(--colorBgContainer);color:var(--colorPrimary)}.FolderSidebar-module__foldersTitle__Uh6u7{display:flex;align-items:center;flex:1;cursor:pointer}.FolderSidebar-module__folderActions__qA2Bk{position:absolute;top:4px;right:4px;display:flex;align-items:center;gap:4px;z-index:10}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__customExpandIcon__IhZJl{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:8px;cursor:pointer;color:#666;font-size:10px;transition:transform .2s ease}.FolderSidebar-module__customExpandIcon__IhZJl:hover{color:var(--colorPrimary)}.FolderSidebar-module__fileCount__bD9DD{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:100%;padding:0 6px;margin-left:8px;color:#8d8d8d;font-size:14px;font-weight:500;transition:all .2s ease;white-space:nowrap;cursor:default;flex-shrink:0;margin-right:10px}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folder-label span,.FolderSidebar-module__folderMenu__JCzLF .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-selected .folderLabelItem{font-weight:600 !important}.FolderSidebar-module__uploadButton__QQUid{width:100%;justify-content:flex-start}.FolderSidebar-module__uploadButton__QQUid button:hover{background-color:var(--colorPrimaryHover) !important}.FolderSidebar-module__folderMenu__JCzLF{padding-left:0;padding-right:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode{display:flex;align-items:center;justify-content:space-between;padding:4px 0;border-radius:4px;transition:background-color .2s ease;width:100%;margin-bottom:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper{flex:1;align-items:center;padding:0;transition:background-color .2s ease}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0)}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher{height:24px;width:24px;margin-top:5px;display:flex !important;align-items:center;justify-content:center;transition:color .2s ease;flex-shrink:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-noop{width:24px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-line-icon{color:#d9d9d9}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .folder-label{display:flex;align-items:center;flex:1;color:#595959;font-size:14px;min-width:0;overflow:hidden}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"]{border-bottom:1px solid var(--colorBorderSecondary);margin-bottom:8px;padding-bottom:8px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"].ant-tree-treenode-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper{padding:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__emptyFolderContainer__WK6tx{padding:20px;text-align:center}.FolderSidebar-module__folderMenu__JCzLF .ant-tree > .ant-tree-treenode{padding-left:0 !important}.FolderSidebar-module__folderIcon__UoZzH{margin-right:8px;font-size:18px;flex-shrink:0}.FolderSidebar-module__folderLabelItem__uJ062{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;user-select:none}.FolderSidebar-module__foldersTitleItem__gapOI{display:flex;align-items:center;flex:1;cursor:pointer;min-width:0;overflow:hidden}.FolderSidebar-module__folderLabel__fHWMp{display:flex;align-items:center;flex:1;min-width:0;overflow:hidden}.FolderSidebar-module__foldersContainer__zdBVU{position:relative;width:100%}.FolderSidebar-module__uploadButton__QQUid .FolderSidebar-module__ant-btn__LXAXm,.FolderSidebar-module__uploadButton__QQUid .ant-btn{display:flex;align-items:center;justify-content:center;gap:3px}.FolderSidebar-module__buttonWrapper__a9Qi5{margin-bottom:24px;display:flex;gap:4px}.FolderSidebar-module__buttonWrapper__a9Qi5>:first-child{flex:1;height:40px;padding-left:10px}.FolderSidebar-module__buttonWrapper__a9Qi5>:last-child{width:40px;height:40px;flex-shrink:0}.FolderSidebar-module__uploadByURLButton__epMiC.ant-btn.ant-btn-icon-only{width:40px;min-width:40px;height:40px;padding:0;flex-shrink:0}.FolderSidebar-module__uploadButtonIcon__mWQmq{font-size:20px}.FolderSidebar-module__uploadButtonTitle__wk_o6{line-height:1em}.FolderSidebar-module__emptyFolderContainer__WK6tx{user-select:none;cursor:default;color:var(--colorTextTertiary)}.FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}`, "",{"version":3,"sources":["webpack://./src/components/FolderSidebar/FolderSidebar.module.scss"],"names":[],"mappings":"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","sourcesContent":[".button:global(.ant-btn.ant-btn-icon-only) {\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\n cursor: pointer;\n color: var(--colorTextSecondary);\n display: flex;\n gap: calc(var(--marginXS) * 1px);\n align-items: center;\n justify-content: center;\n border-radius: calc(var(--borderRadiusSM) * 1px);\n transition: all var(--motionDurationFast);\n box-shadow: none;\n\n border: none;\n width: 32px;\n height: 32px;\n\n &:hover {\n background-color: var(--colorBgLayout);\n color: inherit;\n }\n}\n\n.button:hover {\n background-color: var(--colorBgContainer);\n color: var(--colorPrimary);\n}\n\n.foldersTitle {\n display: flex;\n align-items: center;\n flex: 1;\n cursor: pointer;\n}\n\n.folderActions {\n position: absolute;\n top: 4px; /* Выравниваем по заголовку Folders */\n right: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n z-index: 10;\n\n .button.ant-btn.ant-btn-icon-only {\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\n cursor: pointer;\n color: var(--colorTextSecondary);\n display: flex;\n gap: calc(var(--marginXS) * 1px);\n align-items: center;\n justify-content: center;\n border-radius: calc(var(--borderRadiusSM) * 1px);\n transition: all var(--motionDurationFast);\n box-shadow: none;\n\n border: none;\n width: 32px;\n height: 32px;\n\n &:hover {\n background-color: var(--colorBgLayout);\n color: inherit;\n }\n }\n}\n\n.customExpandIcon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n margin-right: 8px;\n cursor: pointer;\n color: #666;\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.customExpandIcon:hover {\n color: var(--colorPrimary);\n}\n\n.fileCount {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 100%;\n padding: 0 6px;\n margin-left: 8px;\n color: #8D8D8D;\n font-size: 14px;\n font-weight: 500;\n transition: all 0.2s ease;\n white-space: nowrap;\n cursor: default;\n flex-shrink: 0; /* Запрещаем сжатие счетчика */\n margin-right: 10px;\n}\n\n// .fileCount:hover {\n// border-color: var(--colorPrimary);\n// color: var(--colorPrimary);\n// }\n\n:global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected) {\n background-color: transparent !important;\n}\n\n/* :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected):hover {\n color: red !important;\n} */\n\n/* Стили для выделения текста в выбранной папке */\n.folderMenu :global(.ant-tree-treenode-selected .folder-label span),\n.folderMenu :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem),\n.folderMenu :global(.ant-tree-treenode-selected .folderLabelItem),\n.folderMenu :global(.ant-tree-node-selected .folderLabelItem) {\n font-weight: 600 !important;\n}\n\n/* Стили для иконки в выбранной папке */\n/* .folderMenu :global(.ant-tree-treenode-selected .folderIcon),\n.folderMenu :global(.ant-tree-node-selected .folderIcon) {\n color: red !important;\n} */\n\n/* CSS переменные для упрощения расчетов */\n\n.uploadButton {\n width: 100%;\n justify-content: flex-start;\n\n & button:hover {\n background-color: var(--colorPrimaryHover) !important;\n }\n}\n\n.folderMenu {\n padding-left: 0;\n padding-right: 0; /* Место для кнопки справа */\n}\n\n.folderMenu :global(.ant-tree-treenode) {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 0;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n width: 100%;\n margin-bottom: 0;\n}\n\n.folderMenu :global(.ant-tree-node-content-wrapper) {\n flex: 1;\n /* display: flex; */\n align-items: center;\n padding: 0;\n /* border-radius: 4px; */\n transition: background-color 0.2s ease;\n}\n\n.folderMenu :global(.ant-tree-node-content-wrapper:hover) {\n background-color: transparent;\n}\n\n.folderMenu :global(.ant-tree-switcher) {\n height: 24px;\n width: 24px;\n margin-top: 5px;\n display: flex !important;\n align-items: center;\n justify-content: center;\n transition: color 0.2s ease;\n flex-shrink: 0; /* Запрещаем сжатие переключателя */\n}\n\n.folderMenu :global(.ant-tree-switcher-noop) {\n width: 24px;\n}\n\n/* Стили для линий дерева */\n.folderMenu :global(.ant-tree-switcher-line-icon) {\n color: #d9d9d9;\n}\n\n/* Улучшение отображения folder-item-container */\n.folderMenu .folderItemContainer {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 0;\n min-width: 0; /* Позволяет flex-элементам сжиматься */\n}\n\n.folderMenu :global(.folder-label) {\n display: flex;\n align-items: center;\n flex: 1;\n color: #595959;\n font-size: 14px;\n min-width: 0;\n overflow: hidden;\n}\n\n/* Стили для корневого элемента Folders */\n.folderMenu :global(.ant-tree-treenode[data-key='folders']) {\n border-bottom: 1px solid var(--colorBorderSecondary);\n margin-bottom: 8px;\n padding-bottom: 8px;\n}\n\n.folderMenu :global(.ant-tree-treenode[data-key='folders'].ant-tree-treenode-selected) {\n background-color: transparent !important;\n}\n\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper) {\n padding: 0;\n}\n\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper:hover) {\n background-color: transparent !important;\n}\n\n/* Стили для ellipsis - удаляем max-width для гибкости */\n.folderMenu :global(.ellipsis) {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n min-width: 0;\n}\n\n/* Стили для пустого состояния */\n.folderMenu .emptyFolderContainer {\n padding: 20px;\n text-align: center;\n}\n\n/* Убираем отступы у корневого узла */\n.folderMenu :global(.ant-tree > .ant-tree-treenode) {\n padding-left: 0 !important;\n}\n.folderIcon {\n margin-right: 8px;\n font-size: 18px;\n flex-shrink: 0; /* Запрещаем сжатие иконки */\n}\n\n.folderLabelItem {\n font-size: 14px;\n white-space: nowrap; /* Запрещаем перенос строк */\n overflow: hidden; /* Скрываем переполнение */\n text-overflow: ellipsis; /* Показываем троеточие */\n flex: 1; /* Занимает доступное место */\n min-width: 0; /* Позволяет сжиматься */\n user-select: none;\n}\n\n.foldersTitleItem {\n display: flex;\n align-items: center;\n flex: 1;\n cursor: pointer;\n min-width: 0; /* Позволяет сжиматься */\n overflow: hidden; /* Скрываем переполнение */\n}\n\n/* .foldersTitleItem .folderLabelItem {\n font-weight: 500;\n color: #262626;\n} */\n\n/* Класс для заголовка папок */\n.folderLabel {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.foldersContainer {\n position: relative;\n width: 100%;\n}\n\n/* Дополнительные стили для улучшения визуала */\n/* .folderMenu :global(.ant-tree-treenode:hover .folder-label span) {\n color: #1890ff;\n} */\n\n/* Стили для дивайдера между папками */\n\n\n.uploadButton .ant-btn,\n.uploadButton :global(.ant-btn) {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 3px;\n}\n/* .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\n color: #1890ff !important;\n} */\n\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderLabelItem,\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderIcon,\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\n// color: var(--colorLink);\n// }\n\n\n.buttonWrapper {\n // overflow: hidden;\n margin-bottom: 24px;\n display: flex;\n gap: 4px;\n // border-radius: calc(var(--borderRadius) * 1px);\n \n // Левая кнопка занимает всю доступную ширину\n > :first-child {\n flex: 1;\n height: 40px;\n padding-left: 10px;\n }\n \n // Правая кнопка строго 40px\n > :last-child {\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n }\n}\n\n/* Кнопка «Загрузить по URL» — icon-only, поэтому хост-приложение может задать ей\n свои размеры глобальным правилом `.ant-btn.ant-btn-icon-only` (в emailmaker это\n --formControlHeight: 34) и она становится ниже кнопки «Загрузить файл».\n Три класса в селекторе перебивают такие правила без !important. */\n.uploadByURLButton:global(.ant-btn.ant-btn-icon-only) {\n width: 40px;\n min-width: 40px;\n height: 40px;\n padding: 0;\n flex-shrink: 0;\n}\n\n.uploadButtonIcon {\n font-size: 20px;\n}\n\n.uploadButtonTitle {\n line-height: 1em;\n}\n\n.emptyFolderContainer {\n user-select: none;\n cursor: default;\n color: var(--colorTextTertiary);\n}\n\n.folderItemContainer {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 0;\n min-width: 0; /* Позволяет flex-элементам сжиматься */\n}\n"],"sourceRoot":""}]);
48478
+ ___CSS_LOADER_EXPORT___.push([module.id, `.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__button__Yf2rX.ant-btn.ant-btn-icon-only:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__button__Yf2rX:hover{background-color:var(--colorBgContainer);color:var(--colorPrimary)}.FolderSidebar-module__foldersTitle__Uh6u7{display:flex;align-items:center;flex:1;cursor:pointer}.FolderSidebar-module__folderActions__qA2Bk{position:absolute;top:4px;right:4px;display:flex;align-items:center;gap:4px;z-index:10}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF{padding:calc(var(--paddingXXS)*1px) calc(var(--paddingSM)*1px);cursor:pointer;color:var(--colorTextSecondary);display:flex;gap:calc(var(--marginXS)*1px);align-items:center;justify-content:center;border-radius:calc(var(--borderRadiusSM)*1px);transition:all var(--motionDurationFast);box-shadow:none;border:none;width:32px;height:32px}.FolderSidebar-module__folderActions__qA2Bk .FolderSidebar-module__button__Yf2rX.FolderSidebar-module__ant-btn__LXAXm.FolderSidebar-module__ant-btn-icon-only__j_wVF:hover{background-color:var(--colorBgLayout);color:inherit}.FolderSidebar-module__customExpandIcon__IhZJl{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:8px;cursor:pointer;color:#666;font-size:10px;transition:transform .2s ease}.FolderSidebar-module__customExpandIcon__IhZJl:hover{color:var(--colorPrimary)}.FolderSidebar-module__fileCount__bD9DD{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:100%;padding:0 6px;margin-left:8px;color:#8d8d8d;font-size:14px;font-weight:500;transition:all .2s ease;white-space:nowrap;cursor:default;flex-shrink:0;margin-right:10px}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folder-label span,.FolderSidebar-module__folderMenu__JCzLF .ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode-selected .folderLabelItem,.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-selected .folderLabelItem{font-weight:600 !important}.FolderSidebar-module__uploadButton__QQUid{width:100%;justify-content:flex-start}.FolderSidebar-module__uploadButton__QQUid button:hover{background-color:var(--colorPrimaryHover) !important}.FolderSidebar-module__folderMenu__JCzLF{padding-left:0;padding-right:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode{display:flex;align-items:center;justify-content:space-between;padding:4px 0;border-radius:4px;transition:background-color .2s ease;width:100%;margin-bottom:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper{flex:1;align-items:center;padding:0;transition:background-color .2s ease}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0)}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher{height:24px;width:24px;margin-top:5px;display:flex !important;align-items:center;justify-content:center;transition:color .2s ease;flex-shrink:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-noop{width:24px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-switcher-line-icon{color:#d9d9d9}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .folder-label{display:flex;align-items:center;flex:1;color:#595959;font-size:14px;min-width:0;overflow:hidden}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"]{border-bottom:1px solid var(--colorBorderSecondary);margin-bottom:8px;padding-bottom:8px}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"].ant-tree-treenode-selected{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper{padding:0}.FolderSidebar-module__folderMenu__JCzLF .ant-tree-treenode[data-key="folders"] .ant-tree-node-content-wrapper:hover{background-color:rgba(0,0,0,0) !important}.FolderSidebar-module__folderMenu__JCzLF .ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}.FolderSidebar-module__folderMenu__JCzLF .FolderSidebar-module__emptyFolderContainer__WK6tx{padding:20px;text-align:center}.FolderSidebar-module__folderMenu__JCzLF .ant-tree > .ant-tree-treenode{padding-left:0 !important}.FolderSidebar-module__folderIcon__UoZzH{margin-right:8px;font-size:18px;flex-shrink:0}.FolderSidebar-module__folderLabelItem__uJ062{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;user-select:none}.FolderSidebar-module__foldersTitleItem__gapOI{display:flex;align-items:center;flex:1;cursor:pointer;min-width:0;overflow:hidden}.FolderSidebar-module__folderLabel__fHWMp{display:flex;align-items:center;flex:1;min-width:0;overflow:hidden}.FolderSidebar-module__foldersContainer__zdBVU{position:relative;width:100%}.FolderSidebar-module__uploadButton__QQUid .FolderSidebar-module__ant-btn__LXAXm,.FolderSidebar-module__uploadButton__QQUid .ant-btn{display:flex;align-items:center;justify-content:center;gap:3px}.FolderSidebar-module__buttonWrapper__a9Qi5{margin-bottom:24px;display:flex;gap:4px}.FolderSidebar-module__buttonWrapper__a9Qi5>:first-child{flex:1;height:40px;padding-left:10px}.FolderSidebar-module__buttonWrapper__a9Qi5>:last-child{width:40px;height:40px;flex-shrink:0}.FolderSidebar-module__uploadByURLButton__epMiC.ant-btn.ant-btn-icon-only{width:40px;min-width:40px;height:40px;padding:0;flex-shrink:0}.FolderSidebar-module__uploadButtonIcon__mWQmq{font-size:20px}.FolderSidebar-module__uploadButtonTitle__wk_o6{line-height:1em}.FolderSidebar-module__emptyFolderContainer__WK6tx{user-select:none;cursor:default;color:var(--colorTextTertiary)}.FolderSidebar-module__folderItemContainer__byl5b{width:100%;display:flex;align-items:center;justify-content:space-between;padding:2px 0;min-width:0}.FolderSidebar-module__lockedTabIcon__gYKRY{position:relative;display:inline-flex;opacity:.55}.FolderSidebar-module__lockedTabLock__rbkfX{position:absolute;right:-4px;bottom:-2px;opacity:1;border-radius:100%;background-color:var(--colorBgContainer)}`, "",{"version":3,"sources":["webpack://./src/components/FolderSidebar/FolderSidebar.module.scss"],"names":[],"mappings":"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","sourcesContent":[".button:global(.ant-btn.ant-btn-icon-only) {\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\n cursor: pointer;\n color: var(--colorTextSecondary);\n display: flex;\n gap: calc(var(--marginXS) * 1px);\n align-items: center;\n justify-content: center;\n border-radius: calc(var(--borderRadiusSM) * 1px);\n transition: all var(--motionDurationFast);\n box-shadow: none;\n\n border: none;\n width: 32px;\n height: 32px;\n\n &:hover {\n background-color: var(--colorBgLayout);\n color: inherit;\n }\n}\n\n.button:hover {\n background-color: var(--colorBgContainer);\n color: var(--colorPrimary);\n}\n\n.foldersTitle {\n display: flex;\n align-items: center;\n flex: 1;\n cursor: pointer;\n}\n\n.folderActions {\n position: absolute;\n top: 4px; /* Выравниваем по заголовку Folders */\n right: 4px;\n display: flex;\n align-items: center;\n gap: 4px;\n z-index: 10;\n\n .button.ant-btn.ant-btn-icon-only {\n padding: calc(var(--paddingXXS) * 1px) calc(var(--paddingSM) * 1px);\n cursor: pointer;\n color: var(--colorTextSecondary);\n display: flex;\n gap: calc(var(--marginXS) * 1px);\n align-items: center;\n justify-content: center;\n border-radius: calc(var(--borderRadiusSM) * 1px);\n transition: all var(--motionDurationFast);\n box-shadow: none;\n\n border: none;\n width: 32px;\n height: 32px;\n\n &:hover {\n background-color: var(--colorBgLayout);\n color: inherit;\n }\n }\n}\n\n.customExpandIcon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n margin-right: 8px;\n cursor: pointer;\n color: #666;\n font-size: 10px;\n transition: transform 0.2s ease;\n}\n\n.customExpandIcon:hover {\n color: var(--colorPrimary);\n}\n\n.fileCount {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 20px;\n height: 100%;\n padding: 0 6px;\n margin-left: 8px;\n color: #8D8D8D;\n font-size: 14px;\n font-weight: 500;\n transition: all 0.2s ease;\n white-space: nowrap;\n cursor: default;\n flex-shrink: 0; /* Запрещаем сжатие счетчика */\n margin-right: 10px;\n}\n\n// .fileCount:hover {\n// border-color: var(--colorPrimary);\n// color: var(--colorPrimary);\n// }\n\n:global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected) {\n background-color: transparent !important;\n}\n\n/* :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected):hover {\n color: red !important;\n} */\n\n/* Стили для выделения текста в выбранной папке */\n.folderMenu :global(.ant-tree-treenode-selected .folder-label span),\n.folderMenu :global(.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected .folderLabelItem),\n.folderMenu :global(.ant-tree-treenode-selected .folderLabelItem),\n.folderMenu :global(.ant-tree-node-selected .folderLabelItem) {\n font-weight: 600 !important;\n}\n\n/* Стили для иконки в выбранной папке */\n/* .folderMenu :global(.ant-tree-treenode-selected .folderIcon),\n.folderMenu :global(.ant-tree-node-selected .folderIcon) {\n color: red !important;\n} */\n\n/* CSS переменные для упрощения расчетов */\n\n.uploadButton {\n width: 100%;\n justify-content: flex-start;\n\n & button:hover {\n background-color: var(--colorPrimaryHover) !important;\n }\n}\n\n.folderMenu {\n padding-left: 0;\n padding-right: 0; /* Место для кнопки справа */\n}\n\n.folderMenu :global(.ant-tree-treenode) {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 0;\n border-radius: 4px;\n transition: background-color 0.2s ease;\n width: 100%;\n margin-bottom: 0;\n}\n\n.folderMenu :global(.ant-tree-node-content-wrapper) {\n flex: 1;\n /* display: flex; */\n align-items: center;\n padding: 0;\n /* border-radius: 4px; */\n transition: background-color 0.2s ease;\n}\n\n.folderMenu :global(.ant-tree-node-content-wrapper:hover) {\n background-color: transparent;\n}\n\n.folderMenu :global(.ant-tree-switcher) {\n height: 24px;\n width: 24px;\n margin-top: 5px;\n display: flex !important;\n align-items: center;\n justify-content: center;\n transition: color 0.2s ease;\n flex-shrink: 0; /* Запрещаем сжатие переключателя */\n}\n\n.folderMenu :global(.ant-tree-switcher-noop) {\n width: 24px;\n}\n\n/* Стили для линий дерева */\n.folderMenu :global(.ant-tree-switcher-line-icon) {\n color: #d9d9d9;\n}\n\n/* Улучшение отображения folder-item-container */\n.folderMenu .folderItemContainer {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 0;\n min-width: 0; /* Позволяет flex-элементам сжиматься */\n}\n\n.folderMenu :global(.folder-label) {\n display: flex;\n align-items: center;\n flex: 1;\n color: #595959;\n font-size: 14px;\n min-width: 0;\n overflow: hidden;\n}\n\n/* Стили для корневого элемента Folders */\n.folderMenu :global(.ant-tree-treenode[data-key='folders']) {\n border-bottom: 1px solid var(--colorBorderSecondary);\n margin-bottom: 8px;\n padding-bottom: 8px;\n}\n\n.folderMenu :global(.ant-tree-treenode[data-key='folders'].ant-tree-treenode-selected) {\n background-color: transparent !important;\n}\n\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper) {\n padding: 0;\n}\n\n.folderMenu :global(.ant-tree-treenode[data-key='folders'] .ant-tree-node-content-wrapper:hover) {\n background-color: transparent !important;\n}\n\n/* Стили для ellipsis - удаляем max-width для гибкости */\n.folderMenu :global(.ellipsis) {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n min-width: 0;\n}\n\n/* Стили для пустого состояния */\n.folderMenu .emptyFolderContainer {\n padding: 20px;\n text-align: center;\n}\n\n/* Убираем отступы у корневого узла */\n.folderMenu :global(.ant-tree > .ant-tree-treenode) {\n padding-left: 0 !important;\n}\n.folderIcon {\n margin-right: 8px;\n font-size: 18px;\n flex-shrink: 0; /* Запрещаем сжатие иконки */\n}\n\n.folderLabelItem {\n font-size: 14px;\n white-space: nowrap; /* Запрещаем перенос строк */\n overflow: hidden; /* Скрываем переполнение */\n text-overflow: ellipsis; /* Показываем троеточие */\n flex: 1; /* Занимает доступное место */\n min-width: 0; /* Позволяет сжиматься */\n user-select: none;\n}\n\n.foldersTitleItem {\n display: flex;\n align-items: center;\n flex: 1;\n cursor: pointer;\n min-width: 0; /* Позволяет сжиматься */\n overflow: hidden; /* Скрываем переполнение */\n}\n\n/* .foldersTitleItem .folderLabelItem {\n font-weight: 500;\n color: #262626;\n} */\n\n/* Класс для заголовка папок */\n.folderLabel {\n display: flex;\n align-items: center;\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n\n.foldersContainer {\n position: relative;\n width: 100%;\n}\n\n/* Дополнительные стили для улучшения визуала */\n/* .folderMenu :global(.ant-tree-treenode:hover .folder-label span) {\n color: #1890ff;\n} */\n\n/* Стили для дивайдера между папками */\n\n\n.uploadButton .ant-btn,\n.uploadButton :global(.ant-btn) {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 3px;\n}\n/* .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\n color: #1890ff !important;\n} */\n\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderLabelItem,\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabel .folderIcon,\n// .folderMenu :global(.ant-tree-treenode-selected) .folderLabelItem {\n// color: var(--colorLink);\n// }\n\n\n.buttonWrapper {\n // overflow: hidden;\n margin-bottom: 24px;\n display: flex;\n gap: 4px;\n // border-radius: calc(var(--borderRadius) * 1px);\n \n // Левая кнопка занимает всю доступную ширину\n > :first-child {\n flex: 1;\n height: 40px;\n padding-left: 10px;\n }\n \n // Правая кнопка строго 40px\n > :last-child {\n width: 40px;\n height: 40px;\n flex-shrink: 0;\n }\n}\n\n/* Кнопка «Загрузить по URL» — icon-only, поэтому хост-приложение может задать ей\n свои размеры глобальным правилом `.ant-btn.ant-btn-icon-only` (в emailmaker это\n --formControlHeight: 34) и она становится ниже кнопки «Загрузить файл».\n Три класса в селекторе перебивают такие правила без !important. */\n.uploadByURLButton:global(.ant-btn.ant-btn-icon-only) {\n width: 40px;\n min-width: 40px;\n height: 40px;\n padding: 0;\n flex-shrink: 0;\n}\n\n.uploadButtonIcon {\n font-size: 20px;\n}\n\n.uploadButtonTitle {\n line-height: 1em;\n}\n\n.emptyFolderContainer {\n user-select: none;\n cursor: default;\n color: var(--colorTextTertiary);\n}\n\n.folderItemContainer {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 0;\n min-width: 0; /* Позволяет flex-элементам сжиматься */\n}\n\n/** Tab locked by the host (e.g. by subscription plan): still shown, but badged with a lock. */\n.lockedTabIcon {\n position: relative;\n display: inline-flex;\n opacity: 0.55;\n}\n\n.lockedTabLock {\n position: absolute;\n right: -4px;\n bottom: -2px;\n opacity: 1;\n border-radius: 100%;\n background-color: var(--colorBgContainer);\n}\n"],"sourceRoot":""}]);
48435
48479
  // Exports
48436
48480
  ___CSS_LOADER_EXPORT___.locals = {
48437
48481
  "button": `FolderSidebar-module__button__Yf2rX`,
@@ -48456,7 +48500,9 @@ ___CSS_LOADER_EXPORT___.locals = {
48456
48500
  "uploadByURLButton": `FolderSidebar-module__uploadByURLButton__epMiC`,
48457
48501
  "uploadByUrlButton": `FolderSidebar-module__uploadByURLButton__epMiC`,
48458
48502
  "uploadButtonIcon": `FolderSidebar-module__uploadButtonIcon__mWQmq`,
48459
- "uploadButtonTitle": `FolderSidebar-module__uploadButtonTitle__wk_o6`
48503
+ "uploadButtonTitle": `FolderSidebar-module__uploadButtonTitle__wk_o6`,
48504
+ "lockedTabIcon": `FolderSidebar-module__lockedTabIcon__gYKRY`,
48505
+ "lockedTabLock": `FolderSidebar-module__lockedTabLock__rbkfX`
48460
48506
  };
48461
48507
  module.exports = ___CSS_LOADER_EXPORT___;
48462
48508
 
@@ -48916,7 +48962,7 @@ __webpack_require__.d(__webpack_exports__, {
48916
48962
  "default": () => (/* binding */ src)
48917
48963
  });
48918
48964
 
48919
- // UNUSED EXPORTS: DEFAULT_FILE_MANAGER_CACHE_TTL_MS, DataSourceProxyBase, FailedRequestCache, FileContent, FileManagerApiError, FileManagerApp, FileManagerAppWithContext, FileModals, FolderSidebar, MutationRegistry, PathAwareStorageAdapter, PixieOnlyApp, TRASH_FOLDER_ID, TreeCache, ViewCacheManager, buildAssetsPath, compareFileSystemItems, createSystemFolderByPathResolver, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, defaultIsFolderNotFoundError, fetchRemoteImageBlobByUrl, getAssetsBase, getTrashFolderLookupCandidates, init, initFileManager, initPixieEditor, installResizeObserverErrorHandler, joinUrls, mapHttpStatusToErrorCode, matchesChildrenViewFilter, normalizeSystemFolderPath, resolveSortParams, resolveViewStrategyOptions, uninstallResizeObserverErrorHandler, unmount, unmountPixieEditor
48965
+ // UNUSED EXPORTS: DEFAULT_FILE_MANAGER_CACHE_TTL_MS, DataSourceProxyBase, FailedRequestCache, FileContent, FileManagerApiError, FileManagerApp, FileManagerAppWithContext, FileModals, FolderSidebar, MutationRegistry, PathAwareStorageAdapter, PixieOnlyApp, TRASH_FOLDER_ID, TreeCache, ViewCacheManager, buildAssetsPath, compareFileSystemItems, createSystemFolderByPathResolver, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, defaultHasSortValue, defaultIsFolderNotFoundError, fetchRemoteImageBlobByUrl, getAssetsBase, getTrashFolderLookupCandidates, hasComparableSortValue, init, initFileManager, initPixieEditor, installResizeObserverErrorHandler, joinUrls, mapHttpStatusToErrorCode, matchesChildrenViewFilter, normalizeSystemFolderPath, resolveSortParams, resolveViewStrategyOptions, uninstallResizeObserverErrorHandler, unmount, unmountPixieEditor
48920
48966
 
48921
48967
  // EXTERNAL MODULE: ./node_modules/react/jsx-runtime.js
48922
48968
  var jsx_runtime = __webpack_require__(4848);
@@ -50536,6 +50582,16 @@ function isImageItem(file) {
50536
50582
  (((_a = file.type) === null || _a === void 0 ? void 0 : _a.startsWith('image/')) ? (_c = (_b = file.type.split('/')[1]) === null || _b === void 0 ? void 0 : _b.split(';')[0]) === null || _c === void 0 ? void 0 : _c.trim() : undefined);
50537
50583
  return Boolean(extension && constants/* IMAGE_EXTENSIONS */.f9.includes(extension.toLowerCase()));
50538
50584
  }
50585
+ /**
50586
+ * Полноразмерный файл как источник превью, пока миниатюры нет.
50587
+ * Свежезагруженный файл получает её не сразу, а без источника превью не рендерится вовсе.
50588
+ */
50589
+ function resolvePreviewFallbackUrl(file, context) {
50590
+ if (context.previewFallbackToFileUrl === false) {
50591
+ return undefined;
50592
+ }
50593
+ return file.url && isImageItem(file) ? file.url : undefined;
50594
+ }
50539
50595
  function formatDateText(dateString, t) {
50540
50596
  if (!dateString) {
50541
50597
  return '';
@@ -50564,7 +50620,7 @@ function formatDateText(dateString, t) {
50564
50620
  return t('Added', { date: `${day} ${month} ${year}` });
50565
50621
  }
50566
50622
  function buildSignature(file, context) {
50567
- var _a, _b, _c, _d, _e, _f, _g, _h;
50623
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
50568
50624
  const isFolder = Boolean(file.isFolder);
50569
50625
  const folderResolved = isFolder ? resolveFolderItemCount(file, context.folderFileCounts) : null;
50570
50626
  const folderCountSig = isFolder ? (folderResolved === null ? 'u' : String(folderResolved)) : '0';
@@ -50572,16 +50628,16 @@ function buildSignature(file, context) {
50572
50628
  const sizeText = !isFolder && file.size ? String(file.size) : '';
50573
50629
  const thumb = file.thumbnailUrl || file.thumbnail;
50574
50630
  const imageFileUrl = file.url && isImageItem(file) ? file.url : '';
50575
- const previewFallbackSrc = context.previewFallbackToFileUrl ? imageFileUrl : '';
50631
+ const previewFallbackSrc = (_a = resolvePreviewFallbackUrl(file, context)) !== null && _a !== void 0 ? _a : '';
50576
50632
  const featureFlags = [
50577
- ((_a = context.features) === null || _a === void 0 ? void 0 : _a.enableEdit) !== false,
50578
- ((_b = context.features) === null || _b === void 0 ? void 0 : _b.enableMoveFolder) !== false,
50579
- ((_c = context.features) === null || _c === void 0 ? void 0 : _c.enableMoveItem) !== false,
50580
- ((_d = context.features) === null || _d === void 0 ? void 0 : _d.enableCopyFolder) !== false,
50581
- ((_e = context.features) === null || _e === void 0 ? void 0 : _e.enableCopyItem) !== false,
50582
- ((_f = context.features) === null || _f === void 0 ? void 0 : _f.enableRenameFolder) !== false,
50583
- ((_g = context.features) === null || _g === void 0 ? void 0 : _g.enableRenameFile) !== false,
50584
- ((_h = context.features) === null || _h === void 0 ? void 0 : _h.enableDelete) !== false,
50633
+ ((_b = context.features) === null || _b === void 0 ? void 0 : _b.enableEdit) !== false,
50634
+ ((_c = context.features) === null || _c === void 0 ? void 0 : _c.enableMoveFolder) !== false,
50635
+ ((_d = context.features) === null || _d === void 0 ? void 0 : _d.enableMoveItem) !== false,
50636
+ ((_e = context.features) === null || _e === void 0 ? void 0 : _e.enableCopyFolder) !== false,
50637
+ ((_f = context.features) === null || _f === void 0 ? void 0 : _f.enableCopyItem) !== false,
50638
+ ((_g = context.features) === null || _g === void 0 ? void 0 : _g.enableRenameFolder) !== false,
50639
+ ((_h = context.features) === null || _h === void 0 ? void 0 : _h.enableRenameFile) !== false,
50640
+ ((_j = context.features) === null || _j === void 0 ? void 0 : _j.enableDelete) !== false,
50585
50641
  ].join('|');
50586
50642
  const previewKey = [
50587
50643
  thumb || '',
@@ -50623,7 +50679,7 @@ const fileListAdapter = {
50623
50679
  const gridInfoText = isFolder ? folderItemsText : [dimensionsText, sizeText, typeText].filter(Boolean).join(' • ');
50624
50680
  const thumb = file.thumbnailUrl || file.thumbnail;
50625
50681
  const imageFileUrl = file.url && isImageItem(file) ? file.url : undefined;
50626
- const previewFallbackSrc = context.previewFallbackToFileUrl ? imageFileUrl : undefined;
50682
+ const previewFallbackSrc = resolvePreviewFallbackUrl(file, context);
50627
50683
  return {
50628
50684
  id: meta.id,
50629
50685
  signature: meta.signature,
@@ -51463,6 +51519,8 @@ const FileModals = ({ isModalVisible, handleModalOk, handleModalCancel, form, se
51463
51519
  }, closeIcon: (0,jsx_runtime.jsx)(icons_.CloseOutlined, { className: FileModals_module["default"].closeIcon }), centered: true, getContainer: getModalContainer, children: [(0,jsx_runtime.jsx)("div", { children: t('Are you sure you want to permanently delete all items from Trash?') }), isLoading && ((0,jsx_runtime.jsxs)("div", { className: FileModals_module["default"].clearTrashProgress, children: [(0,jsx_runtime.jsx)(external_root_antd_commonjs2_antd_commonjs_antd_amd_antd_.Progress, { percent: 99, status: "active", showInfo: false }), (0,jsx_runtime.jsx)("div", { className: FileModals_module["default"].progressText, children: t('Deleting items...') })] }))] })] }));
51464
51520
  };
51465
51521
 
51522
+ // EXTERNAL MODULE: ./src/utils/libraryTabLock.ts
51523
+ var libraryTabLock = __webpack_require__(8546);
51466
51524
  // EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[3].use[1]!./node_modules/sass-loader/dist/cjs.js!./src/components/FolderSidebar/FolderSidebar.module.scss
51467
51525
  var FolderSidebar_module = __webpack_require__(9287);
51468
51526
  var FolderSidebar_module_default = /*#__PURE__*/__webpack_require__.n(FolderSidebar_module);
@@ -51505,6 +51563,7 @@ var FolderSidebar_module_update = injectStylesIntoStyleTag_default()((FolderSide
51505
51563
 
51506
51564
 
51507
51565
 
51566
+
51508
51567
  const FolderSidebar = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.memo)((0,external_root_React_commonjs2_react_commonjs_react_amd_react_.forwardRef)(({ selectedFolder, generateMenuItems, onFolderSelect, folders,
51509
51568
  // fetchFolders,
51510
51569
  fetchChildFolders, handleAddFile, setIsUrlModalVisible, handleCreateFolder, activeLibraryItem, setActiveLibraryItem, }, ref) => {
@@ -51522,6 +51581,13 @@ fetchChildFolders, handleAddFile, setIsUrlModalVisible, handleCreateFolder, acti
51522
51581
  const isIconStockEnabled = ((_c = config === null || config === void 0 ? void 0 : config.features) === null || _c === void 0 ? void 0 : _c.enableIconStock) !== false && (!(config === null || config === void 0 ? void 0 : config.enabledTabs) || config.enabledTabs.includes('icons'));
51523
51582
  const isImageCodesEnabled = ((_d = config === null || config === void 0 ? void 0 : config.features) === null || _d === void 0 ? void 0 : _d.enableQrBarcodeTab) !== false &&
51524
51583
  (!(config === null || config === void 0 ? void 0 : config.enabledTabs) || config.enabledTabs.includes('codes'));
51584
+ /** Wraps a tab icon with a lock badge when the host marked that tab as locked. */
51585
+ const withLockBadge = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)((icon, tab) => {
51586
+ if (!(0,libraryTabLock/* isLibraryTabLocked */.v)(tab, config)) {
51587
+ return icon;
51588
+ }
51589
+ return ((0,jsx_runtime.jsxs)("span", { className: FolderSidebar_FolderSidebar_module.lockedTabIcon, children: [icon, (0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.Lock01, { size: 12, strokeWidth: 2.5, className: FolderSidebar_FolderSidebar_module.lockedTabLock })] }));
51590
+ }, [config]);
51525
51591
  // кастомные иконки не используются в этом блоке
51526
51592
  const getAllFolderKeys = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)((menuItems) => {
51527
51593
  const keys = [];
@@ -51737,19 +51803,19 @@ fetchChildFolders, handleAddFile, setIsUrlModalVisible, handleCreateFolder, acti
51737
51803
  {
51738
51804
  key: constants/* GIF */.xI,
51739
51805
  label: t('GIF'),
51740
- icon: (0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.PlaySquare, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }),
51806
+ icon: withLockBadge((0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.PlaySquare, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }), constants/* GIF */.xI),
51741
51807
  disabled: !isGifEnabled,
51742
51808
  },
51743
51809
  {
51744
51810
  key: constants/* STOCK_IMAGES */.SM,
51745
51811
  label: t('Stock images'),
51746
- icon: (0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.Colors, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }),
51812
+ icon: withLockBadge((0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.Colors, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }), constants/* STOCK_IMAGES */.SM),
51747
51813
  disabled: !isStockImagesEnabled,
51748
51814
  },
51749
51815
  {
51750
51816
  key: constants/* ICONS */.Ze,
51751
51817
  label: t('Icons'),
51752
- icon: (0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.ThumbsUp, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }),
51818
+ icon: withLockBadge((0,jsx_runtime.jsx)(icons_amd_untitledui_icons_.ThumbsUp, { size: 20, strokeWidth: config === null || config === void 0 ? void 0 : config.iconStrokeWidth }), constants/* ICONS */.Ze),
51753
51819
  disabled: !isIconStockEnabled,
51754
51820
  },
51755
51821
  {
@@ -51775,11 +51841,19 @@ fetchChildFolders, handleAddFile, setIsUrlModalVisible, handleCreateFolder, acti
51775
51841
  setActiveLibraryItem(constants/* MY_FILES */.Zz);
51776
51842
  }
51777
51843
  onFolderSelect === null || onFolderSelect === void 0 ? void 0 : onFolderSelect(key);
51778
- await (fetchChildFolders === null || fetchChildFolders === void 0 ? void 0 : fetchChildFolders(key));
51844
+ // 'folders' — синтетический ключ корневого узла дерева, а не id папки;
51845
+ // fetchChildFolders(null) — тот же смысл, что и для остальных вызовов в дереве.
51846
+ await (fetchChildFolders === null || fetchChildFolders === void 0 ? void 0 : fetchChildFolders(key === 'folders' ? null : key));
51779
51847
  }, [onFolderSelect, activeLibraryItem, setActiveLibraryItem, fetchChildFolders]);
51780
51848
  const handleOpenLibraryChange = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(({ key }) => {
51849
+ var _a;
51850
+ // A locked tab stays closed: the host decides what to show instead (e.g. an upsell).
51851
+ if ((0,libraryTabLock/* isLibraryTabLocked */.v)(key, config)) {
51852
+ (_a = config === null || config === void 0 ? void 0 : config.onLockedTabClick) === null || _a === void 0 ? void 0 : _a.call(config, key);
51853
+ return;
51854
+ }
51781
51855
  setActiveLibraryItem(key);
51782
- }, [setActiveLibraryItem]);
51856
+ }, [config, setActiveLibraryItem]);
51783
51857
  const handleTreeExpand = (0,external_root_React_commonjs2_react_commonjs_react_amd_react_.useCallback)(async (keys, info) => {
51784
51858
  var _a;
51785
51859
  setExpandedKeys(keys);
@@ -56845,6 +56919,7 @@ class ViewCacheManager {
56845
56919
  preloadPagesAfter: (_e = resolved.preloadPagesAfter) !== null && _e !== void 0 ? _e : 1,
56846
56920
  comparator: resolved.comparator,
56847
56921
  filterMatch: resolved.filterMatch,
56922
+ hasSortValue: resolved.hasSortValue,
56848
56923
  };
56849
56924
  this.ttl = ttl;
56850
56925
  this.errorTtl = errorTtl !== null && errorTtl !== void 0 ? errorTtl : ttl;
@@ -57288,6 +57363,16 @@ class ViewCacheManager {
57288
57363
  }
57289
57364
  return wasNewPageCreated;
57290
57365
  }
57366
+ /** Whether the entity carries the field this sorted view is ordered by. */
57367
+ canCompareInSortedView(rec, entity) {
57368
+ var _a;
57369
+ const params = (_a = rec.params) !== null && _a !== void 0 ? _a : {};
57370
+ if (!params.sortBy && !params.sortOrder)
57371
+ return true;
57372
+ if (!this.strategy.hasSortValue)
57373
+ return true;
57374
+ return this.strategy.hasSortValue(entity, rec.params);
57375
+ }
57291
57376
  tryInsertSorted(rec, entity, entitiesManager) {
57292
57377
  var _a, _b;
57293
57378
  const comparator = this.strategy.comparator;
@@ -57298,6 +57383,10 @@ class ViewCacheManager {
57298
57383
  const itemType = ((_a = rec.params) === null || _a === void 0 ? void 0 : _a.itemType) || 'all';
57299
57384
  if (!this.isEntityTypeCompatible(entity, itemType))
57300
57385
  return false;
57386
+ // Без значения поля сортировки позиция неизвестна: отказ здесь приводит
57387
+ // к markViewStaleForReload, то есть к перечитыванию листинга с сервера.
57388
+ if (!this.canCompareInSortedView(rec, entity))
57389
+ return false;
57301
57390
  const currentEntities = rec.view.value.map((id) => entitiesManager.getEntity(id));
57302
57391
  if (currentEntities.some((e) => !e))
57303
57392
  return false;
@@ -57959,8 +58048,12 @@ class TreeCache_TreeCache {
57959
58048
  forceInvalidate(id) {
57960
58049
  var _a;
57961
58050
  const ent = this.entities.getEntity(id);
57962
- if (!ent)
58051
+ if (!ent) {
58052
+ // Папки может не быть в графе (корень, синтетические папки) — листинги всё равно сбрасываем.
58053
+ this.views.forceInvalidateChildrenViews(id !== null && id !== void 0 ? id : null);
58054
+ this.invalidateChildrenCountCache(id);
57963
58055
  return;
58056
+ }
57964
58057
  const visited = new Set();
57965
58058
  if (isFolderEntity(ent)) {
57966
58059
  const stack = [id];
@@ -58856,7 +58949,7 @@ class DataSourceProxyBase {
58856
58949
  return result;
58857
58950
  }
58858
58951
  async uploadFiles(request) {
58859
- var _a, _b, _c, _d, _e;
58952
+ var _a, _b, _c, _d, _e, _f, _g;
58860
58953
  const tempFolder = request.items.some(item => item.noFolder) ? await this.getTempFolder() : null;
58861
58954
  request = Object.assign(Object.assign({}, request), { items: (_a = request.items) === null || _a === void 0 ? void 0 : _a.map((f) => (Object.assign(Object.assign({}, f), { folderId: f.noFolder ? tempFolder === null || tempFolder === void 0 ? void 0 : tempFolder.id : f.folderId }))) });
58862
58955
  for (const item of request.items) {
@@ -58881,7 +58974,6 @@ class DataSourceProxyBase {
58881
58974
  }
58882
58975
  }
58883
58976
  }
58884
- const cachedFolder = this._cache.getEntity(folderIdNormalized);
58885
58977
  let batchResult = { detailed: new Array(filesToUpload.length), success: true };
58886
58978
  if (typeof this._dataProvider.uploadFiles === 'function') {
58887
58979
  const providerFiles = filesToUpload.map((f) => {
@@ -58905,13 +58997,19 @@ class DataSourceProxyBase {
58905
58997
  thumbnail: data.thumbnail,
58906
58998
  };
58907
58999
  });
59000
+ // Ответ провайдера до обрезки до публичного UploadFileResultData: индексы
59001
+ // совпадают с batchResult.detailed, оба собраны из одного массива.
59002
+ const providerDetailed = providerResult === null || providerResult === void 0 ? void 0 : providerResult.detailed;
58908
59003
  if (batchResult.detailed && batchResult.detailed.length) {
58909
59004
  for (let i = 0; i < batchResult.detailed.length; i++) {
58910
59005
  const current = batchResult.detailed[i];
58911
59006
  if (current && current.success) {
58912
59007
  const uploaded = current.data;
58913
59008
  const id = (_d = uploaded === null || uploaded === void 0 ? void 0 : uploaded.id) !== null && _d !== void 0 ? _d : current.requestId;
58914
- const entity = normalizeFileSystemItem(Object.assign(Object.assign(Object.assign({}, cachedFolder), uploaded), { folderId: (_e = uploaded === null || uploaded === void 0 ? void 0 : uploaded.folderId) !== null && _e !== void 0 ? _e : folderIdNormalized }));
59009
+ // В кэш кладём полный ответ провайдера: без date/size/type сущность
59010
+ // встаёт в отсортированный листинг наугад (по дате — в самый конец).
59011
+ const providerItem = (_e = providerDetailed === null || providerDetailed === void 0 ? void 0 : providerDetailed[i]) === null || _e === void 0 ? void 0 : _e.data;
59012
+ const entity = normalizeFileSystemItem(Object.assign(Object.assign(Object.assign({}, providerItem), uploaded), { id, folderId: (_g = (_f = uploaded === null || uploaded === void 0 ? void 0 : uploaded.folderId) !== null && _f !== void 0 ? _f : providerItem === null || providerItem === void 0 ? void 0 : providerItem.folderId) !== null && _g !== void 0 ? _g : folderIdNormalized, isFolder: false }));
58915
59013
  // Если провайдер вернул только id/data, всё равно апдейтим кэш
58916
59014
  this._cache.upsertEntity(entity);
58917
59015
  // Нормализуем id в detailed (на случай, если провайдер пропустил)
@@ -1,6 +1,14 @@
1
1
  import { Folder, MenuItem } from '../../types';
2
2
  import { FileManagerHookBase } from './types';
3
3
  import type { FormInstance } from 'antd';
4
+ /**
5
+ * Ленивый режим дерева (`folderTreeLoading: 'lazy'`) не обходит поддеревья — свежий
6
+ * root-фетч содержит только корневые папки. Старые вложенные записи (с `parentId`)
7
+ * сохраняются как есть, НО если тот же `id` уже есть в свежем корневом ответе
8
+ * (сервер теперь считает папку корневой), старая копия вытесняется, а не дублируется
9
+ * рядом с новой (см. DEV-дубликаты в дереве после загрузки файла в подпапку).
10
+ */
11
+ export declare function mergeLazyRootFolders(prev: Folder[], rootFolders: Folder[]): Folder[];
4
12
  export interface UseFoldersState {
5
13
  folders: Folder[];
6
14
  isCreatingFolder: boolean;
package/index.d.ts CHANGED
@@ -23,7 +23,7 @@ export { mapHttpStatusToErrorCode } from './shared/mapHttpStatusToErrorCode';
23
23
  export { buildAssetsPath, joinUrls, getAssetsBase } from './helpers/urls';
24
24
  export { FailedRequestCache } from './adapters/FailedRequestCache';
25
25
  export { MutationRegistry } from './adapters/MutationRegistry';
26
- export { compareFileSystemItems, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, matchesChildrenViewFilter, resolveSortParams, resolveViewStrategyOptions, } from './adapters/cacheViewStrategy';
26
+ export { compareFileSystemItems, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, defaultHasSortValue, hasComparableSortValue, matchesChildrenViewFilter, resolveSortParams, resolveViewStrategyOptions, } from './adapters/cacheViewStrategy';
27
27
  export { TRASH_FOLDER_ID, createSystemFolderByPathResolver, getTrashFolderLookupCandidates, normalizeSystemFolderPath, type SystemFolderDefinition, } from './adapters/systemFolderPath';
28
28
  export { TreeCache, ViewCacheManager, DEFAULT_FILE_MANAGER_CACHE_TTL_MS, defaultIsFolderNotFoundError, type TreeCacheConfig, type QueryResult, type ChildrenQueryParams, type ViewStrategyOptions, } from './adapters/TreeCache';
29
29
  export { DataSourceProxyBase, type DataSourceProxyConfig, type DataSourceProxyOptions, type FileManagerProxyOptions, } from './adapters/DataSourceProxyBase';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emailmaker/filemanager",
3
- "version": "0.10.97",
3
+ "version": "0.10.99",
4
4
  "main": "./file-manager.js",
5
5
  "module": "./file-manager.esm.js",
6
6
  "types": "./index.d.ts",
@@ -7,7 +7,7 @@ export interface FileListContext {
7
7
  folderFileCounts: Record<string, number | null>;
8
8
  features: Record<string, boolean | undefined>;
9
9
  t: TFunction;
10
- /** См. Config.previewFallbackToFileUrl */
10
+ /** См. Config.previewFallbackToFileUrl. Не задан — считается включённым. */
11
11
  previewFallbackToFileUrl?: boolean;
12
12
  }
13
13
  export declare const fileListAdapter: ListItemAdapter<AppFile, FileListContext, FileListRowModel>;
package/types.d.ts CHANGED
@@ -463,6 +463,14 @@ export interface Config {
463
463
  /** Включить удаление */
464
464
  enableDelete?: boolean;
465
465
  };
466
+ /**
467
+ * Library tabs shown with a lock badge instead of being usable — for hosts that gate features
468
+ * by subscription plan. Clicking a locked tab fires `onLockedTabClick` and does not open it.
469
+ * Absent or empty: nothing is locked (previous behaviour).
470
+ */
471
+ lockedTabs?: LibraryMenuKey[];
472
+ /** Called when the user clicks a tab listed in `lockedTabs`, e.g. to show an upsell dialog. */
473
+ onLockedTabClick?: (tab: LibraryMenuKey) => void;
466
474
  dataProcessingMode?: 'server' | 'client' | 'auto';
467
475
  enableClientSideProcessing?: boolean;
468
476
  disablePagination?: boolean;
@@ -477,7 +485,8 @@ export interface Config {
477
485
  dedupeUploadNamesOnClient?: boolean;
478
486
  /**
479
487
  * Для превью в таблице/плитке разрешить fallback на `file.url` (только изображения),
480
- * если миниатюры нет или она загрузилась с ошибкой.
488
+ * если миниатюры нет или она загрузилась с ошибкой. По умолчанию включён;
489
+ * `false` оставляет элемент без превью, пока миниатюра не готова.
481
490
  */
482
491
  previewFallbackToFileUrl?: boolean;
483
492
  /**