lexgui 8.2.3 → 8.2.5

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 (36) hide show
  1. package/build/components/BaseComponent.d.ts +75 -75
  2. package/build/components/Form.d.ts +14 -14
  3. package/build/components/NodeTree.d.ts +51 -51
  4. package/build/components/TextInput.d.ts +13 -13
  5. package/build/core/Namespace.js +1 -1
  6. package/build/core/Namespace.js.map +1 -1
  7. package/build/extensions/AssetView.d.ts +138 -137
  8. package/build/extensions/AssetView.js +57 -29
  9. package/build/extensions/AssetView.js.map +1 -1
  10. package/build/extensions/Audio.js +163 -163
  11. package/build/extensions/CodeEditor.d.ts +5 -0
  12. package/build/extensions/CodeEditor.js +5088 -5054
  13. package/build/extensions/CodeEditor.js.map +1 -1
  14. package/build/extensions/DocMaker.d.ts +1 -1
  15. package/build/extensions/DocMaker.js +14 -5
  16. package/build/extensions/DocMaker.js.map +1 -1
  17. package/build/lexgui.all.js +219 -101
  18. package/build/lexgui.all.js.map +1 -1
  19. package/build/lexgui.all.min.js +1 -1
  20. package/build/lexgui.all.module.js +219 -101
  21. package/build/lexgui.all.module.js.map +1 -1
  22. package/build/lexgui.all.module.min.js +1 -1
  23. package/build/lexgui.css +7466 -7475
  24. package/build/lexgui.js +83 -36
  25. package/build/lexgui.js.map +1 -1
  26. package/build/lexgui.min.css +1 -1
  27. package/build/lexgui.min.js +1 -1
  28. package/build/lexgui.module.js +83 -36
  29. package/build/lexgui.module.js.map +1 -1
  30. package/build/lexgui.module.min.js +1 -1
  31. package/changelog.md +28 -1
  32. package/demo.js +4 -1
  33. package/examples/asset-view.html +29 -2
  34. package/examples/code-editor.html +7 -1
  35. package/examples/editor.html +1 -1
  36. package/package.json +2 -1
@@ -12,7 +12,7 @@ const g$2 = globalThis;
12
12
  let LX = g$2.LX;
13
13
  if (!LX) {
14
14
  LX = {
15
- version: '8.2.3',
15
+ version: '8.2.5',
16
16
  ready: false,
17
17
  extensions: [], // Store extensions used
18
18
  extraCommandbarEntries: [], // User specific entries for command bar
@@ -1716,8 +1716,8 @@ class TextInput extends BaseComponent$1 {
1716
1716
  }
1717
1717
  wValue.style.textAlign = options.float ?? '';
1718
1718
  wValue.addEventListener('transitionstart', (e) => {
1719
- if (e.propertyName === 'background-color' &&
1720
- wValue.matches(':-webkit-autofill')) {
1719
+ if (e.propertyName === 'background-color'
1720
+ && wValue.matches(':-webkit-autofill')) {
1721
1721
  this.syncFromDOM();
1722
1722
  }
1723
1723
  });
@@ -2221,10 +2221,10 @@ class Checkbox extends BaseComponent$1 {
2221
2221
  const realNameWidth = this.root.domName?.style.width ?? '0px';
2222
2222
  container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
2223
2223
  };
2224
- var container = document.createElement('div');
2224
+ let container = document.createElement('div');
2225
2225
  container.className = 'flex items-center gap-2 my-0 mx-auto [&_span]:truncate [&_span]:flex-auto-fill';
2226
2226
  this.root.appendChild(container);
2227
- let checkbox = LX.makeElement('input', LX.mergeClass('lexcheckbox rounded-xl', options.className ?? 'primary'));
2227
+ let checkbox = LX.makeElement('input', LX.mergeClass('lexcheckbox rounded-xl disabled:pointer-events-none disabled:opacity-50', options.className ?? 'primary'));
2228
2228
  checkbox.type = 'checkbox';
2229
2229
  checkbox.checked = value;
2230
2230
  checkbox.disabled = this.disabled;
@@ -3037,8 +3037,8 @@ class Counter extends BaseComponent$1 {
3037
3037
  if (e.shiftKey)
3038
3038
  mult *= 10;
3039
3039
  this.set(this.count + mult, false, e);
3040
- }, { disabled: this.disabled, className: `p-0 ${this.disabled ? '' : 'hover:bg-secondary'} rounded-r-lg`,
3041
- buttonClass: 'px-0 bg-none h-7', icon: 'Plus' });
3040
+ }, { disabled: this.disabled, className: `p-0 ${this.disabled ? '' : 'hover:bg-secondary'} rounded-r-lg`, buttonClass: 'px-0 bg-none h-7',
3041
+ icon: 'Plus' });
3042
3042
  container.appendChild(addButton.root);
3043
3043
  }
3044
3044
  }
@@ -3797,7 +3797,8 @@ class DatePicker extends BaseComponent$1 {
3797
3797
  const calendarIcon = LX.makeIcon('Calendar');
3798
3798
  const calendarButton = new Button(null, d1, () => {
3799
3799
  this._popover = new Popover(calendarButton.root, [this.calendar]);
3800
- }, { disabled: this.disabled, buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3800
+ }, { disabled: this.disabled,
3801
+ buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3801
3802
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
3802
3803
  calendarButton.root.style.width = '100%';
3803
3804
  container.appendChild(calendarButton.root);
@@ -4299,6 +4300,8 @@ class Form extends BaseComponent$1 {
4299
4300
  }
4300
4301
  // This is basically the "submit" button
4301
4302
  this.primaryButton = new Button(null, options.primaryActionName ?? 'Submit', (value, event) => {
4303
+ // Force sync before testing text patterns
4304
+ this.syncInputs();
4302
4305
  const errors = [];
4303
4306
  for (let entry in data) {
4304
4307
  let entryData = data[entry];
@@ -4381,7 +4384,8 @@ class Layers extends BaseComponent$1 {
4381
4384
  }
4382
4385
  for (let bit = 0; bit < maxBits; ++bit) {
4383
4386
  let layer = document.createElement('button');
4384
- layer.className = `lexlayer size-6 text-secondary-foreground text-center content-center place-self-center cursor-pointer font-semibold text-xs rounded-lg select-none
4387
+ layer.className =
4388
+ `lexlayer size-6 text-secondary-foreground text-center content-center place-self-center cursor-pointer font-semibold text-xs rounded-lg select-none
4385
4389
  disabled:pointer-events-none disabled:opacity-50`;
4386
4390
  layer.disabled = this.disabled;
4387
4391
  if (val != undefined) {
@@ -4978,6 +4982,7 @@ class NodeTree {
4978
4982
  item.id = LX.getSupportedDOMName(node.id);
4979
4983
  item.tabIndex = '0';
4980
4984
  item.treeData = node;
4985
+ node.treeEl = item;
4981
4986
  // Select hierarchy icon
4982
4987
  let icon = (this.options.skipDefaultIcon ?? true) ? null : 'Dot'; // Default: no childs
4983
4988
  if (isParent) {
@@ -5460,21 +5465,45 @@ class NodeTree {
5460
5465
  el.focus();
5461
5466
  }
5462
5467
  }
5463
- select(id) {
5468
+ /* 'path' here helps to identity the correct item based on its parent path, for same 'id' issues */
5469
+ select(id, path) {
5464
5470
  const nodeFilter = this.domEl.querySelector('.lexnodetreefilter');
5465
5471
  if (nodeFilter) {
5466
5472
  nodeFilter.value = '';
5467
5473
  }
5468
5474
  this.refresh(null, id);
5469
5475
  this.domEl.querySelectorAll('.selected').forEach((i) => i.classList.remove('selected'));
5470
- // Unselect
5471
- if (!id) {
5472
- this.selected.length = 0;
5473
- return;
5476
+ if (id === undefined) {
5477
+ // if no id, try with the path
5478
+ if (path !== undefined) {
5479
+ id = path.at(-1);
5480
+ }
5481
+ else {
5482
+ // Unselect
5483
+ this.selected.length = 0;
5484
+ return;
5485
+ }
5486
+ }
5487
+ let el = null;
5488
+ if (path !== undefined) {
5489
+ let sourceData = this.data;
5490
+ for (const p of path) {
5491
+ const pItem = sourceData.children.find((item) => item.id === p);
5492
+ if (!pItem)
5493
+ break;
5494
+ sourceData = pItem;
5495
+ }
5496
+ el = sourceData.treeEl;
5497
+ console.assert(el, 'NodeTree: No domEl in item ' + id);
5498
+ }
5499
+ else if (id !== undefined) {
5500
+ // Element should exist, since tree was refreshed to show it
5501
+ el = this.domEl.querySelector('#' + LX.getSupportedDOMName(id));
5502
+ console.assert(el, "NodeTree: Can't select node " + id);
5503
+ }
5504
+ if (!el) {
5505
+ console.assert(el, "NodeTree: Can't select node " + id);
5474
5506
  }
5475
- // Element should exist, since tree was refreshed to show it
5476
- const el = this.domEl.querySelector('#' + LX.getSupportedDOMName(id));
5477
- console.assert(el, "NodeTree: Can't select node " + id);
5478
5507
  el.classList.add('selected');
5479
5508
  this.selected = [el.treeData];
5480
5509
  el.focus();
@@ -7276,7 +7305,8 @@ class Tags extends BaseComponent$1 {
7276
7305
  tagsContainer.innerHTML = '';
7277
7306
  for (let i = 0; i < value.length; ++i) {
7278
7307
  const tagName = value[i];
7279
- const tag = LX.makeElement('span', 'lextag bg-primary px-2 py-1 rounded-xl min-w-2 justify-center text-primary-foreground gap-1 text-sm select-none', tagName);
7308
+ const tagClass = LX.mergeClass('lextag bg-primary px-2 py-1 rounded-xl min-w-2 justify-center text-primary-foreground gap-1 text-sm select-none', options.tagClass);
7309
+ const tag = LX.makeElement('span', tagClass, tagName);
7280
7310
  if (!this.disabled) {
7281
7311
  const removeButton = LX.makeIcon('X', { svgClass: 'sm' });
7282
7312
  tag.appendChild(removeButton);
@@ -7339,7 +7369,7 @@ class TextArea extends BaseComponent$1 {
7339
7369
  container.className = 'lextextarea';
7340
7370
  container.style.display = 'flex';
7341
7371
  this.root.appendChild(container);
7342
- let wValue = LX.makeElement('textarea', options.inputClass ?? '');
7372
+ let wValue = LX.makeElement('textarea', LX.mergeClass('w-full text-sm text-foreground bg-card border-color disabled:pointer-events-none disabled:opacity-50 rounded-lg outline-none pad-md', options.inputClass ?? ''));
7343
7373
  wValue.value = value ?? '';
7344
7374
  wValue.style.textAlign = options.float ?? '';
7345
7375
  wValue.disabled = this.disabled;
@@ -7355,9 +7385,18 @@ class TextArea extends BaseComponent$1 {
7355
7385
  wValue.setAttribute('placeholder', options.placeholder);
7356
7386
  }
7357
7387
  const trigger = options.trigger ?? 'default';
7388
+ const submitOnEnterKey = options.submitOnEnterKey ?? true;
7358
7389
  if (trigger == 'default') {
7390
+ wValue.addEventListener('keydown', function (e) {
7391
+ if (submitOnEnterKey && e.key == 'Enter' && !e.shiftKey) {
7392
+ e.preventDefault();
7393
+ return false;
7394
+ }
7395
+ });
7359
7396
  wValue.addEventListener('keyup', function (e) {
7360
- if (e.key == 'Enter') {
7397
+ if ((submitOnEnterKey && e.key == 'Enter' && !e.shiftKey)
7398
+ || e.key == 'Escape') {
7399
+ e.preventDefault();
7361
7400
  wValue.blur();
7362
7401
  }
7363
7402
  });
@@ -7446,7 +7485,7 @@ class Toggle extends BaseComponent$1 {
7446
7485
  var container = document.createElement('div');
7447
7486
  container.className = 'flex flex-row gap-2 items-center';
7448
7487
  this.root.appendChild(container);
7449
- let toggle = LX.makeElement('input', LX.mergeClass('lextoggle relative inline-grid place-content-center cursor-pointer shrink-0 select-none', options.className));
7488
+ let toggle = LX.makeElement('input', LX.mergeClass('lextoggle relative inline-grid place-content-center cursor-pointer shrink-0 select-none disabled:pointer-events-none disabled:opacity-50', options.className));
7450
7489
  toggle.type = 'checkbox';
7451
7490
  toggle.checked = value;
7452
7491
  toggle.iValue = value;
@@ -10841,29 +10880,37 @@ function prompt(text, title, callback, options = {}) {
10841
10880
  options.modal = true;
10842
10881
  options.className = 'prompt';
10843
10882
  let value = '';
10883
+ const _submitFn = () => {
10884
+ if (options.required && value === '') {
10885
+ text += text.includes('You must fill the input text.') ? '' : '\nYou must fill the input text.';
10886
+ dialog.close();
10887
+ prompt(text, title, callback, options);
10888
+ }
10889
+ else {
10890
+ if (callback)
10891
+ callback.call(LX, value);
10892
+ dialog.close();
10893
+ }
10894
+ };
10844
10895
  const dialog = new LX.Dialog(title, (p) => {
10845
- p.addTextArea(null, text, null, { disabled: true, fitHeight: true });
10896
+ LX.makeElement('p', 'max-h-64 p-2 break-word overflow-scroll', text, p);
10846
10897
  if (options.input ?? true) {
10847
- p.addText(null, options.input || value, (v) => value = v, { placeholder: '...' });
10898
+ p.addText(null, options.input || value, (v, e) => {
10899
+ value = v;
10900
+ if (e?.constructor === KeyboardEvent) {
10901
+ _submitFn();
10902
+ }
10903
+ }, { placeholder: '...' });
10848
10904
  }
10849
10905
  p.sameLine(2);
10850
10906
  p.addButton(null, 'Cancel', () => {
10851
10907
  if (options.on_cancel)
10852
10908
  options.on_cancel();
10853
10909
  dialog.close();
10854
- });
10910
+ }, { width: '50%', buttonClass: 'destructive' });
10855
10911
  p.addButton(null, options.accept || 'Continue', () => {
10856
- if (options.required && value === '') {
10857
- text += text.includes('You must fill the input text.') ? '' : '\nYou must fill the input text.';
10858
- dialog.close();
10859
- prompt(text, title, callback, options);
10860
- }
10861
- else {
10862
- if (callback)
10863
- callback.call(LX, value);
10864
- dialog.close();
10865
- }
10866
- }, { buttonClass: 'primary' });
10912
+ _submitFn();
10913
+ }, { width: '50%', buttonClass: 'primary' });
10867
10914
  }, options);
10868
10915
  // Focus text prompt
10869
10916
  if (options.input ?? true) {
@@ -11705,7 +11752,7 @@ class AlertDialog extends Dialog$1 {
11705
11752
  options.modal = true;
11706
11753
  super(undefined, (p) => {
11707
11754
  p.root.className = LX.mergeClass(p.root.className, 'pad-2xl flex flex-col gap-2');
11708
- LX.makeContainer(['100%', '100%'], 'text-lg font-medium text-foreground', title, p);
11755
+ LX.makeContainer(['100%', '100%'], 'text-lg font-medium text-foreground px-2', title, p);
11709
11756
  p.addTextArea(null, message, null, { disabled: true, fitHeight: true, inputClass: 'bg-none text-sm text-muted-foreground' });
11710
11757
  p.sameLine(2, 'justify-end');
11711
11758
  p.addButton(null, options.cancelText ?? 'Cancel', () => this.destroy(), {
@@ -14015,7 +14062,7 @@ class AssetView {
14015
14062
  rootItem;
14016
14063
  path = [];
14017
14064
  rootPath = '';
14018
- selectedItem = undefined;
14065
+ selectedItems = [];
14019
14066
  allowedTypes;
14020
14067
  searchValue = '';
14021
14068
  filter = 'None';
@@ -14027,7 +14074,8 @@ class AssetView {
14027
14074
  skipPreview = false;
14028
14075
  useNativeTitle = false;
14029
14076
  onlyFolders = true;
14030
- allowMultipleSelection = false;
14077
+ allowMultipleSelection = true;
14078
+ allowItemCheck = false;
14031
14079
  previewActions = [];
14032
14080
  contextMenu = [];
14033
14081
  itemContextMenuOptions = null;
@@ -14067,6 +14115,7 @@ class AssetView {
14067
14115
  this.useNativeTitle = options.useNativeTitle ?? this.useNativeTitle;
14068
14116
  this.onlyFolders = options.onlyFolders ?? this.onlyFolders;
14069
14117
  this.allowMultipleSelection = options.allowMultipleSelection ?? this.allowMultipleSelection;
14118
+ this.allowItemCheck = options.allowItemCheck ?? this.allowItemCheck;
14070
14119
  this.previewActions = options.previewActions ?? [];
14071
14120
  this.itemContextMenuOptions = options.itemContextMenuOptions;
14072
14121
  this.gridScale = options.gridScale ?? this.gridScale;
@@ -14163,9 +14212,9 @@ class AssetView {
14163
14212
  if (!this.useNativeTitle) {
14164
14213
  let desc = document.createElement('span');
14165
14214
  desc.className = 'lexitemdesc';
14166
- desc.id = `floatingTitle_${metadata.uid}`;
14215
+ desc.id = LX.getSupportedDOMName(`floatingTitle_${metadata.uid}`);
14167
14216
  desc.innerHTML = `File: ${item.id}<br>Type: ${type}`;
14168
- LX.insertChildAtIndex(this.content, desc, childIndex ? childIndex + 1 : undefined);
14217
+ LX.insertChildAtIndex(this.content, desc, childIndex !== undefined ? childIndex + 1 : undefined);
14169
14218
  itemEl.addEventListener('mousemove', (e) => {
14170
14219
  if (!isGridLayout) {
14171
14220
  return;
@@ -14191,7 +14240,7 @@ class AssetView {
14191
14240
  else {
14192
14241
  itemEl.title = type + ': ' + item.id;
14193
14242
  }
14194
- if (this.allowMultipleSelection) {
14243
+ if (this.allowItemCheck) {
14195
14244
  let checkbox = document.createElement('input');
14196
14245
  checkbox.type = 'checkbox';
14197
14246
  checkbox.className = 'lexcheckbox';
@@ -14280,11 +14329,12 @@ class AssetView {
14280
14329
  e.stopPropagation();
14281
14330
  const isDoubleClick = e.detail == LX.MOUSE_DOUBLE_CLICK;
14282
14331
  if (!isDoubleClick) {
14283
- if (!e.shiftKey) {
14332
+ if (!e.shiftKey || !that.allowMultipleSelection) {
14284
14333
  that.content.querySelectorAll('.lexassetitem').forEach((i) => i.classList.remove('selected'));
14334
+ that.selectedItems.length = 0;
14285
14335
  }
14286
14336
  this.classList.add('selected');
14287
- that.selectedItem = item;
14337
+ that.selectedItems.push(item);
14288
14338
  if (!that.skipPreview) {
14289
14339
  that._previewAsset(item);
14290
14340
  }
@@ -14316,36 +14366,44 @@ class AssetView {
14316
14366
  e.preventDefault();
14317
14367
  e.stopImmediatePropagation();
14318
14368
  e.stopPropagation();
14319
- const multiple = that.content.querySelectorAll('.selected').length;
14369
+ const multipleSelection = that.selectedItems.length > 1;
14320
14370
  const options = [
14321
14371
  {
14322
- name: (multiple > 1) ? (multiple + ' selected') : item.id,
14372
+ name: multipleSelection ? (`${that.selectedItems.length} selected`) : item.id,
14323
14373
  icon: LX.makeIcon('CircleSmall', { svgClass: `fill-current text-${typeColor}` }),
14324
14374
  className: 'text-sm',
14325
14375
  disabled: true
14326
14376
  },
14327
14377
  null
14328
14378
  ];
14329
- if (multiple <= 1) {
14379
+ // By now, allow with none/single selected items
14380
+ if (!multipleSelection) {
14330
14381
  options.push({ name: 'Rename', icon: 'TextCursor', callback: that._renameItemPopover.bind(that, item) });
14331
14382
  }
14332
- if (!isFolder) {
14383
+ // By now, allow with none/single selected items
14384
+ if (!isFolder && !multipleSelection) {
14333
14385
  options.push({ name: 'Clone', icon: 'Copy', callback: that._requestCloneItem.bind(that, item) });
14334
14386
  }
14335
- options.push({ name: 'Move', icon: 'FolderInput', callback: () => that._moveItem(item) });
14336
- if (type == 'Script' && LX.has('CodeEditor')) {
14387
+ // By now, allow with none/single selected items
14388
+ if (!multipleSelection) {
14389
+ options.push({ name: 'Move', icon: 'FolderInput', callback: () => that._moveItem(item) });
14390
+ }
14391
+ // By now, allow with none/single selected items
14392
+ if (!multipleSelection && type == 'Script' && LX.has('CodeEditor')) {
14337
14393
  options.push({ name: 'Open in Editor', icon: 'Code', callback: that._openScriptInEditor.bind(that, item) });
14338
14394
  }
14339
14395
  if (that.itemContextMenuOptions) {
14340
- options.push(null);
14396
+ if (options.length > 2)
14397
+ options.push(null);
14341
14398
  for (let o of that.itemContextMenuOptions) {
14342
14399
  if (!o.name || !o.callback)
14343
14400
  continue;
14344
- options.push({ name: o.name, icon: o.icon, callback: o.callback?.bind(that, item) });
14401
+ options.push({ name: o.name, icon: o.icon,
14402
+ callback: o.callback?.bind(that, multipleSelection ? that.selectedItems : [item]) });
14345
14403
  }
14346
14404
  }
14347
14405
  options.push(null, { name: 'Delete', icon: 'Trash2', className: 'destructive',
14348
- callback: that._requestDeleteItem.bind(that, item) });
14406
+ callback: that._requestDeleteItem.bind(that, multipleSelection ? that.selectedItems : [item]) });
14349
14407
  LX.addClass(that.contentPanel.root, 'pointer-events-none');
14350
14408
  LX.addDropdownMenu(e.target, options, { side: 'right', align: 'start', event: e, onBlur: () => {
14351
14409
  LX.removeClass(that.contentPanel.root, 'pointer-events-none');
@@ -14376,7 +14434,8 @@ class AssetView {
14376
14434
  e.dataTransfer.setDragImage(img, 0, 0);
14377
14435
  e.dataTransfer.effectAllowed = 'move';
14378
14436
  }
14379
- const desc = that.content.querySelector(`#floatingTitle_${metadata.uid}`);
14437
+ const domName = LX.getSupportedDOMName(`floatingTitle_${metadata.uid}`);
14438
+ const desc = that.content.querySelector(`#${domName}`);
14380
14439
  if (desc)
14381
14440
  desc.style.display = 'none';
14382
14441
  }, false);
@@ -14411,7 +14470,8 @@ class AssetView {
14411
14470
  });
14412
14471
  itemEl.addEventListener('mouseenter', (e) => {
14413
14472
  if (!that.useNativeTitle && isGridLayout) {
14414
- const desc = that.content.querySelector(`#floatingTitle_${metadata.uid}`);
14473
+ const domName = LX.getSupportedDOMName(`floatingTitle_${metadata.uid}`);
14474
+ const desc = that.content.querySelector(`#${domName}`);
14415
14475
  if (desc)
14416
14476
  desc.style.display = 'unset';
14417
14477
  }
@@ -14425,7 +14485,8 @@ class AssetView {
14425
14485
  itemEl.addEventListener('mouseleave', (e) => {
14426
14486
  if (!that.useNativeTitle && isGridLayout) {
14427
14487
  setTimeout(() => {
14428
- const desc = that.content.querySelector(`#floatingTitle_${metadata.uid}`);
14488
+ const domName = LX.getSupportedDOMName(`floatingTitle_${metadata.uid}`);
14489
+ const desc = that.content.querySelector(`#${domName}`);
14429
14490
  if (desc)
14430
14491
  desc.style.display = 'none';
14431
14492
  }, 100);
@@ -14554,7 +14615,7 @@ class AssetView {
14554
14615
  const dom = node.domEl;
14555
14616
  dom?.classList.add('selected');
14556
14617
  }
14557
- this.selectedItem = node;
14618
+ this.selectedItems = [node];
14558
14619
  }
14559
14620
  });
14560
14621
  tree.on('beforeMove', (event, resolve) => {
@@ -14705,6 +14766,7 @@ class AssetView {
14705
14766
  });
14706
14767
  this.content.addEventListener('click', function () {
14707
14768
  this.querySelectorAll('.lexassetitem').forEach((i) => i.classList.remove('selected'));
14769
+ that.selectedItems.length = 0;
14708
14770
  });
14709
14771
  this.content.addEventListener('contextmenu', function (e) {
14710
14772
  e.preventDefault();
@@ -14923,7 +14985,7 @@ class AssetView {
14923
14985
  return;
14924
14986
  }
14925
14987
  const child = this.currentData[0];
14926
- const sameFolder = child?.parent?.id === folderItem.id;
14988
+ const sameFolder = child?.parent?.metadata?.uid === folderItem.metadata?.uid;
14927
14989
  if (storeCurrent) {
14928
14990
  this.prevData.push(this.currentFolder ?? {
14929
14991
  id: '/',
@@ -14949,7 +15011,15 @@ class AssetView {
14949
15011
  if (mustRefresh) {
14950
15012
  this._processData(this.data);
14951
15013
  this._refreshContent();
14952
- this.tree?.select(this.currentFolder.id);
15014
+ // Get path to avoid same id issues
15015
+ let path = `${this.currentFolder.id}/`;
15016
+ let parent = this.currentFolder.parent;
15017
+ while (parent && parent.id !== '/') {
15018
+ path += `${parent.id}/`;
15019
+ parent = parent.parent;
15020
+ }
15021
+ const parentsPath = path.split('/').filter(Boolean).reverse();
15022
+ this.tree?.select(undefined, parentsPath);
14953
15023
  }
14954
15024
  this._updatePath();
14955
15025
  }
@@ -14974,14 +15044,14 @@ class AssetView {
14974
15044
  }
14975
15045
  return true;
14976
15046
  }
14977
- _requestDeleteItem(item) {
15047
+ _requestDeleteItem(items) {
14978
15048
  const onBeforeDelete = this._callbacks['beforeDelete'];
14979
15049
  const onDelete = this._callbacks['delete'];
14980
15050
  const resolve = (...args) => {
14981
- this._deleteItem(item);
15051
+ items.forEach((item) => this._deleteItem(item));
14982
15052
  const event = {
14983
15053
  type: 'delete',
14984
- items: [item],
15054
+ items,
14985
15055
  userInitiated: true
14986
15056
  };
14987
15057
  if (onDelete)
@@ -14990,7 +15060,7 @@ class AssetView {
14990
15060
  if (onBeforeDelete) {
14991
15061
  const event = {
14992
15062
  type: 'delete',
14993
- items: [item],
15063
+ items,
14994
15064
  userInitiated: true
14995
15065
  };
14996
15066
  onBeforeDelete(event, resolve);
@@ -15099,7 +15169,7 @@ class AssetView {
15099
15169
  }
15100
15170
  bcContainer.innerHTML = '';
15101
15171
  bcContainer.appendChild(LX.makeBreadcrumb(path.reverse().map((p) => {
15102
- return { title: p };
15172
+ return { name: p };
15103
15173
  }), {
15104
15174
  maxItems: 4,
15105
15175
  separatorIcon: 'ChevronRight'
@@ -15269,16 +15339,21 @@ class AssetView {
15269
15339
  // It could be a Tree event, so maybe the elements is not created yet
15270
15340
  if (item.domEl) {
15271
15341
  const wasSelected = LX.hasClass(item.domEl, 'selected');
15272
- const hoverTitle = this.content.querySelector(`#floatingTitle_${item.id.replace(/\s/g, '_').replaceAll('.', '_')}`);
15342
+ const hoverTitleDomName = LX.getSupportedDOMName(`floatingTitle_${item.metadata.uid}`);
15343
+ const hoverTitle = this.content.querySelector(`#${hoverTitleDomName}`);
15273
15344
  if (hoverTitle)
15274
15345
  hoverTitle.remove();
15275
15346
  item.domEl?.remove();
15347
+ // Update new name
15348
+ item.id = newName;
15276
15349
  item.domEl = this.addItem(item, idx * 2);
15277
15350
  if (wasSelected) {
15278
15351
  this._previewAsset(item);
15279
15352
  }
15280
15353
  }
15281
- item.id = newName;
15354
+ else {
15355
+ item.id = newName;
15356
+ }
15282
15357
  this.tree?.refresh();
15283
15358
  this._processData(this.data);
15284
15359
  }
@@ -15557,7 +15632,7 @@ function swapArrayElements(array, id0, id1) {
15557
15632
  [array[id0], array[id1]] = [array[id1], array[id0]];
15558
15633
  }
15559
15634
  function sliceChars(str, idx, n = 1) {
15560
- return str.substr(0, idx) + str.substr(idx + n);
15635
+ return str.substring(0, idx) + str.substring(idx + n);
15561
15636
  }
15562
15637
  function firstNonspaceIndex(str) {
15563
15638
  const index = str.search(/\S|$/);
@@ -15802,7 +15877,7 @@ const HighlightRules = {
15802
15877
  common: [
15803
15878
  { test: (ctx) => ctx.inBlockComment, className: 'cm-com' },
15804
15879
  { test: (ctx) => ctx.inString, action: (ctx, editor) => editor._appendStringToken(ctx.token), discard: true },
15805
- { test: (ctx) => ctx.token.substr(0, ctx.singleLineCommentToken.length) == ctx.singleLineCommentToken, className: 'cm-com' },
15880
+ { test: (ctx) => ctx.token.substring(0, ctx.singleLineCommentToken.length) == ctx.singleLineCommentToken, className: 'cm-com' },
15806
15881
  { test: (ctx, editor) => editor._isKeyword(ctx), className: 'cm-kwd' },
15807
15882
  {
15808
15883
  test: (ctx, editor) => editor._mustHightlightWord(ctx.token, CE.builtIn, ctx.lang) && (ctx.lang.tags ?? false
@@ -16568,8 +16643,8 @@ class CodeEditor {
16568
16643
  var _c0 = this.getCharAtPos(cursor, -1);
16569
16644
  var _c1 = this.getCharAtPos(cursor);
16570
16645
  this.code.lines.splice(cursor.line + 1, 0, '');
16571
- this.code.lines[cursor.line + 1] = this.code.lines[ln].substr(cursor.position); // new line (below)
16572
- this.code.lines[ln] = this.code.lines[ln].substr(0, cursor.position); // line above
16646
+ this.code.lines[cursor.line + 1] = this.code.lines[ln].substring(cursor.position); // new line (below)
16647
+ this.code.lines[ln] = this.code.lines[ln].substring(0, cursor.position); // line above
16573
16648
  this.lineDown(cursor, true);
16574
16649
  // Check indentation
16575
16650
  var spaces = firstNonspaceIndex(this.code.lines[ln]);
@@ -16661,7 +16736,7 @@ class CodeEditor {
16661
16736
  e.keepSelection = kS;
16662
16737
  }
16663
16738
  var diff = Math.max(cursor.position - from, 1);
16664
- var substr = word.substr(0, diff);
16739
+ var substr = word.substring(0, diff);
16665
16740
  // Selections...
16666
16741
  if (e.shiftKey) {
16667
16742
  if (!cursor.selection) {
@@ -16731,7 +16806,7 @@ class CodeEditor {
16731
16806
  if (!word.length)
16732
16807
  this.lineDown(cursor, true);
16733
16808
  var diff = cursor.position - from;
16734
- var substr = word.substr(diff);
16809
+ var substr = word.substring(diff);
16735
16810
  // Selections...
16736
16811
  if (e.shiftKey) {
16737
16812
  if (!cursor.selection) {
@@ -17115,6 +17190,7 @@ class CodeEditor {
17115
17190
  this._addRedoStep(cursor);
17116
17191
  // Extract info from the last code state
17117
17192
  const step = this.code.undoSteps.pop();
17193
+ debugger;
17118
17194
  // Set old state lines
17119
17195
  this.code.lines = step.lines;
17120
17196
  this.processLines();
@@ -17730,13 +17806,13 @@ class CodeEditor {
17730
17806
  index += i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length;
17731
17807
  }
17732
17808
  index += cursor.selection.fromY * separator.length;
17733
- const num_chars = cursor.selection.chars
17809
+ const numChars = cursor.selection.chars
17734
17810
  + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
17735
- const text = code.substr(index, num_chars);
17811
+ const text = code.substring(index, index + numChars);
17736
17812
  content = text.split(separator).join('\n');
17737
17813
  }
17738
17814
  const options = this.onContextMenu(this, content, e);
17739
- if (options.length) {
17815
+ if (options?.length) {
17740
17816
  m.add('');
17741
17817
  for (const o of options) {
17742
17818
  m.add(o.path, { disabled: o.disabled, callback: o.callback });
@@ -17877,7 +17953,7 @@ class CodeEditor {
17877
17953
  : this.code.lines[i].substring(toX, fromX);
17878
17954
  }
17879
17955
  else
17880
- string = this.code.lines[i].substr(fromX);
17956
+ string = this.code.lines[i].substring(fromX);
17881
17957
  const pixels = (reverse && deltaY == 0 ? toX : fromX) * this.charWidth;
17882
17958
  if (isVisible)
17883
17959
  domEl.style.left = `calc(${pixels}px + ${this.xPadding})`;
@@ -17917,7 +17993,7 @@ class CodeEditor {
17917
17993
  // Compute new width and selection margins
17918
17994
  let string;
17919
17995
  if (sId == 0) {
17920
- string = this.code.lines[i].substr(toX);
17996
+ string = this.code.lines[i].substring(toX);
17921
17997
  const pixels = toX * this.charWidth;
17922
17998
  if (isVisible)
17923
17999
  domEl.style.left = 'calc(' + pixels + 'px + ' + this.xPadding + ')';
@@ -18244,9 +18320,9 @@ class CodeEditor {
18244
18320
  index += i == cursor.selection.fromY ? cursor.selection.fromX : this.code.lines[i].length;
18245
18321
  }
18246
18322
  index += cursor.selection.fromY * separator.length;
18247
- const num_chars = cursor.selection.chars
18323
+ const numChars = cursor.selection.chars
18248
18324
  + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
18249
- const text = code.substr(index, num_chars);
18325
+ const text = code.substring(index, index + numChars);
18250
18326
  const lines = text.split(separator);
18251
18327
  textToCopy = lines.join('\n');
18252
18328
  }
@@ -18280,7 +18356,7 @@ class CodeEditor {
18280
18356
  index += cursor.selection.fromY * separator.length;
18281
18357
  const numChars = cursor.selection.chars
18282
18358
  + (cursor.selection.toY - cursor.selection.fromY) * separator.length;
18283
- const text = code.substr(index, numChars);
18359
+ const text = code.substring(index, index + numChars);
18284
18360
  const lines = text.split(separator);
18285
18361
  textToCut = lines.join('\n');
18286
18362
  this.deleteSelection(cursor);
@@ -18540,7 +18616,7 @@ class CodeEditor {
18540
18616
  const tokenIndex = i;
18541
18617
  const tokenStartIndex = this._currentTokenPositions[tokenIndex];
18542
18618
  if (blockComments) {
18543
- if (token.substr(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]) {
18619
+ if (token.substring(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]) {
18544
18620
  this._buildingBlockComment = [lineNumber, tokenStartIndex];
18545
18621
  }
18546
18622
  }
@@ -18561,7 +18637,7 @@ class CodeEditor {
18561
18637
  tokens: tokensToEvaluate
18562
18638
  });
18563
18639
  if (blockComments && this._buildingBlockComment != undefined
18564
- && token.substr(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]) {
18640
+ && token.substring(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]) {
18565
18641
  const [commentLineNumber, tokenPos] = this._buildingBlockComment;
18566
18642
  this._blockCommentCache.push([new LX.vec2(commentLineNumber, lineNumber), new LX.vec2(tokenPos, tokenStartIndex)]);
18567
18643
  delete this._buildingBlockComment;
@@ -18584,10 +18660,10 @@ class CodeEditor {
18584
18660
  const openIdx = kLineString.lastIndexOf('{');
18585
18661
  const closeIdx = kLineString.lastIndexOf('}');
18586
18662
  if (openIdx > -1) {
18587
- kLineString = kLineString.substr(openIdx);
18663
+ kLineString = kLineString.substring(openIdx);
18588
18664
  }
18589
18665
  else if (closeIdx > -1) {
18590
- kLineString = kLineString.substr(closeIdx);
18666
+ kLineString = kLineString.substring(closeIdx);
18591
18667
  }
18592
18668
  contextTokens = [...this._getTokensFromLine(kLineString), ...contextTokens];
18593
18669
  if (kLineString.length !== this.code.lines[lineNumber - k]) {
@@ -18650,7 +18726,7 @@ class CodeEditor {
18650
18726
  until reaching new delimiters
18651
18727
  */
18652
18728
  if (lineOpensBlock) {
18653
- const r = tokens.filter((t) => t.substr(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]);
18729
+ const r = tokens.filter((t) => t.substring(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]);
18654
18730
  if (!r.length) {
18655
18731
  this._buildingBlockComment = [lineNumber - 1, 0];
18656
18732
  this.mustProcessPreviousLine = (tokens) => {
@@ -18672,7 +18748,7 @@ class CodeEditor {
18672
18748
  }
18673
18749
  }
18674
18750
  else if (lineClosesBlock) {
18675
- const r = tokens.filter((t) => t.substr(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]);
18751
+ const r = tokens.filter((t) => t.substring(0, blockCommentsTokens[1].length) == blockCommentsTokens[1]);
18676
18752
  if (!r.length) {
18677
18753
  this._buildingBlockComment = [section[0].x, section[1].x];
18678
18754
  this.mustProcessNextLine = (tokens) => {
@@ -18949,18 +19025,19 @@ class CodeEditor {
18949
19025
  lineString = ogLine.substring(0, hasCommentIdx);
18950
19026
  }
18951
19027
  let tokensToEvaluate = []; // store in a temp array so we know prev and next tokens...
18952
- let charCounterList = [];
18953
19028
  let charCounter = 0;
18954
19029
  const pushToken = function (t) {
18955
19030
  if ((skipNonWords && (t.includes('"') || t.length < 3))) {
18956
19031
  return;
18957
19032
  }
18958
- tokensToEvaluate.push(t);
18959
- charCounterList.push(charCounter);
19033
+ tokensToEvaluate.push({
19034
+ text: t,
19035
+ pos: charCounter
19036
+ });
18960
19037
  // Update positions
18961
19038
  charCounter += t.length;
18962
19039
  };
18963
- let iter = lineString.matchAll(/(<!--|-->|\*\/|\/\*|::|[\[\](){}<>.,;:*"'`%@$!/= ])/g);
19040
+ let iter = lineString.matchAll(/(<!--|-->|\*\/|\/\*|::|[\[\](){}<>.,;:*"'`%@$!/=+\- ])/g);
18964
19041
  let subtokens = iter.next();
18965
19042
  if (subtokens.value) {
18966
19043
  let idx = 0;
@@ -18983,8 +19060,40 @@ class CodeEditor {
18983
19060
  if (hasCommentIdx != undefined) {
18984
19061
  pushToken(ogLine.substring(hasCommentIdx));
18985
19062
  }
18986
- this._currentTokenPositions = charCounterList;
18987
- return this._processTokens(tokensToEvaluate);
19063
+ // Apply step to merge numeric tokens, since they might be separated by '.'
19064
+ const mergedTokens = this._mergeNumericTokens(tokensToEvaluate);
19065
+ this._currentTokenPositions = mergedTokens.map((t) => t.pos);
19066
+ return this._processTokens(mergedTokens.map((t) => t.text));
19067
+ }
19068
+ _mergeNumericTokens(tokens) {
19069
+ const result = [];
19070
+ for (let i = 0; i < tokens.length; i++) {
19071
+ const t = tokens[i];
19072
+ const prev = result[result.length - 1];
19073
+ const next = tokens[i + 1];
19074
+ // number . number
19075
+ if (prev && t.text === '.' && /^\d+$/.test(prev.text) && next && /^\d+$/.test(next.text)) {
19076
+ prev.text += '.' + next.text;
19077
+ i++;
19078
+ continue;
19079
+ }
19080
+ // . number
19081
+ if (t.text === '.' && next && /^\d+$/.test(next.text)) {
19082
+ result.push({
19083
+ text: '.' + next.text,
19084
+ pos: t.pos
19085
+ });
19086
+ i++;
19087
+ continue;
19088
+ }
19089
+ // number .
19090
+ if (prev && t.text === '.' && /^\d+$/.test(prev.text)) {
19091
+ prev.text += '.';
19092
+ continue;
19093
+ }
19094
+ result.push({ ...t });
19095
+ }
19096
+ return result;
18988
19097
  }
18989
19098
  _processTokens(tokens, offset = 0) {
18990
19099
  if (this.highlight == 'C++' || this.highlight == 'CSS') {
@@ -19414,9 +19523,9 @@ class CodeEditor {
19414
19523
  index += i == selection.fromY ? selection.fromX : this.code.lines[i].length;
19415
19524
  }
19416
19525
  index += selection.fromY * separator.length;
19417
- const num_chars = selection.chars + (selection.toY - selection.fromY) * separator.length;
19526
+ const numChars = selection.chars + (selection.toY - selection.fromY) * separator.length;
19418
19527
  const pre = code.slice(0, index);
19419
- const post = code.slice(index + num_chars);
19528
+ const post = code.slice(index + numChars);
19420
19529
  this.code.lines = (pre + post).split(separator);
19421
19530
  this.cursorToLine(cursor, selection.fromY, true);
19422
19531
  this.cursorToPosition(cursor, selection.fromX);
@@ -20062,7 +20171,7 @@ class CodeEditor {
20062
20171
  preWord.innerHTML = currSuggestion.substring(0, index);
20063
20172
  pre.appendChild(preWord);
20064
20173
  var actualWord = document.createElement('span');
20065
- actualWord.innerHTML = currSuggestion.substr(index, word.length);
20174
+ actualWord.innerHTML = currSuggestion.substring(index, index + word.length);
20066
20175
  actualWord.classList.add('word-highlight');
20067
20176
  pre.appendChild(actualWord);
20068
20177
  var postWord = document.createElement('span');
@@ -20203,13 +20312,13 @@ class CodeEditor {
20203
20312
  const getIndex = (l) => {
20204
20313
  var string = this.code.lines[l];
20205
20314
  if (reverse) {
20206
- string = string.substr(0, l == cursorData.y ? cursorData.x : string.length);
20315
+ string = string.substring(0, l == cursorData.y ? cursorData.x : string.length);
20207
20316
  var reversed = strReverse(string);
20208
20317
  var reversedIdx = reversed.indexOf(strReverse(text));
20209
20318
  return reversedIdx == -1 ? -1 : string.length - reversedIdx - text.length;
20210
20319
  }
20211
20320
  else {
20212
- return string.substr(l == cursorData.y ? cursorData.x : 0).indexOf(text);
20321
+ return string.substring(l == cursorData.y ? cursorData.x : 0).indexOf(text);
20213
20322
  }
20214
20323
  };
20215
20324
  if (reverse) {
@@ -20592,11 +20701,17 @@ if (!LX) {
20592
20701
  throw ('Missing LX namespace!');
20593
20702
  }
20594
20703
  LX.extensions.push('DocMaker');
20704
+ const CLASS_WORDS = ['uint32_t', 'uint64_t', 'uint8_t'];
20595
20705
  const CPP_KEY_WORDS = ['int', 'float', 'double', 'bool', 'char', 'wchar_t', 'const', 'static_cast', 'dynamic_cast', 'new', 'delete', 'void', 'true',
20596
20706
  'false', 'auto', 'struct', 'typedef', 'nullptr', 'NULL', 'unsigned', 'namespace', 'auto'];
20597
- const CLASS_WORDS = ['uint32_t', 'uint64_t', 'uint8_t'];
20598
- const STATEMENT_WORDS = ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'import', 'from', 'await'];
20599
20707
  const JS_KEY_WORDS = ['var', 'let', 'const', 'static', 'function', 'null', 'undefined', 'new', 'delete', 'true', 'false', 'NaN', 'this'];
20708
+ const WGSL_KEY_WORDS = ['var', 'let', 'const', 'override', 'fn', 'struct', 'alias', 'true', 'false', 'bool', 'f16', 'f32', 'i32', 'u32', 'vec2',
20709
+ 'vec3', 'vec4', 'mat2x2', 'mat2x3', 'mat2x4', 'mat3x2', 'mat3x3', 'mat3x4', 'mat4x2', 'mat4x3', 'mat4x4' // 'atomic', 'array', 'ptr', 'sampler', 'sampler_comparison', 'texture_1d', 'texture_2d', 'texture_2d_array', 'texture_3d', 'texture_cube', 'texture_cube_array',
20710
+ // 'texture_multisampled_2d', 'texture_external', 'texture_storage_1d', 'texture_storage_2d', 'texture_storage_2d_array', 'texture_storage_3d', 'texture_depth_2d',
20711
+ // 'texture_depth_2d_array', 'texture_depth_cube', 'texture_depth_cube_array', 'texture_depth_multisampled_2d', 'function', 'private', 'workgroup', 'uniform',
20712
+ // 'storage', 'read', 'write', 'read_write', 'binding', 'builtin', 'group', 'id', 'interpolate', 'invariant', 'location', 'size', 'align', 'stride', 'vertex', 'fragment', 'compute', 'workgroup_size',
20713
+ ];
20714
+ const STATEMENT_WORDS = ['for', 'if', 'else', 'return', 'continue', 'break', 'case', 'switch', 'while', 'import', 'from', 'await'];
20600
20715
  const HTML_ATTRIBUTES = ['html', 'charset', 'rel', 'src', 'href', 'crossorigin', 'type', 'lang'];
20601
20716
  const HTML_TAGS = ['DOCTYPE', 'html', 'head', 'body', 'title', 'base', 'link', 'meta', 'style', 'main', 'section', 'nav', 'article', 'aside',
20602
20717
  'header', 'footer', 'address', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'hr', 'pre', 'blockquote', 'ol', 'ul', 'li', 'dl', 'dt', 'dd', 'figure',
@@ -20624,7 +20739,7 @@ class DocMaker {
20624
20739
  if (options.collapsable) {
20625
20740
  const collapsible = LX.makeElement('div', LX.mergeClass('my-4 px-6 cursor-pointer', options.className), `<${type} id="${id ?? ''}">${string}</${type}>`, this.root);
20626
20741
  const collapsibleContent = LX.makeContainer(['100%', 'auto'], 'px-4', '', this.root);
20627
- LX.listen(collapsible, "click", () => collapsible.querySelector('a.collapser').click());
20742
+ LX.listen(collapsible, 'click', () => collapsible.querySelector('a.collapser').click());
20628
20743
  this._lastDomTarget = this.root;
20629
20744
  this.setDomTarget(collapsibleContent);
20630
20745
  if (options.collapsableContentCallback) {
@@ -20705,6 +20820,9 @@ class DocMaker {
20705
20820
  else if (language == 'js' && JS_KEY_WORDS.includes(content)) {
20706
20821
  highlight = 'kwd';
20707
20822
  }
20823
+ else if (language == 'wgsl' && WGSL_KEY_WORDS.includes(content)) {
20824
+ highlight = 'kwd';
20825
+ }
20708
20826
  else if (CLASS_WORDS.includes(content)) {
20709
20827
  highlight = 'cls';
20710
20828
  }
@@ -20726,8 +20844,8 @@ class DocMaker {
20726
20844
  highlight = 'dec';
20727
20845
  }
20728
20846
  else {
20729
- console.error('ERROR[Code Parsing]: Unknown highlight type: ' + content);
20730
- return;
20847
+ highlight = '';
20848
+ console.error('WARNING[Code Parsing]: Unknown highlight type: ' + content);
20731
20849
  }
20732
20850
  html = getHTML(highlight, content);
20733
20851
  text = text.replace(`@${content}@`, html);