lexgui 8.1.1 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/build/components/Avatar.d.ts +15 -0
  2. package/build/components/NodeTree.d.ts +51 -26
  3. package/build/components/Vector.d.ts +10 -9
  4. package/build/core/Event.d.ts +6 -26
  5. package/build/core/Namespace.js +1 -1
  6. package/build/core/Namespace.js.map +1 -1
  7. package/build/core/Panel.d.ts +538 -538
  8. package/build/extensions/AssetView.d.ts +7 -6
  9. package/build/extensions/AssetView.js +194 -155
  10. package/build/extensions/AssetView.js.map +1 -1
  11. package/build/extensions/Audio.js.map +1 -1
  12. package/build/extensions/CodeEditor.d.ts +358 -350
  13. package/build/extensions/CodeEditor.js +5054 -5022
  14. package/build/extensions/CodeEditor.js.map +1 -1
  15. package/build/extensions/DocMaker.js +330 -327
  16. package/build/extensions/DocMaker.js.map +1 -1
  17. package/build/extensions/GraphEditor.js +2754 -2760
  18. package/build/extensions/GraphEditor.js.map +1 -1
  19. package/build/extensions/Timeline.d.ts +668 -670
  20. package/build/extensions/Timeline.js +3948 -3955
  21. package/build/extensions/Timeline.js.map +1 -1
  22. package/build/extensions/VideoEditor.d.ts +128 -128
  23. package/build/extensions/VideoEditor.js +893 -898
  24. package/build/extensions/VideoEditor.js.map +1 -1
  25. package/build/index.css.d.ts +3 -4
  26. package/build/index.d.ts +57 -56
  27. package/build/lexgui.all.js +1587 -1369
  28. package/build/lexgui.all.js.map +1 -1
  29. package/build/lexgui.all.min.js +1 -1
  30. package/build/lexgui.all.module.js +1584 -1364
  31. package/build/lexgui.all.module.js.map +1 -1
  32. package/build/lexgui.all.module.min.js +1 -1
  33. package/build/lexgui.css +6157 -5583
  34. package/build/lexgui.js +977 -815
  35. package/build/lexgui.js.map +1 -1
  36. package/build/lexgui.min.css +2 -3
  37. package/build/lexgui.min.js +1 -1
  38. package/build/lexgui.module.js +975 -811
  39. package/build/lexgui.module.js.map +1 -1
  40. package/build/lexgui.module.min.js +1 -1
  41. package/changelog.md +52 -1
  42. package/demo.js +167 -65
  43. package/examples/all-components.html +38 -52
  44. package/examples/asset-view.html +27 -0
  45. package/examples/code-editor.html +1 -1
  46. package/examples/editor.html +10 -95
  47. package/examples/index.html +2 -2
  48. package/examples/side-bar.html +1 -1
  49. package/examples/timeline.html +2 -2
  50. package/examples/video-editor.html +1 -1
  51. package/examples/video-editor2.html +2 -2
  52. package/package.json +7 -4
@@ -2,7 +2,8 @@ import { LX } from '../core/Namespace';
2
2
  declare const Area: any;
3
3
  declare const Panel: any;
4
4
  declare const NodeTree: any;
5
- export type AssetViewAction = 'select' | 'dbl_click' | 'check' | 'clone' | 'move' | 'delete' | 'rename' | 'enter_folder' | 'create-folder';
5
+ declare const Tree: any;
6
+ export type AssetViewAction = 'select' | 'dbl_click' | 'check' | 'clone' | 'move' | 'delete' | 'rename' | 'enter_folder' | 'create-folder' | 'refresh-content' | 'node-drag';
6
7
  export interface AssetViewItem {
7
8
  id: string;
8
9
  type: string;
@@ -23,6 +24,7 @@ interface AssetViewEvent {
23
24
  where?: AssetViewItem;
24
25
  oldName?: string;
25
26
  newName?: string;
27
+ search?: any[];
26
28
  userInitiated: boolean;
27
29
  }
28
30
  /**
@@ -70,9 +72,7 @@ export declare class AssetView {
70
72
  allowMultipleSelection: boolean;
71
73
  previewActions: any[];
72
74
  contextMenu: any[];
73
- onRefreshContent: any;
74
75
  itemContextMenuOptions: any;
75
- onItemDragged: any;
76
76
  private _assetsPerPage;
77
77
  get assetsPerPage(): any;
78
78
  set assetsPerPage(v: any);
@@ -107,10 +107,11 @@ export declare class AssetView {
107
107
  _updatePath(): void;
108
108
  _createNavigationBar(panel: typeof Panel): void;
109
109
  _createTreePanel(area: typeof Area): void;
110
+ _subscribeTreeEvents(tree: typeof Tree): void;
110
111
  _setContentLayout(layoutMode: number): void;
111
112
  _createContentPanel(area: typeof Area): void;
112
113
  _makeNameFilterFn(searchValue: string): (name: string) => boolean;
113
- _refreshContent(searchValue?: string, filter?: string): void;
114
+ _refreshContent(searchValue?: string, filter?: string, userInitiated?: boolean): void;
114
115
  _previewAsset(file: AssetViewItem): void;
115
116
  _processDrop(e: DragEvent): void;
116
117
  _sortData(sortBy?: string, sortMode?: number): void;
@@ -124,8 +125,8 @@ export declare class AssetView {
124
125
  _requestCloneItem(item: AssetViewItem): false | undefined;
125
126
  _cloneItem(item: AssetViewItem): AssetViewItem;
126
127
  _getClonedName(originalName: string, siblings: any[]): string;
127
- _requestRenameItem(item: AssetViewItem, newName: string): void;
128
- _renameItem(item: AssetViewItem, newName: string): void;
128
+ _requestRenameItem(item: AssetViewItem, newName: string, treeEvent?: boolean): void;
129
+ _renameItem(item: AssetViewItem, newName: string, data?: AssetViewItem[]): void;
129
130
  _renameItemPopover(item: AssetViewItem): void;
130
131
  _requestCreateFolder(folder?: AssetViewItem): void;
131
132
  _createFolder(folder?: AssetViewItem): AssetViewItem;
@@ -9,7 +9,7 @@ LX.extensions.push('AssetView');
9
9
  const Area = LX.Area;
10
10
  LX.Panel;
11
11
  LX.NodeTree;
12
- LX.TreeEvent;
12
+ LX.Tree;
13
13
  /**
14
14
  * @class AssetView
15
15
  * @description Asset container with Tree for file system
@@ -51,9 +51,7 @@ class AssetView {
51
51
  allowMultipleSelection = false;
52
52
  previewActions = [];
53
53
  contextMenu = [];
54
- onRefreshContent = null;
55
54
  itemContextMenuOptions = null;
56
- onItemDragged = null;
57
55
  _assetsPerPage = 24;
58
56
  get assetsPerPage() {
59
57
  return this._assetsPerPage;
@@ -92,8 +90,6 @@ class AssetView {
92
90
  this.allowMultipleSelection = options.allowMultipleSelection ?? this.allowMultipleSelection;
93
91
  this.previewActions = options.previewActions ?? [];
94
92
  this.itemContextMenuOptions = options.itemContextMenuOptions;
95
- this.onRefreshContent = options.onRefreshContent;
96
- this.onItemDragged = options.onItemDragged;
97
93
  this.gridScale = options.gridScale ?? this.gridScale;
98
94
  if (this.gridScale !== 1.0) {
99
95
  const r = document.querySelector(':root');
@@ -154,8 +150,7 @@ class AssetView {
154
150
  this.currentData = this.data;
155
151
  this.path = ['@'];
156
152
  if (!this.skipBrowser) {
157
- this.tree.refresh({ id: '/', children: this.data, type: 'folder',
158
- metadata: { uid: LX.guidGenerator() } });
153
+ this.tree.refresh({ id: '/', children: this.data, type: 'folder', metadata: { uid: LX.guidGenerator() } });
159
154
  }
160
155
  this._refreshContent();
161
156
  }
@@ -239,10 +234,8 @@ class AssetView {
239
234
  });
240
235
  itemEl.appendChild(checkbox);
241
236
  }
242
- let title = document.createElement('span');
243
- title.className = 'lexassettitle';
244
- title.innerText = item.id;
245
- itemEl.appendChild(title);
237
+ // Asset title
238
+ LX.makeElement('span', 'lexassettitle absolute w-full h-8 bottom-0 text-sm bg-card text-card-foreground cursor-pointer text-center content-center block px-3 py-0.5 truncate z-1 pointer-events-none', item.id, itemEl);
246
239
  if (!this.skipPreview) {
247
240
  if (item.type === 'video') {
248
241
  const itemVideo = LX.makeElement('video', 'absolute left-0 top-0 w-full border-none pointer-events-none', '', itemEl);
@@ -330,7 +323,6 @@ class AssetView {
330
323
  userInitiated: true
331
324
  };
332
325
  onDblClick(event);
333
- // event.multiple = !!e.shiftKey;
334
326
  }
335
327
  else if (!isDoubleClick && onSelect !== undefined) {
336
328
  const event = {
@@ -339,7 +331,6 @@ class AssetView {
339
331
  userInitiated: true
340
332
  };
341
333
  onSelect(event);
342
- // event.multiple = !!e.shiftKey;
343
334
  }
344
335
  });
345
336
  itemEl.addEventListener('contextmenu', function (e) {
@@ -350,23 +341,21 @@ class AssetView {
350
341
  const options = [
351
342
  {
352
343
  name: (multiple > 1) ? (multiple + ' selected') : item.id,
353
- icon: LX.makeIcon('CircleSmall', { svgClass: `fill-current fg-${typeColor}` }),
344
+ icon: LX.makeIcon('CircleSmall', { svgClass: `fill-current text-${typeColor}` }),
354
345
  className: 'text-sm',
355
346
  disabled: true
356
347
  },
357
348
  null
358
349
  ];
359
350
  if (multiple <= 1) {
360
- options.push({ name: 'Rename', icon: 'TextCursor',
361
- callback: that._renameItemPopover.bind(that, item) });
351
+ options.push({ name: 'Rename', icon: 'TextCursor', callback: that._renameItemPopover.bind(that, item) });
362
352
  }
363
353
  if (!isFolder) {
364
354
  options.push({ name: 'Clone', icon: 'Copy', callback: that._requestCloneItem.bind(that, item) });
365
355
  }
366
356
  options.push({ name: 'Move', icon: 'FolderInput', callback: () => that._moveItem(item) });
367
357
  if (type == 'Script' && LX.has('CodeEditor')) {
368
- options.push({ name: 'Open in Editor', icon: 'Code',
369
- callback: that._openScriptInEditor.bind(that, item) });
358
+ options.push({ name: 'Open in Editor', icon: 'Code', callback: that._openScriptInEditor.bind(that, item) });
370
359
  }
371
360
  if (that.itemContextMenuOptions) {
372
361
  options.push(null);
@@ -376,7 +365,7 @@ class AssetView {
376
365
  options.push({ name: o.name, icon: o.icon, callback: o.callback?.bind(that, item) });
377
366
  }
378
367
  }
379
- options.push(null, { name: 'Delete', icon: 'Trash2', className: 'fg-error',
368
+ options.push(null, { name: 'Delete', icon: 'Trash2', className: 'text-destructive',
380
369
  callback: that._requestDeleteItem.bind(that, item) });
381
370
  LX.addClass(that.contentPanel.root, 'pointer-events-none');
382
371
  LX.addDropdownMenu(e.target, options, { side: 'right', align: 'start', event: e, onBlur: () => {
@@ -530,20 +519,20 @@ class AssetView {
530
519
  return;
531
520
  this.nextData.push(this.currentFolder);
532
521
  this._enterFolder(this.prevData.pop(), false);
533
- }, { buttonClass: 'bg-none', title: 'Go Back', tooltip: true, icon: 'ArrowLeft' });
522
+ }, { buttonClass: 'ghost', title: 'Go Back', tooltip: true, icon: 'ArrowLeft' });
534
523
  panel.addButton(null, 'GoForwardButton', () => {
535
524
  if (!this.nextData.length || !this.currentFolder)
536
525
  return;
537
526
  this._enterFolder(this.nextData.pop());
538
- }, { buttonClass: 'bg-none', title: 'Go Forward', tooltip: true, icon: 'ArrowRight' });
527
+ }, { buttonClass: 'ghost', title: 'Go Forward', tooltip: true, icon: 'ArrowRight' });
539
528
  panel.addButton(null, 'GoUpButton', () => {
540
529
  const parentFolder = this.currentFolder?.parent;
541
530
  if (parentFolder)
542
531
  this._enterFolder(parentFolder);
543
- }, { buttonClass: 'bg-none', title: 'Go Upper Folder', tooltip: true, icon: 'ArrowUp' });
544
- panel.addButton(null, 'GoUpButton', () => {
545
- this._refreshContent();
546
- }, { buttonClass: 'bg-none', title: 'Refresh', tooltip: true, icon: 'Refresh' });
532
+ }, { buttonClass: 'ghost', title: 'Go Upper Folder', tooltip: true, icon: 'ArrowUp' });
533
+ panel.addButton(null, 'RefreshButton', () => {
534
+ this._refreshContent(undefined, undefined, true);
535
+ }, { buttonClass: 'ghost', title: 'Refresh', tooltip: true, icon: 'Refresh' });
547
536
  }
548
537
  _createTreePanel(area) {
549
538
  if (this.leftPanel) {
@@ -555,61 +544,91 @@ class AssetView {
555
544
  this._createNavigationBar(this.leftPanel);
556
545
  const treeData = { id: '/', children: this.data };
557
546
  const tree = this.leftPanel.addTree('Content Browser', treeData, {
558
- // icons: tree_icons,
559
547
  filter: false,
560
- onlyFolders: this.onlyFolders,
561
- onevent: (event) => {
562
- let node = event.node;
563
- let value = event.value;
564
- switch (event.type) {
565
- case LX.TreeEvent.NODE_SELECTED:
566
- {
567
- if (event.multiple) {
568
- return;
569
- }
570
- if (!node.parent) {
571
- if (this.currentFolder) {
572
- this.prevData.push(this.currentFolder);
573
- }
574
- this.currentFolder = undefined;
575
- this.currentData = this.data;
576
- this._refreshContent();
577
- this._updatePath();
578
- }
579
- else {
580
- this._enterFolder(node.type === 'folder' ? node : node.parent);
581
- this._previewAsset(node);
582
- if (node.type !== 'folder') {
583
- this.content.querySelectorAll('.lexassetitem').forEach((i) => i.classList.remove('selected'));
584
- const dom = node.domEl;
585
- dom?.classList.add('selected');
586
- }
587
- this.selectedItem = node;
588
- }
589
- break;
590
- }
591
- case LX.TreeEvent.NODE_DRAGGED:
592
- {
593
- if (node.parent) {
594
- const idx = node.parent.children.indexOf(node);
595
- node.parent.children.splice(idx, 1);
596
- }
597
- if (!value.children) {
598
- value.children = [];
599
- }
600
- value.children.push(node);
601
- node.parent = value;
602
- node.dir = value.children;
603
- if (this.onItemDragged) {
604
- this.onItemDragged(node, value);
605
- }
606
- this._refreshContent();
607
- break;
608
- }
548
+ onlyFolders: this.onlyFolders
549
+ });
550
+ this._subscribeTreeEvents(tree);
551
+ this.tree = tree.innerTree;
552
+ }
553
+ _subscribeTreeEvents(tree) {
554
+ // If some of these events we don't have to call "resolve" since the AV itself
555
+ // will update the data and refresh when necessary
556
+ tree.on("select", (event, resolve) => {
557
+ if (event.items.length > 1) // Do nothing if multiple selection
558
+ {
559
+ return;
560
+ }
561
+ const node = event.items[0];
562
+ if (!node.parent) {
563
+ if (this.currentFolder) {
564
+ this.prevData.push(this.currentFolder);
565
+ }
566
+ this.currentFolder = undefined;
567
+ this.currentData = this.data;
568
+ this._refreshContent();
569
+ this._updatePath();
570
+ }
571
+ else {
572
+ this._enterFolder(node.type === 'folder' ? node : node.parent);
573
+ this._previewAsset(node);
574
+ if (node.type !== 'folder') {
575
+ this.content.querySelectorAll('.lexassetitem').forEach((i) => i.classList.remove('selected'));
576
+ const dom = node.domEl;
577
+ dom?.classList.add('selected');
609
578
  }
579
+ this.selectedItem = node;
610
580
  }
611
581
  });
612
- this.tree = tree.innerTree;
582
+ tree.on("beforeMove", (event, resolve) => {
583
+ const onBeforeNodeDragged = this._callbacks['beforeNodeDragged'];
584
+ const onNodeDragged = this._callbacks['nodeDragged'];
585
+ const node = event.items[0];
586
+ const value = event.to;
587
+ const av_resolve = (...args) => {
588
+ if (node.parent) {
589
+ const idx = node.parent.children.indexOf(node);
590
+ node.parent.children.splice(idx, 1);
591
+ }
592
+ if (!value.children) {
593
+ value.children = [];
594
+ }
595
+ value.children.push(node);
596
+ node.parent = value;
597
+ node.dir = value.children;
598
+ // Resolve Tree move event
599
+ resolve(...args);
600
+ // Fire AV drag event, and not catch the onMove Tree vent
601
+ const av_event = {
602
+ type: 'node-drag',
603
+ items: [node],
604
+ to: value,
605
+ userInitiated: true
606
+ };
607
+ if (onNodeDragged)
608
+ onNodeDragged(av_event, ...args);
609
+ this._refreshContent();
610
+ };
611
+ if (onBeforeNodeDragged) {
612
+ const av_event = {
613
+ type: 'node-drag',
614
+ items: [node],
615
+ to: value,
616
+ userInitiated: true
617
+ };
618
+ onBeforeNodeDragged(av_event, av_resolve);
619
+ }
620
+ else {
621
+ av_resolve();
622
+ }
623
+ });
624
+ tree.on("beforeDelete", (event, resolve) => {
625
+ const node = event.items[0];
626
+ this._requestDeleteItem(node);
627
+ });
628
+ tree.on("beforeRename", (event, resolve) => {
629
+ const node = event.items[0];
630
+ this._requestRenameItem(node, event.newName, true);
631
+ });
613
632
  }
614
633
  _setContentLayout(layoutMode) {
615
634
  this.layout = layoutMode;
@@ -647,17 +666,14 @@ class AssetView {
647
666
  { name: 'Name', icon: 'ALargeSmall', callback: () => this._sortData('id') },
648
667
  { name: 'Type', icon: 'Type', callback: () => this._sortData('type') },
649
668
  null,
650
- { name: 'Ascending', icon: 'SortAsc',
651
- callback: () => this._sortData(undefined, AssetView.CONTENT_SORT_ASC) },
652
- { name: 'Descending', icon: 'SortDesc',
653
- callback: () => this._sortData(undefined, AssetView.CONTENT_SORT_DESC) }
669
+ { name: 'Ascending', icon: 'SortAsc', callback: () => this._sortData(undefined, AssetView.CONTENT_SORT_ASC) },
670
+ { name: 'Descending', icon: 'SortDesc', callback: () => this._sortData(undefined, AssetView.CONTENT_SORT_DESC) }
654
671
  ], { side: 'bottom', align: 'start' });
655
672
  };
656
673
  const _onChangeView = (value, event) => {
657
674
  LX.addDropdownMenu(event.target, [
658
675
  { name: 'Grid', icon: 'LayoutGrid', callback: () => this._setContentLayout(AssetView.LAYOUT_GRID) },
659
- { name: 'Compact', icon: 'LayoutList',
660
- callback: () => this._setContentLayout(AssetView.LAYOUT_COMPACT) },
676
+ { name: 'Compact', icon: 'LayoutList', callback: () => this._setContentLayout(AssetView.LAYOUT_COMPACT) },
661
677
  { name: 'List', icon: 'List', callback: () => this._setContentLayout(AssetView.LAYOUT_LIST) }
662
678
  ], { side: 'bottom', align: 'start' });
663
679
  };
@@ -669,8 +685,8 @@ class AssetView {
669
685
  this._createNavigationBar(this.toolsPanel);
670
686
  }
671
687
  this.toolsPanel.sameLine();
672
- const sortButton = this.toolsPanel.addButton(null, '', _onSort.bind(this), { title: 'Sort',
673
- tooltip: true, icon: (this.sortMode === AssetView.CONTENT_SORT_ASC) ? 'SortAsc' : 'SortDesc' });
688
+ const sortButton = this.toolsPanel.addButton(null, '', _onSort.bind(this), { title: 'Sort', tooltip: true,
689
+ icon: (this.sortMode === AssetView.CONTENT_SORT_ASC) ? 'SortAsc' : 'SortDesc' });
674
690
  this.toolsPanel.addButton(null, '', _onChangeView.bind(this), { title: 'View', tooltip: true,
675
691
  icon: (this.layout === AssetView.LAYOUT_GRID) ? 'LayoutGrid' : 'LayoutList' });
676
692
  this.toolsPanel.addSelect(null, typeEntries, this.filter ?? typeEntries[0], (v) => {
@@ -692,7 +708,7 @@ class AssetView {
692
708
  this.contentPanel.attach(this.content);
693
709
  if (!this.skipBrowser) {
694
710
  this.contentPanel.addText(null, this.path.join('/'), null, {
695
- inputClass: 'bg-none fg-quinary text-end',
711
+ inputClass: 'bg-none text-muted-foreground text-sm text-end',
696
712
  disabled: true,
697
713
  signal: '@on_folder_change'
698
714
  });
@@ -741,48 +757,68 @@ class AssetView {
741
757
  // default case, only check include
742
758
  return (name) => name.toLowerCase().includes(q.toLowerCase());
743
759
  }
744
- _refreshContent(searchValue, filter) {
745
- const isCompactLayout = this.layout == AssetView.LAYOUT_COMPACT;
746
- const isListLayout = this.layout == AssetView.LAYOUT_LIST;
747
- this.filter = filter ?? (this.filter ?? 'None');
748
- this.searchValue = searchValue ?? (this.searchValue ?? '');
749
- this.content.innerHTML = '';
750
- this.content.className = `lexassetscontent${isCompactLayout ? ' compact' : (isListLayout ? ' list' : '')}`;
751
- if (!this.currentData.length) {
752
- return;
753
- }
754
- const fr = new FileReader();
755
- const nameFilterFn = this._makeNameFilterFn(this.searchValue);
756
- const filteredData = this.currentData.filter((_i) => {
757
- const typeMatch = this.filter !== 'None' ? _i.type.toLowerCase() === this.filter.toLowerCase() : true;
758
- const nameMatch = nameFilterFn(_i.id);
759
- return typeMatch && nameMatch;
760
- });
761
- this._paginator?.setPages(Math.max(Math.ceil(filteredData.length / this.assetsPerPage), 1));
762
- // Show all data if using filters
763
- const start = this._paginator ? (this._paginator.page - 1) * this.assetsPerPage : 0;
764
- const end = this._paginator ? Math.min(start + this.assetsPerPage, filteredData.length) : filteredData.length;
765
- for (let i = start; i < end; ++i) {
766
- let item = filteredData[i];
767
- if (item.path) {
768
- LX.request({ url: item.path, dataType: 'blob', success: (f) => {
769
- item.metadata.bytesize = f.size;
770
- fr.readAsDataURL(f);
771
- fr.onload = (e) => {
772
- const target = e.currentTarget;
773
- item.src = target.result; // This is a base64 string...
774
- item.metadata.path = item.path;
775
- delete item.path;
776
- this._refreshContent(searchValue, filter);
777
- };
778
- } });
760
+ _refreshContent(searchValue, filter, userInitiated = false) {
761
+ const onBeforeRefreshContent = this._callbacks['beforeRefreshContent'];
762
+ const onRefreshContent = this._callbacks['refreshContent'];
763
+ const resolve = (...args) => {
764
+ const isCompactLayout = this.layout == AssetView.LAYOUT_COMPACT;
765
+ const isListLayout = this.layout == AssetView.LAYOUT_LIST;
766
+ this.filter = filter ?? (this.filter ?? 'None');
767
+ this.searchValue = searchValue ?? (this.searchValue ?? '');
768
+ this.content.innerHTML = '';
769
+ this.content.className = `lexassetscontent${isCompactLayout ? ' compact' : (isListLayout ? ' list' : '')}`;
770
+ if (!this.currentData.length) {
771
+ return;
779
772
  }
780
- else {
781
- item.domEl = this.addItem(item, undefined, false);
773
+ const fr = new FileReader();
774
+ const nameFilterFn = this._makeNameFilterFn(this.searchValue);
775
+ const filteredData = this.currentData.filter((_i) => {
776
+ const typeMatch = this.filter !== 'None' ? _i.type.toLowerCase() === this.filter.toLowerCase() : true;
777
+ const nameMatch = nameFilterFn(_i.id);
778
+ return typeMatch && nameMatch;
779
+ });
780
+ this._paginator?.setPages(Math.max(Math.ceil(filteredData.length / this.assetsPerPage), 1));
781
+ // Show all data if using filters
782
+ const start = this._paginator ? (this._paginator.page - 1) * this.assetsPerPage : 0;
783
+ const end = this._paginator ? Math.min(start + this.assetsPerPage, filteredData.length) : filteredData.length;
784
+ for (let i = start; i < end; ++i) {
785
+ let item = filteredData[i];
786
+ if (item.path) {
787
+ LX.request({ url: item.path, dataType: 'blob', success: (f) => {
788
+ item.metadata.bytesize = f.size;
789
+ fr.readAsDataURL(f);
790
+ fr.onload = (e) => {
791
+ const target = e.currentTarget;
792
+ item.src = target.result; // This is a base64 string...
793
+ item.metadata.path = item.path;
794
+ delete item.path;
795
+ this._refreshContent(searchValue, filter);
796
+ };
797
+ } });
798
+ }
799
+ else {
800
+ item.domEl = this.addItem(item, undefined, false);
801
+ }
782
802
  }
803
+ const event = {
804
+ type: 'refresh-content',
805
+ search: [this.searchValue, this.filter],
806
+ items: filteredData.slice(start, end),
807
+ userInitiated
808
+ };
809
+ if (onRefreshContent)
810
+ onRefreshContent(event, ...args);
811
+ };
812
+ if (onBeforeRefreshContent) {
813
+ const event = {
814
+ type: 'refresh-content',
815
+ search: [this.searchValue, this.filter],
816
+ userInitiated
817
+ };
818
+ onBeforeRefreshContent(event, resolve);
783
819
  }
784
- if (this.onRefreshContent) {
785
- this.onRefreshContent(searchValue, filter);
820
+ else {
821
+ resolve();
786
822
  }
787
823
  }
788
824
  _previewAsset(file) {
@@ -935,6 +971,7 @@ class AssetView {
935
971
  if (mustRefresh) {
936
972
  this._processData(this.data);
937
973
  this._refreshContent();
974
+ this.tree?.select(this.currentFolder.id);
938
975
  }
939
976
  this._updatePath();
940
977
  }
@@ -1037,6 +1074,7 @@ class AssetView {
1037
1074
  this.tree?.refresh();
1038
1075
  this._moveItemDialog?.destroy();
1039
1076
  this._movingItem = undefined;
1077
+ this.previewPanel?.clear();
1040
1078
  }
1041
1079
  _moveItem(item, defaultFolder) {
1042
1080
  if (this._moveItemDialog) {
@@ -1051,16 +1089,16 @@ class AssetView {
1051
1089
  for (let pi of (targetFolder.children ?? targetFolder)) {
1052
1090
  const row = LX.makeContainer(['100%', 'auto'], 'flex flex-row px-1 items-center', '', container);
1053
1091
  const isFolder = pi.type === 'folder';
1054
- const rowItem = LX.makeContainer(['100%', 'auto'], `move-item flex flex-row gap-1 py-1 px-3 cursor-pointer ${isFolder ? 'fg-primary font-medium' : 'fg-quinary'} rounded-xxl ${isFolder ? 'hover:bg-secondary' : 'hover:bg-primary'}`, `${isFolder ? LX.makeIcon('FolderOpen', { svgClass: '' }).innerHTML : ''}${pi.id}`, row);
1092
+ const rowItem = LX.makeContainer(['100%', 'auto'], `move-item flex flex-row gap-1 py-1 px-3 cursor-pointer items-center ${isFolder ? 'text-foreground font-medium' : 'text-muted-foreground'} rounded-2xl ${isFolder ? 'hover:bg-accent' : 'hover:bg-muted'}`, `${isFolder ? LX.makeIcon('FolderOpen', { svgClass: '' }).innerHTML : ''}${pi.id}`, row);
1055
1093
  if (isFolder) {
1056
1094
  rowItem.addEventListener('click', () => {
1057
- container.querySelectorAll('.move-item').forEach((el) => LX.removeClass(el, 'bg-quinary'));
1058
- LX.addClass(rowItem, 'bg-quinary');
1095
+ container.querySelectorAll('.move-item').forEach((el) => LX.removeClass(el, 'bg-primary text-primary-foreground'));
1096
+ LX.addClass(rowItem, 'bg-primary text-primary-foreground');
1059
1097
  targetFolder = pi;
1060
1098
  });
1061
1099
  const fPathButton = new LX.Button(null, 'FPathButton', () => {
1062
1100
  _openFolder(pi, container);
1063
- }, { icon: 'ChevronRight', className: 'ml-auto h-8', buttonClass: 'bg-none hover:bg-secondary' });
1101
+ }, { icon: 'ChevronRight', className: 'ml-auto h-8', buttonClass: 'ghost' });
1064
1102
  row.appendChild(fPathButton.root);
1065
1103
  }
1066
1104
  }
@@ -1094,33 +1132,29 @@ class AssetView {
1094
1132
  p.attach(area);
1095
1133
  const content = LX.makeContainer(['auto', '100%'], 'flex flex-auto-fill flex-col overflow-scroll py-2 gap-1', ``);
1096
1134
  {
1097
- const headerPanel = area.addPanel({ className: 'p-2 border-bottom flex flex-auto', height: 'auto' });
1135
+ const headerPanel = area.addPanel({ className: 'p-2 border-b-color flex flex-auto-keep', height: 'auto' });
1098
1136
  headerPanel.sameLine(2, 'w-full');
1099
1137
  headerPanel.addButton(null, 'BackButton', () => {
1100
1138
  if (targetFolder && targetFolder.parent)
1101
1139
  _openFolder(targetFolder.parent, content);
1102
- }, { icon: 'ArrowLeft', title: 'Back', tooltip: true, className: 'flex-auto',
1103
- buttonClass: 'bg-none hover:bg-secondary' });
1140
+ }, { icon: 'ArrowLeft', title: 'Back', tooltip: true, className: 'flex-auto-keep', buttonClass: 'ghost' });
1104
1141
  bcContainer = LX.makeElement('div');
1105
- headerPanel.addContent('ITEM_MOVE_PATH', bcContainer, { signal: '@item_move_path',
1106
- className: 'flex-auto-fill' });
1142
+ headerPanel.addContent('ITEM_MOVE_PATH', bcContainer, { signal: '@item_move_path', className: 'flex-auto-fill' });
1107
1143
  }
1108
1144
  area.attach(content);
1109
1145
  _openFolder(defaultFolder ?? this.data, content);
1110
1146
  {
1111
- const footerPanel = area.addPanel({ className: 'p-2 border-top flex flex-auto justify-between',
1112
- height: 'auto' });
1147
+ const footerPanel = area.addPanel({ className: 'p-2 border-t-color flex flex-auto-keep justify-between', height: 'auto' });
1113
1148
  footerPanel.addButton(null, 'NewFolderButton', () => {
1114
1149
  this._requestCreateFolder(targetFolder);
1115
- }, { width: 'auto', icon: 'FolderPlus', title: 'Create Folder', tooltip: true, className: 'ml-2',
1116
- buttonClass: 'bg-none hover:bg-secondary' });
1150
+ }, { width: 'auto', icon: 'FolderPlus', title: 'Create Folder', tooltip: true, className: 'ml-2', buttonClass: 'ghost' });
1117
1151
  footerPanel.sameLine(2, 'mr-2');
1118
1152
  footerPanel.addButton(null, 'Cancel', () => {
1119
1153
  this._moveItemDialog.close();
1120
- }, { buttonClass: 'bg-none fg-error' });
1154
+ }, { buttonClass: 'ghost text-destructive' });
1121
1155
  footerPanel.addButton(null, 'Move', () => {
1122
1156
  this._requestMoveItemToFolder(item, targetFolder);
1123
- }, { className: '', buttonClass: 'contrast' });
1157
+ }, { className: '', buttonClass: 'primary' });
1124
1158
  }
1125
1159
  }, { modal: true, size: ['616px', '500px'], closable: true, onBeforeClose: () => {
1126
1160
  delete this._moveItemDialog;
@@ -1218,12 +1252,12 @@ class AssetView {
1218
1252
  }
1219
1253
  return maxN === -1 ? originalName : `${base} (${maxN + 1})${ext}`;
1220
1254
  }
1221
- _requestRenameItem(item, newName) {
1255
+ _requestRenameItem(item, newName, treeEvent = false) {
1222
1256
  const onBeforeRename = this._callbacks['beforeRename'];
1223
1257
  const onRename = this._callbacks['rename'];
1224
1258
  const oldName = item.id;
1225
1259
  const resolve = (...args) => {
1226
- this._renameItem(item, newName);
1260
+ this._renameItem(item, newName, treeEvent ? item.dir : this.currentData);
1227
1261
  const event = {
1228
1262
  type: 'rename',
1229
1263
  items: [item],
@@ -1248,21 +1282,25 @@ class AssetView {
1248
1282
  resolve();
1249
1283
  }
1250
1284
  }
1251
- _renameItem(item, newName) {
1252
- const idx = this.currentData.indexOf(item);
1285
+ _renameItem(item, newName, data) {
1286
+ data = data ?? this.currentData;
1287
+ const idx = data.indexOf(item);
1253
1288
  if (idx < 0) {
1254
1289
  return;
1255
1290
  }
1256
- const wasSelected = LX.hasClass(item.domEl, 'selected');
1257
- const hoverTitle = this.content.querySelector(`#floatingTitle_${item.id.replace(/\s/g, '_').replaceAll('.', '_')}`);
1258
- if (hoverTitle)
1259
- hoverTitle.remove();
1260
- item.domEl?.remove();
1261
- item.id = newName;
1262
- item.domEl = this.addItem(item, idx * 2);
1263
- if (wasSelected) {
1264
- this._previewAsset(item);
1291
+ // It could be a Tree event, so maybe the elements is not created yet
1292
+ if (item.domEl) {
1293
+ const wasSelected = LX.hasClass(item.domEl, 'selected');
1294
+ const hoverTitle = this.content.querySelector(`#floatingTitle_${item.id.replace(/\s/g, '_').replaceAll('.', '_')}`);
1295
+ if (hoverTitle)
1296
+ hoverTitle.remove();
1297
+ item.domEl?.remove();
1298
+ item.domEl = this.addItem(item, idx * 2);
1299
+ if (wasSelected) {
1300
+ this._previewAsset(item);
1301
+ }
1265
1302
  }
1303
+ item.id = newName;
1266
1304
  this.tree?.refresh();
1267
1305
  this._processData(this.data);
1268
1306
  }
@@ -1284,7 +1322,7 @@ class AssetView {
1284
1322
  });
1285
1323
  panel.addButton(null, 'Save', () => {
1286
1324
  onRename(newName);
1287
- }, { buttonClass: 'contrast' });
1325
+ }, { buttonClass: 'primary' });
1288
1326
  const p = new LX.Popover(item.domEl, [panel], { align: 'center', side: 'bottom', sideOffset: -128 });
1289
1327
  }
1290
1328
  _requestCreateFolder(folder) {
@@ -1322,14 +1360,15 @@ class AssetView {
1322
1360
  if (!folder) {
1323
1361
  throw ('_createFolder: Something went wrong!');
1324
1362
  }
1363
+ const dir = folder.children ?? folder;
1325
1364
  const newFolder = {
1326
- id: this._getClonedName('New Folder', folder.children),
1365
+ id: this._getClonedName('New Folder', dir),
1327
1366
  type: 'folder',
1328
1367
  children: [],
1329
1368
  parent: this.currentFolder,
1330
1369
  metadata: {}
1331
1370
  };
1332
- folder.children.push(newFolder);
1371
+ dir.push(newFolder);
1333
1372
  this._refreshContent();
1334
1373
  this.tree?.refresh();
1335
1374
  if (this._moveItemDialog && this._movingItem) {