lexgui 8.2.2 → 8.2.4

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 +2 -0
  2. package/build/components/Form.d.ts +6 -0
  3. package/build/components/TextInput.d.ts +2 -0
  4. package/build/core/Namespace.js +1 -1
  5. package/build/core/Namespace.js.map +1 -1
  6. package/build/extensions/AssetView.d.ts +137 -137
  7. package/build/extensions/AssetView.js +1 -2
  8. package/build/extensions/AssetView.js.map +1 -1
  9. package/build/extensions/Audio.js +2 -2
  10. package/build/extensions/Audio.js.map +1 -1
  11. package/build/extensions/CodeEditor.d.ts +363 -358
  12. package/build/extensions/CodeEditor.js +5087 -5054
  13. package/build/extensions/CodeEditor.js.map +1 -1
  14. package/build/extensions/DocMaker.d.ts +14 -13
  15. package/build/extensions/DocMaker.js +354 -331
  16. package/build/extensions/DocMaker.js.map +1 -1
  17. package/build/lexgui.all.js +288 -145
  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 +288 -145
  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 +59 -57
  24. package/build/lexgui.js +195 -107
  25. package/build/lexgui.js.map +1 -1
  26. package/build/lexgui.min.css +2 -2
  27. package/build/lexgui.min.js +1 -1
  28. package/build/lexgui.module.js +195 -107
  29. package/build/lexgui.module.js.map +1 -1
  30. package/build/lexgui.module.min.js +1 -1
  31. package/changelog.md +33 -1
  32. package/demo.js +6 -3
  33. package/examples/all-components.html +15 -1
  34. package/examples/code-editor.html +7 -1
  35. package/examples/editor.html +9 -7
  36. package/package.json +1 -1
@@ -16,7 +16,7 @@
16
16
  exports.LX = g$2.LX;
17
17
  if (!exports.LX) {
18
18
  exports.LX = {
19
- version: '8.2.2',
19
+ version: '8.2.4',
20
20
  ready: false,
21
21
  extensions: [], // Store extensions used
22
22
  extraCommandbarEntries: [], // User specific entries for command bar
@@ -453,6 +453,7 @@
453
453
  onGetValue;
454
454
  onAllowPaste;
455
455
  onResize;
456
+ onSetDisabled;
456
457
  _initialValue;
457
458
  static NO_CONTEXT_TYPES = [
458
459
  exports.ComponentType.BUTTON,
@@ -521,6 +522,7 @@
521
522
  }
522
523
  this.root = root;
523
524
  this.root.jsInstance = this;
525
+ this.disabled = options.disabled ?? false;
524
526
  this.options = options;
525
527
  }
526
528
  static _dispatchEvent(element, type, data, bubbles, cancelable) {
@@ -681,6 +683,12 @@
681
683
  }
682
684
  console.error(`Unknown Component type: ${this.type}`);
683
685
  }
686
+ setDisabled(disabled) {
687
+ this.disabled = disabled;
688
+ if (this.onSetDisabled) {
689
+ this.onSetDisabled(disabled);
690
+ }
691
+ }
684
692
  refresh(value) {
685
693
  }
686
694
  };
@@ -752,6 +760,7 @@
752
760
  var wValue = exports.LX.makeElement('button', exports.LX.mergeClass(['lexbutton', 'inline-flex', 'items-center', 'justify-center', 'whitespace-nowrap', 'transition-all', 'disabled:pointer-events-none',
753
761
  'disabled:opacity-50', '[&_svg]:pointer-events-none', 'shrink-0', '[&_svg]:shrink-0', 'outline-none', 'select-none', 'cursor-pointer',
754
762
  'font-medium', 'text-sm', 'border-1', 'h-9', 'px-2', 'overflow-hidden', 'bg-clip-padding'].join(' '), options.buttonClass ?? 'outline'));
763
+ wValue.disabled = this.disabled;
755
764
  wValue.title = options.tooltip ? '' : (options.title ?? '');
756
765
  this.root.appendChild(wValue);
757
766
  if (options.selected) {
@@ -810,10 +819,6 @@
810
819
  };
811
820
  });
812
821
  }
813
- if (options.disabled) {
814
- this.disabled = true;
815
- wValue.setAttribute('disabled', true);
816
- }
817
822
  let trigger = wValue;
818
823
  if (options.swap) {
819
824
  wValue.classList.add('swap');
@@ -1473,6 +1478,7 @@
1473
1478
  vecinput.max = options.max ?? 1e24;
1474
1479
  vecinput.step = options.step ?? 'any';
1475
1480
  vecinput.type = 'number';
1481
+ vecinput.disabled = this.disabled;
1476
1482
  if (value.constructor == Number) {
1477
1483
  value = exports.LX.clamp(value, +vecinput.min, +vecinput.max);
1478
1484
  value = exports.LX.round(value, options.precision);
@@ -1485,9 +1491,6 @@
1485
1491
  let unitBox = exports.LX.makeContainer(['auto', 'auto'], 'px-2 bg-card content-center break-keep', options.units, valueBox);
1486
1492
  vecinput.unitBox = unitBox;
1487
1493
  }
1488
- if (options.disabled) {
1489
- this.disabled = vecinput.disabled = true;
1490
- }
1491
1494
  // Add slider below
1492
1495
  if (!options.skipSlider && options.min !== undefined && options.max !== undefined) {
1493
1496
  let sliderBox = exports.LX.makeContainer(['100%', 'auto'], 'z-1 input-box', '', box);
@@ -1602,6 +1605,7 @@
1602
1605
  */
1603
1606
  class TextInput extends BaseComponent$1 {
1604
1607
  valid;
1608
+ input;
1605
1609
  _triggerEvent;
1606
1610
  _lastValueTriggered;
1607
1611
  constructor(name, value, callback, options = {}) {
@@ -1640,13 +1644,12 @@
1640
1644
  container.style.display = 'flex';
1641
1645
  container.style.position = 'relative';
1642
1646
  this.root.appendChild(container);
1643
- this.disabled = (options.disabled || options.warning) ?? (options.url ? true : false);
1647
+ // override disabled (default is options.disable)
1648
+ this.disabled = (this.disabled || options.warning) ?? (options.url ? true : false);
1644
1649
  let wValue = null;
1645
1650
  if (!this.disabled) {
1646
1651
  wValue = exports.LX.makeElement('input', exports.LX.mergeClass('lextext text-sm', options.inputClass));
1647
1652
  wValue.type = options.type || '';
1648
- wValue.value = value || '';
1649
- wValue.style.textAlign = options.float ?? '';
1650
1653
  wValue.setAttribute('placeholder', options.placeholder ?? '');
1651
1654
  if (options.required) {
1652
1655
  wValue.setAttribute('required', options.required);
@@ -1693,17 +1696,46 @@
1693
1696
  else {
1694
1697
  wValue = document.createElement('input');
1695
1698
  wValue.disabled = true;
1696
- wValue.value = value;
1697
- wValue.style.textAlign = options.float ?? '';
1698
1699
  wValue.className = exports.LX.mergeClass('lextext ellipsis-overflow', options.inputClass);
1699
1700
  }
1700
1701
  if (options.fit) {
1701
1702
  wValue.classList.add('field-sizing-content');
1702
1703
  }
1704
+ if (wValue instanceof HTMLInputElement) {
1705
+ wValue.name = options.name;
1706
+ wValue.value = value ?? '';
1707
+ if (options.autocomplete) {
1708
+ wValue.autocomplete = options.autocomplete;
1709
+ }
1710
+ else if (wValue.type === 'password') {
1711
+ // allow password managers by default
1712
+ wValue.autocomplete = 'current-password';
1713
+ }
1714
+ else if (options.name === 'username' || options.name === 'email') {
1715
+ wValue.autocomplete = options.name;
1716
+ }
1717
+ else {
1718
+ // neutral default, don't break browser heuristics
1719
+ wValue.autocomplete = 'on';
1720
+ }
1721
+ wValue.style.textAlign = options.float ?? '';
1722
+ wValue.addEventListener('transitionstart', (e) => {
1723
+ if (e.propertyName === 'background-color'
1724
+ && wValue.matches(':-webkit-autofill')) {
1725
+ this.syncFromDOM();
1726
+ }
1727
+ });
1728
+ }
1703
1729
  Object.assign(wValue.style, options.style ?? {});
1704
1730
  container.appendChild(wValue);
1731
+ this.input = wValue;
1705
1732
  exports.LX.doAsync(this.onResize.bind(this));
1706
1733
  }
1734
+ syncFromDOM(skipCallback = true) {
1735
+ if (this.input instanceof HTMLInputElement) {
1736
+ this.set(this.input.value, skipCallback);
1737
+ }
1738
+ }
1707
1739
  }
1708
1740
  exports.LX.TextInput = TextInput;
1709
1741
 
@@ -1847,7 +1879,7 @@
1847
1879
  if (filter) {
1848
1880
  filter.root.querySelector('input').focus();
1849
1881
  }
1850
- }, { buttonClass: 'outline [&_a]:ml-auto', skipInlineCount: true, disabled: options.disabled });
1882
+ }, { buttonClass: 'outline [&_a]:ml-auto', skipInlineCount: true, disabled: this.disabled });
1851
1883
  selectedOption.root.style.width = '100%';
1852
1884
  selectedOption.root.querySelector('button').appendChild(exports.LX.makeIcon('Down', { svgClass: 'sm' }));
1853
1885
  container.appendChild(selectedOption.root);
@@ -2071,36 +2103,40 @@
2071
2103
  component = new TextInput(i + '', value, function (value) {
2072
2104
  values[i] = value;
2073
2105
  callback(values);
2074
- }, { nameWidth: '12px', className: 'p-0', skipReset: true });
2106
+ }, { nameWidth: '12px', className: 'p-0', disabled: this.disabled, skipReset: true });
2075
2107
  break;
2076
2108
  case Number:
2077
2109
  component = new NumberInput(i + '', value, function (value) {
2078
2110
  values[i] = value;
2079
2111
  callback(values);
2080
- }, { nameWidth: '12px', className: 'p-0', skipReset: true });
2112
+ }, { nameWidth: '12px', className: 'p-0', disabled: this.disabled, skipReset: true });
2081
2113
  break;
2082
2114
  case 'select':
2083
2115
  component = new Select(i + '', options.innerValues, value, function (value) {
2084
2116
  values[i] = value;
2085
2117
  callback(values);
2086
- }, { nameWidth: '12px', className: 'p-0', skipReset: true });
2118
+ }, { nameWidth: '12px', className: 'p-0', disabled: this.disabled, skipReset: true });
2087
2119
  break;
2088
2120
  }
2089
2121
  console.assert(component, `Value of type ${baseclass} cannot be modified in ArrayInput`);
2090
2122
  arrayItems.appendChild(component.root);
2091
- const removeComponent = new Button(null, '', (v, event) => {
2092
- values.splice(values.indexOf(value), 1);
2123
+ if (!this.disabled) {
2124
+ const removeComponent = new Button(null, '', (v, event) => {
2125
+ values.splice(values.indexOf(value), 1);
2126
+ this._updateItems();
2127
+ this._trigger(new IEvent$1(name, values, event), callback);
2128
+ }, { buttonClass: 'ghost sm p-0', title: 'Remove item', icon: 'Trash2' });
2129
+ component.root.appendChild(removeComponent.root);
2130
+ }
2131
+ }
2132
+ if (!this.disabled) {
2133
+ const addButton = new Button(null, exports.LX.makeIcon('Plus', { svgClass: 'sm' }).innerHTML + 'Add item', (v, event) => {
2134
+ values.push(options.innerValues ? options.innerValues[0] : '');
2093
2135
  this._updateItems();
2094
2136
  this._trigger(new IEvent$1(name, values, event), callback);
2095
- }, { buttonClass: 'ghost xs p-0', title: 'Remove item', icon: 'Trash2' });
2096
- component.root.appendChild(removeComponent.root);
2137
+ }, { buttonClass: 'ghost' });
2138
+ arrayItems.appendChild(addButton.root);
2097
2139
  }
2098
- const addButton = new Button(null, exports.LX.makeIcon('Plus', { svgClass: 'sm' }).innerHTML + 'Add item', (v, event) => {
2099
- values.push(options.innerValues ? options.innerValues[0] : '');
2100
- this._updateItems();
2101
- this._trigger(new IEvent$1(name, values, event), callback);
2102
- }, { buttonClass: 'ghost' });
2103
- arrayItems.appendChild(addButton.root);
2104
2140
  };
2105
2141
  this._updateItems();
2106
2142
  }
@@ -2189,13 +2225,13 @@
2189
2225
  const realNameWidth = this.root.domName?.style.width ?? '0px';
2190
2226
  container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
2191
2227
  };
2192
- var container = document.createElement('div');
2228
+ let container = document.createElement('div');
2193
2229
  container.className = 'flex items-center gap-2 my-0 mx-auto [&_span]:truncate [&_span]:flex-auto-fill';
2194
2230
  this.root.appendChild(container);
2195
- let checkbox = exports.LX.makeElement('input', exports.LX.mergeClass('lexcheckbox rounded-xl', options.className ?? 'primary'));
2231
+ let checkbox = exports.LX.makeElement('input', exports.LX.mergeClass('lexcheckbox rounded-xl disabled:pointer-events-none disabled:opacity-50', options.className ?? 'primary'));
2196
2232
  checkbox.type = 'checkbox';
2197
2233
  checkbox.checked = value;
2198
- checkbox.disabled = options.disabled ?? false;
2234
+ checkbox.disabled = this.disabled;
2199
2235
  container.appendChild(checkbox);
2200
2236
  exports.LX.makeElement('span', 'text-sm', options.label ?? 'On', container);
2201
2237
  checkbox.addEventListener('change', (e) => {
@@ -2830,7 +2866,7 @@
2830
2866
  let sampleContainer = exports.LX.makeContainer(['18px', '18px'], 'flex flex-row rounded overflow-hidden', '', container);
2831
2867
  sampleContainer.tabIndex = '1';
2832
2868
  sampleContainer.addEventListener('click', (e) => {
2833
- if ((options.disabled ?? false)) {
2869
+ if (this.disabled) {
2834
2870
  return;
2835
2871
  }
2836
2872
  this._popover = new Popover(sampleContainer, [this.picker]);
@@ -2854,7 +2890,7 @@
2854
2890
  this.set(v);
2855
2891
  delete this._skipTextUpdate;
2856
2892
  this.picker.fromHexColor(v);
2857
- }, { width: 'calc( 100% - 24px )', disabled: options.disabled });
2893
+ }, { width: 'calc( 100% - 24px )', disabled: this.disabled });
2858
2894
  textComponent.root.style.marginLeft = '6px';
2859
2895
  container.appendChild(textComponent.root);
2860
2896
  exports.LX.doAsync(this.onResize.bind(this));
@@ -2991,15 +3027,13 @@
2991
3027
  const input = exports.LX.makeElement('input', 'lexcounter w-12 bg-card px-2 text-foreground', '', container);
2992
3028
  input.type = 'number';
2993
3029
  input.value = value;
2994
- if (options.disabled) {
2995
- input.setAttribute('disabled', 'true');
2996
- }
3030
+ input.disabled = this.disabled;
2997
3031
  const substrButton = new Button(null, '', (value, e) => {
2998
3032
  let mult = step ?? 1;
2999
3033
  if (e.shiftKey)
3000
3034
  mult *= 10;
3001
3035
  this.set(this.count - mult, false, e);
3002
- }, { disabled: options.disabled, className: `p-0 ${options.disabled ? '' : 'hover:bg-secondary'} border-l-color border-r-color`,
3036
+ }, { disabled: this.disabled, className: `p-0 ${this.disabled ? '' : 'hover:bg-secondary'} border-l-color border-r-color`,
3003
3037
  buttonClass: 'px-0 bg-none h-7', icon: 'Minus' });
3004
3038
  container.appendChild(substrButton.root);
3005
3039
  const addButton = new Button(null, '', (value, e) => {
@@ -3007,8 +3041,8 @@
3007
3041
  if (e.shiftKey)
3008
3042
  mult *= 10;
3009
3043
  this.set(this.count + mult, false, e);
3010
- }, { disabled: options.disabled, className: `p-0 ${options.disabled ? '' : 'hover:bg-secondary'} rounded-r-lg`,
3011
- buttonClass: 'px-0 bg-none h-7', icon: 'Plus' });
3044
+ }, { disabled: this.disabled, className: `p-0 ${this.disabled ? '' : 'hover:bg-secondary'} rounded-r-lg`, buttonClass: 'px-0 bg-none h-7',
3045
+ icon: 'Plus' });
3012
3046
  container.appendChild(addButton.root);
3013
3047
  }
3014
3048
  }
@@ -3756,7 +3790,7 @@
3756
3790
  const calendarIcon = exports.LX.makeIcon('Calendar');
3757
3791
  const calendarButton = new Button(null, d0, () => {
3758
3792
  this._popover = new Popover(calendarButton.root, [this.calendar]);
3759
- }, { buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3793
+ }, { disabled: this.disabled, buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3760
3794
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
3761
3795
  calendarButton.root.style.width = '100%';
3762
3796
  container.appendChild(calendarButton.root);
@@ -3767,7 +3801,8 @@
3767
3801
  const calendarIcon = exports.LX.makeIcon('Calendar');
3768
3802
  const calendarButton = new Button(null, d1, () => {
3769
3803
  this._popover = new Popover(calendarButton.root, [this.calendar]);
3770
- }, { buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3804
+ }, { disabled: this.disabled,
3805
+ buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3771
3806
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
3772
3807
  calendarButton.root.style.width = '100%';
3773
3808
  container.appendChild(calendarButton.root);
@@ -4138,7 +4173,7 @@
4138
4173
  let input = document.createElement('input');
4139
4174
  input.className = 'lexfileinput';
4140
4175
  input.type = 'file';
4141
- input.disabled = options.disabled ?? false;
4176
+ input.disabled = this.disabled;
4142
4177
  this.root.appendChild(input);
4143
4178
  if (options.placeholder) {
4144
4179
  input.placeholder = options.placeholder;
@@ -4188,7 +4223,7 @@
4188
4223
  root.remove();
4189
4224
  settingsDialog = null;
4190
4225
  } });
4191
- }, { skipInlineCount: true, title: 'Settings', disabled: options.disabled, icon: 'Settings' });
4226
+ }, { skipInlineCount: true, title: 'Settings', disabled: this.disabled, icon: 'Settings' });
4192
4227
  this.root.appendChild(settingButton.root);
4193
4228
  }
4194
4229
  exports.LX.doAsync(this.onResize.bind(this));
@@ -4202,6 +4237,9 @@
4202
4237
  * @description Form Component
4203
4238
  */
4204
4239
  class Form extends BaseComponent$1 {
4240
+ data;
4241
+ formData = {};
4242
+ primaryButton;
4205
4243
  constructor(name, data, callback, options = {}) {
4206
4244
  if (data.constructor != Object) {
4207
4245
  console.error('Form data must be an Object');
@@ -4211,10 +4249,10 @@
4211
4249
  options.hideName = true;
4212
4250
  super(exports.ComponentType.FORM, name, null, options);
4213
4251
  this.onGetValue = () => {
4214
- return container.formData;
4252
+ return this.formData;
4215
4253
  };
4216
4254
  this.onSetValue = (newValue, skipCallback, event) => {
4217
- container.formData = newValue;
4255
+ this.formData = newValue;
4218
4256
  const entries = container.querySelectorAll('.lexcomponent');
4219
4257
  for (let i = 0; i < entries.length; ++i) {
4220
4258
  const entry = entries[i];
@@ -4230,7 +4268,6 @@
4230
4268
  let container = document.createElement('div');
4231
4269
  container.className = 'flex flex-col gap-1';
4232
4270
  container.style.width = '100%';
4233
- container.formData = {};
4234
4271
  this.root.appendChild(container);
4235
4272
  for (let entry in data) {
4236
4273
  let entryData = data[entry];
@@ -4248,42 +4285,70 @@
4248
4285
  container.appendChild(label.root);
4249
4286
  }
4250
4287
  entryData.textComponent = new TextInput(null, entryData.constructor == Object ? entryData.value : entryData, (value, event) => {
4251
- container.formData[entry] = value;
4252
- if (entryData.submit && event.constructor === KeyboardEvent) {
4253
- primaryButton?.click();
4288
+ this.formData[entry] = value;
4289
+ if (entryData.submit && event?.constructor === KeyboardEvent) {
4290
+ this.submit();
4254
4291
  }
4255
4292
  }, entryData);
4256
4293
  container.appendChild(entryData.textComponent.root);
4257
- container.formData[entry] = entryData.constructor == Object ? entryData.value : entryData;
4294
+ this.formData[entry] = entryData.constructor == Object ? entryData.value : entryData;
4258
4295
  }
4259
4296
  const buttonContainer = exports.LX.makeContainer(['100%', 'auto'], 'flex flex-row mt-2', '', container);
4260
4297
  if (options.secondaryActionName || options.secondaryActionCallback) {
4261
4298
  const secondaryButton = new Button(null, options.secondaryActionName ?? 'Cancel', (value, event) => {
4262
4299
  if (options.secondaryActionCallback) {
4263
- options.secondaryActionCallback(container.formData, event);
4300
+ options.secondaryActionCallback(this.formData, event);
4264
4301
  }
4265
4302
  }, { width: '100%', minWidth: '0', buttonClass: options.secondaryButtonClass ?? 'secondary' });
4266
4303
  buttonContainer.appendChild(secondaryButton.root);
4267
4304
  }
4268
- const primaryButton = new Button(null, options.primaryActionName ?? 'Submit', (value, event) => {
4305
+ // This is basically the "submit" button
4306
+ this.primaryButton = new Button(null, options.primaryActionName ?? 'Submit', (value, event) => {
4307
+ // Force sync before testing text patterns
4308
+ this.syncInputs();
4269
4309
  const errors = [];
4270
4310
  for (let entry in data) {
4271
4311
  let entryData = data[entry];
4272
4312
  const pattern = entryData.pattern;
4273
- const matchField = pattern?.fieldMatchName ? container.formData[pattern.fieldMatchName] : undefined;
4313
+ const matchField = pattern?.fieldMatchName ? this.formData[pattern.fieldMatchName] : undefined;
4274
4314
  if (!entryData.textComponent.valid(undefined, matchField)) {
4275
4315
  const err = { entry, type: 'input_not_valid', messages: [] };
4276
4316
  if (pattern) {
4277
- err.messages = exports.LX.validateValueAtPattern(container.formData[entry], pattern, matchField);
4317
+ err.messages = exports.LX.validateValueAtPattern(this.formData[entry], pattern, matchField);
4278
4318
  }
4279
4319
  errors.push(err);
4280
4320
  }
4281
4321
  }
4282
4322
  if (callback) {
4283
- callback(container.formData, errors, event);
4323
+ callback(this.formData, errors, event);
4284
4324
  }
4285
4325
  }, { width: '100%', minWidth: '0', buttonClass: options.primaryButtonClass ?? 'primary' });
4286
- buttonContainer.appendChild(primaryButton.root);
4326
+ buttonContainer.appendChild(this.primaryButton.root);
4327
+ if (!(options.skipEnterSubmit ?? false)) {
4328
+ this.root.addEventListener('keydown', (e) => {
4329
+ if (e.key !== 'Enter' || e.shiftKey)
4330
+ return;
4331
+ const target = e.target;
4332
+ if (target.tagName === 'TEXTAREA')
4333
+ return;
4334
+ e.preventDefault();
4335
+ this.submit();
4336
+ });
4337
+ }
4338
+ this.data = data;
4339
+ }
4340
+ submit() {
4341
+ this.syncInputs();
4342
+ this.primaryButton?.click();
4343
+ }
4344
+ syncInputs() {
4345
+ for (const entry in this.data) {
4346
+ const component = this.data[entry].textComponent;
4347
+ if (component instanceof TextInput) {
4348
+ component.syncFromDOM();
4349
+ this.formData[entry] = component.value();
4350
+ }
4351
+ }
4287
4352
  }
4288
4353
  }
4289
4354
  exports.LX.Form = Form;
@@ -4322,9 +4387,11 @@
4322
4387
  binary = '0' + binary;
4323
4388
  }
4324
4389
  for (let bit = 0; bit < maxBits; ++bit) {
4325
- let layer = document.createElement('div');
4390
+ let layer = document.createElement('button');
4326
4391
  layer.className =
4327
- 'lexlayer size-6 text-secondary-foreground text-center content-center place-self-center cursor-pointer font-semibold text-xs rounded-lg';
4392
+ `lexlayer size-6 text-secondary-foreground text-center content-center place-self-center cursor-pointer font-semibold text-xs rounded-lg select-none
4393
+ disabled:pointer-events-none disabled:opacity-50`;
4394
+ layer.disabled = this.disabled;
4328
4395
  if (val != undefined) {
4329
4396
  const valueBit = binary[maxBits - bit - 1];
4330
4397
  if (valueBit != undefined && valueBit == '1') {
@@ -4395,8 +4462,9 @@
4395
4462
  icon = itemValue[1];
4396
4463
  itemValue = itemValue[0];
4397
4464
  }
4398
- let listElement = document.createElement('div');
4399
- listElement.className = 'lexlistitem' + (value == itemValue ? ' selected' : '');
4465
+ let listElement = document.createElement('button');
4466
+ listElement.className = `lexlistitem disabled:pointer-events-none disabled:opacity-50 ${(value == itemValue) ? 'selected' : ''}`;
4467
+ listElement.disabled = this.disabled;
4400
4468
  if (icon) {
4401
4469
  listElement.appendChild(exports.LX.makeIcon(icon));
4402
4470
  }
@@ -4855,10 +4923,10 @@
4855
4923
  container.className = 'lexmap2d';
4856
4924
  this.root.appendChild(container);
4857
4925
  this.map2d = new CanvasMap2D(points, callback, options);
4858
- const calendarIcon = exports.LX.makeIcon('SquareMousePointer');
4926
+ const calendarIcon = exports.LX.makeIcon(options.mapIcon ?? 'SquareMousePointer');
4859
4927
  const calendarButton = new Button(null, 'Open Map', () => {
4860
4928
  this._popover = new Popover(calendarButton.root, [this.map2d]);
4861
- }, { buttonClass: `outline justify-between` });
4929
+ }, { buttonClass: `outline justify-between`, disabled: this.disabled });
4862
4930
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
4863
4931
  container.appendChild(calendarButton.root);
4864
4932
  exports.LX.doAsync(this.onResize.bind(this));
@@ -5540,7 +5608,6 @@
5540
5608
  const realNameWidth = this.root.domName?.style.width ?? '0px';
5541
5609
  container.style.width = `calc( 100% - ${realNameWidth})`;
5542
5610
  };
5543
- this.disabled = options.disabled ?? false;
5544
5611
  const container = document.createElement('div');
5545
5612
  container.className = 'lexotp flex flex-row items-center';
5546
5613
  this.root.appendChild(container);
@@ -5651,17 +5718,18 @@
5651
5718
  const realNameWidth = this.root.domName?.style.width ?? '0px';
5652
5719
  container.style.width = `calc( 100% - ${realNameWidth})`;
5653
5720
  };
5654
- var container = document.createElement('div');
5721
+ let container = document.createElement('div');
5655
5722
  container.className = 'lexpad';
5656
5723
  this.root.appendChild(container);
5657
5724
  let pad = document.createElement('div');
5658
5725
  pad.id = 'lexpad-' + name;
5659
- pad.className = 'lexinnerpad';
5726
+ pad.className = 'lexinnerpad data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 border-color';
5660
5727
  pad.style.width = options.padSize ?? '96px';
5661
5728
  pad.style.height = options.padSize ?? '96px';
5729
+ pad.dataset['disabled'] = this.disabled.toString();
5662
5730
  container.appendChild(pad);
5663
5731
  let thumb = document.createElement('div');
5664
- thumb.className = 'lexpadthumb';
5732
+ thumb.className = 'lexpadthumb opacity-inherit';
5665
5733
  thumb.value = new vec2$3(value[0], value[1]);
5666
5734
  thumb.min = options.min ?? 0;
5667
5735
  thumb.max = options.max ?? 1;
@@ -5854,7 +5922,7 @@
5854
5922
  container.appendChild(optionItem);
5855
5923
  const optionButton = document.createElement('button');
5856
5924
  optionButton.className = 'flex p-0 rounded-lg cursor-pointer';
5857
- optionButton.disabled = options.disabled ?? false;
5925
+ optionButton.disabled = this.disabled;
5858
5926
  optionItem.appendChild(optionButton);
5859
5927
  optionButton.addEventListener('click', (e) => {
5860
5928
  this.set(i, false, e);
@@ -5966,7 +6034,7 @@
5966
6034
  slider.max = options.max ?? 100;
5967
6035
  slider.step = options.step ?? 1;
5968
6036
  slider.type = 'range';
5969
- slider.disabled = options.disabled ?? false;
6037
+ slider.disabled = this.disabled;
5970
6038
  if (value.constructor == Number) {
5971
6039
  value = exports.LX.clamp(value, +slider.min, +slider.max);
5972
6040
  }
@@ -6025,7 +6093,7 @@
6025
6093
  maxSlider.max = options.max ?? 100;
6026
6094
  maxSlider.step = options.step ?? 1;
6027
6095
  maxSlider.type = 'range';
6028
- maxSlider.disabled = options.disabled ?? false;
6096
+ maxSlider.disabled = this.disabled;
6029
6097
  this._maxSlider = maxSlider;
6030
6098
  let maxRangeValue = ogValue[1];
6031
6099
  maxSlider.value = maxRangeValue = exports.LX.clamp(maxRangeValue, +maxSlider.min, +maxSlider.max);
@@ -6066,7 +6134,8 @@
6066
6134
  container.style.width = `calc( 100% - ${realNameWidth})`;
6067
6135
  };
6068
6136
  const container = document.createElement('div');
6069
- container.className = 'lexrate relative';
6137
+ container.className = 'lexrate relative data-[disabled=true]:pointer-events-none';
6138
+ container.dataset['disabled'] = this.disabled.toString();
6070
6139
  this.root.appendChild(container);
6071
6140
  const starsContainer = exports.LX.makeContainer(['fit-content', 'auto'], 'flex flex-row gap-1', '', container);
6072
6141
  const filledStarsContainer = exports.LX.makeContainer(['fit-content', 'auto'], 'absolute top-0 flex flex-row gap-1 pointer-events-none', '', container);
@@ -6165,7 +6234,7 @@
6165
6234
  if (callback) {
6166
6235
  callback(value);
6167
6236
  }
6168
- }, { min: 0, disabled: options.disabled, precision: options.precision, className: 'flex-auto-fill' });
6237
+ }, { min: 0, disabled: this.disabled, precision: options.precision, className: 'flex-auto-fill' });
6169
6238
  container.appendChild(this.root.dimensions[i].root);
6170
6239
  if ((i + 1) != value.length) {
6171
6240
  const xIcon = exports.LX.makeIcon('X', { svgClass: 'text-foreground font-bold' });
@@ -7215,16 +7284,22 @@
7215
7284
  tagsContainer.innerHTML = '';
7216
7285
  for (let i = 0; i < value.length; ++i) {
7217
7286
  const tagName = value[i];
7218
- const tag = exports.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);
7219
- const removeButton = exports.LX.makeIcon('X', { svgClass: 'sm' });
7220
- tag.appendChild(removeButton);
7221
- removeButton.addEventListener('click', (e) => {
7222
- tag.remove();
7223
- value.splice(value.indexOf(tagName), 1);
7224
- this.set(value, false, e);
7225
- });
7287
+ const tagClass = exports.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);
7288
+ const tag = exports.LX.makeElement('span', tagClass, tagName);
7289
+ if (!this.disabled) {
7290
+ const removeButton = exports.LX.makeIcon('X', { svgClass: 'sm' });
7291
+ tag.appendChild(removeButton);
7292
+ removeButton.addEventListener('click', (e) => {
7293
+ tag.remove();
7294
+ value.splice(value.indexOf(tagName), 1);
7295
+ this.set(value, false, e);
7296
+ });
7297
+ }
7226
7298
  tagsContainer.appendChild(tag);
7227
7299
  }
7300
+ if (this.disabled) {
7301
+ return;
7302
+ }
7228
7303
  let tagInput = document.createElement('input');
7229
7304
  tagInput.value = '';
7230
7305
  tagInput.placeholder = 'Add tag...';
@@ -7273,9 +7348,10 @@
7273
7348
  container.className = 'lextextarea';
7274
7349
  container.style.display = 'flex';
7275
7350
  this.root.appendChild(container);
7276
- let wValue = exports.LX.makeElement('textarea', options.inputClass ?? '');
7351
+ let wValue = exports.LX.makeElement('textarea', exports.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 ?? ''));
7277
7352
  wValue.value = value ?? '';
7278
7353
  wValue.style.textAlign = options.float ?? '';
7354
+ wValue.disabled = this.disabled;
7279
7355
  Object.assign(wValue.style, options.style ?? {});
7280
7356
  if (options.fitHeight ?? false) {
7281
7357
  wValue.classList.add('field-sizing-content');
@@ -7284,17 +7360,22 @@
7284
7360
  wValue.classList.add('resize-none');
7285
7361
  }
7286
7362
  container.appendChild(wValue);
7287
- if (options.disabled ?? false) {
7288
- this.disabled = true;
7289
- wValue.setAttribute('disabled', 'true');
7290
- }
7291
7363
  if (options.placeholder) {
7292
7364
  wValue.setAttribute('placeholder', options.placeholder);
7293
7365
  }
7294
7366
  const trigger = options.trigger ?? 'default';
7367
+ const submitOnEnterKey = options.submitOnEnterKey ?? true;
7295
7368
  if (trigger == 'default') {
7369
+ wValue.addEventListener('keydown', function (e) {
7370
+ if (submitOnEnterKey && e.key == 'Enter' && !e.shiftKey) {
7371
+ e.preventDefault();
7372
+ return false;
7373
+ }
7374
+ });
7296
7375
  wValue.addEventListener('keyup', function (e) {
7297
- if (e.key == 'Enter') {
7376
+ if ((submitOnEnterKey && e.key == 'Enter' && !e.shiftKey)
7377
+ || e.key == 'Escape') {
7378
+ e.preventDefault();
7298
7379
  wValue.blur();
7299
7380
  }
7300
7381
  });
@@ -7383,11 +7464,11 @@
7383
7464
  var container = document.createElement('div');
7384
7465
  container.className = 'flex flex-row gap-2 items-center';
7385
7466
  this.root.appendChild(container);
7386
- let toggle = exports.LX.makeElement('input', exports.LX.mergeClass('lextoggle relative inline-grid place-content-center cursor-pointer shrink-0 select-none', options.className));
7467
+ let toggle = exports.LX.makeElement('input', exports.LX.mergeClass('lextoggle relative inline-grid place-content-center cursor-pointer shrink-0 select-none disabled:pointer-events-none disabled:opacity-50', options.className));
7387
7468
  toggle.type = 'checkbox';
7388
7469
  toggle.checked = value;
7389
7470
  toggle.iValue = value;
7390
- toggle.disabled = options.disabled ?? false;
7471
+ toggle.disabled = this.disabled;
7391
7472
  container.appendChild(toggle);
7392
7473
  let valueName = document.createElement('span');
7393
7474
  valueName.className = 'font-medium w-full overflow-hidden truncate';
@@ -7454,7 +7535,6 @@
7454
7535
  var container = document.createElement('div');
7455
7536
  container.className = 'lexvector flex';
7456
7537
  this.root.appendChild(container);
7457
- this.disabled = options.disabled ?? false;
7458
7538
  const that = this;
7459
7539
  for (let i = 0; i < numComponents; ++i) {
7460
7540
  let box = document.createElement('div');
@@ -7468,6 +7548,7 @@
7468
7548
  vecinput.type = 'number';
7469
7549
  vecinput.id = 'vec' + numComponents + '_' + exports.LX.guidGenerator();
7470
7550
  vecinput.idx = i;
7551
+ vecinput.disabled = this.disabled;
7471
7552
  vectorInputs[i] = vecinput;
7472
7553
  box.appendChild(vecinput);
7473
7554
  if (value[i].constructor == Number) {
@@ -7477,9 +7558,6 @@
7477
7558
  vecinput.value = vecinput.iValue = value[i];
7478
7559
  const dragIcon = exports.LX.makeIcon('MoveVertical', { iconClass: 'drag-icon hidden-opacity', svgClass: 'sm' });
7479
7560
  box.appendChild(dragIcon);
7480
- if (this.disabled) {
7481
- vecinput.disabled = true;
7482
- }
7483
7561
  // Add wheel input
7484
7562
  vecinput.addEventListener('wheel', function (e) {
7485
7563
  e.preventDefault();
@@ -10376,8 +10454,10 @@
10376
10454
  const collapsed = options.collapsed ?? true;
10377
10455
  const actionIcon = exports.LX.makeIcon('Right');
10378
10456
  actionIcon.classList.add('collapser');
10379
- if (collapsed)
10380
- actionIcon.dataset['collapsed'] = `${collapsed}`;
10457
+ if (collapsed) {
10458
+ actionIcon.dataset['collapsed'] = `true`;
10459
+ content.style.display = 'none';
10460
+ }
10381
10461
  actionIcon.style.marginLeft = 'auto';
10382
10462
  actionIcon.style.marginRight = '0.2rem';
10383
10463
  actionIcon.addEventListener('click', function (e) {
@@ -10779,29 +10859,37 @@
10779
10859
  options.modal = true;
10780
10860
  options.className = 'prompt';
10781
10861
  let value = '';
10862
+ const _submitFn = () => {
10863
+ if (options.required && value === '') {
10864
+ text += text.includes('You must fill the input text.') ? '' : '\nYou must fill the input text.';
10865
+ dialog.close();
10866
+ prompt(text, title, callback, options);
10867
+ }
10868
+ else {
10869
+ if (callback)
10870
+ callback.call(exports.LX, value);
10871
+ dialog.close();
10872
+ }
10873
+ };
10782
10874
  const dialog = new exports.LX.Dialog(title, (p) => {
10783
- p.addTextArea(null, text, null, { disabled: true, fitHeight: true });
10875
+ exports.LX.makeElement('p', 'max-h-64 p-2 break-word overflow-scroll', text, p);
10784
10876
  if (options.input ?? true) {
10785
- p.addText(null, options.input || value, (v) => value = v, { placeholder: '...' });
10877
+ p.addText(null, options.input || value, (v, e) => {
10878
+ value = v;
10879
+ if (e?.constructor === KeyboardEvent) {
10880
+ _submitFn();
10881
+ }
10882
+ }, { placeholder: '...' });
10786
10883
  }
10787
10884
  p.sameLine(2);
10788
10885
  p.addButton(null, 'Cancel', () => {
10789
10886
  if (options.on_cancel)
10790
10887
  options.on_cancel();
10791
10888
  dialog.close();
10792
- });
10889
+ }, { width: '50%', buttonClass: 'destructive' });
10793
10890
  p.addButton(null, options.accept || 'Continue', () => {
10794
- if (options.required && value === '') {
10795
- text += text.includes('You must fill the input text.') ? '' : '\nYou must fill the input text.';
10796
- dialog.close();
10797
- prompt(text, title, callback, options);
10798
- }
10799
- else {
10800
- if (callback)
10801
- callback.call(exports.LX, value);
10802
- dialog.close();
10803
- }
10804
- }, { buttonClass: 'primary' });
10891
+ _submitFn();
10892
+ }, { width: '50%', buttonClass: 'primary' });
10805
10893
  }, options);
10806
10894
  // Focus text prompt
10807
10895
  if (options.input ?? true) {
@@ -11643,7 +11731,7 @@
11643
11731
  options.modal = true;
11644
11732
  super(undefined, (p) => {
11645
11733
  p.root.className = exports.LX.mergeClass(p.root.className, 'pad-2xl flex flex-col gap-2');
11646
- exports.LX.makeContainer(['100%', '100%'], 'text-lg font-medium text-foreground', title, p);
11734
+ exports.LX.makeContainer(['100%', '100%'], 'text-lg font-medium text-foreground px-2', title, p);
11647
11735
  p.addTextArea(null, message, null, { disabled: true, fitHeight: true, inputClass: 'bg-none text-sm text-muted-foreground' });
11648
11736
  p.sameLine(2, 'justify-end');
11649
11737
  p.addButton(null, options.cancelText ?? 'Cancel', () => this.destroy(), {
@@ -14282,8 +14370,7 @@
14282
14370
  options.push({ name: o.name, icon: o.icon, callback: o.callback?.bind(that, item) });
14283
14371
  }
14284
14372
  }
14285
- options.push(null, { name: 'Delete', icon: 'Trash2', className: 'text-destructive',
14286
- callback: that._requestDeleteItem.bind(that, item) });
14373
+ options.push(null, { name: 'Delete', icon: 'Trash2', className: 'destructive', callback: that._requestDeleteItem.bind(that, item) });
14287
14374
  exports.LX.addClass(that.contentPanel.root, 'pointer-events-none');
14288
14375
  exports.LX.addDropdownMenu(e.target, options, { side: 'right', align: 'start', event: e, onBlur: () => {
14289
14376
  exports.LX.removeClass(that.contentPanel.root, 'pointer-events-none');
@@ -15384,7 +15471,7 @@
15384
15471
  };
15385
15472
  const angle = exports.LX.remapRange(value, min, max, -135, 135.0);
15386
15473
  innerKnobCircle.style.rotate = angle + 'deg';
15387
- if (options.disabled) {
15474
+ if (this.disabled) {
15388
15475
  exports.LX.addClass(container, 'disabled');
15389
15476
  }
15390
15477
  innerKnobCircle.addEventListener('change', (e) => {
@@ -15411,7 +15498,7 @@
15411
15498
  innerKnobCircle.addEventListener('mousedown', innerMouseDown);
15412
15499
  var that = this;
15413
15500
  function innerMouseDown(e) {
15414
- if (document.activeElement == innerKnobCircle || options.disabled) {
15501
+ if (document.activeElement == innerKnobCircle || that.disabled) {
15415
15502
  return;
15416
15503
  }
15417
15504
  var doc = that.root.ownerDocument;
@@ -17674,7 +17761,7 @@
17674
17761
  content = text.split(separator).join('\n');
17675
17762
  }
17676
17763
  const options = this.onContextMenu(this, content, e);
17677
- if (options.length) {
17764
+ if (options?.length) {
17678
17765
  m.add('');
17679
17766
  for (const o of options) {
17680
17767
  m.add(o.path, { disabled: o.disabled, callback: o.callback });
@@ -18478,7 +18565,7 @@
18478
18565
  const tokenIndex = i;
18479
18566
  const tokenStartIndex = this._currentTokenPositions[tokenIndex];
18480
18567
  if (blockComments) {
18481
- if (token.substr(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]) {
18568
+ if (token.substring(0, blockCommentsTokens[0].length) == blockCommentsTokens[0]) {
18482
18569
  this._buildingBlockComment = [lineNumber, tokenStartIndex];
18483
18570
  }
18484
18571
  }
@@ -18887,18 +18974,19 @@
18887
18974
  lineString = ogLine.substring(0, hasCommentIdx);
18888
18975
  }
18889
18976
  let tokensToEvaluate = []; // store in a temp array so we know prev and next tokens...
18890
- let charCounterList = [];
18891
18977
  let charCounter = 0;
18892
18978
  const pushToken = function (t) {
18893
18979
  if ((skipNonWords && (t.includes('"') || t.length < 3))) {
18894
18980
  return;
18895
18981
  }
18896
- tokensToEvaluate.push(t);
18897
- charCounterList.push(charCounter);
18982
+ tokensToEvaluate.push({
18983
+ text: t,
18984
+ pos: charCounter
18985
+ });
18898
18986
  // Update positions
18899
18987
  charCounter += t.length;
18900
18988
  };
18901
- let iter = lineString.matchAll(/(<!--|-->|\*\/|\/\*|::|[\[\](){}<>.,;:*"'`%@$!/= ])/g);
18989
+ let iter = lineString.matchAll(/(<!--|-->|\*\/|\/\*|::|[\[\](){}<>.,;:*"'`%@$!/=+\- ])/g);
18902
18990
  let subtokens = iter.next();
18903
18991
  if (subtokens.value) {
18904
18992
  let idx = 0;
@@ -18921,8 +19009,40 @@
18921
19009
  if (hasCommentIdx != undefined) {
18922
19010
  pushToken(ogLine.substring(hasCommentIdx));
18923
19011
  }
18924
- this._currentTokenPositions = charCounterList;
18925
- return this._processTokens(tokensToEvaluate);
19012
+ // Apply step to merge numeric tokens, since they might be separated by '.'
19013
+ const mergedTokens = this._mergeNumericTokens(tokensToEvaluate);
19014
+ this._currentTokenPositions = mergedTokens.map((t) => t.pos);
19015
+ return this._processTokens(mergedTokens.map((t) => t.text));
19016
+ }
19017
+ _mergeNumericTokens(tokens) {
19018
+ const result = [];
19019
+ for (let i = 0; i < tokens.length; i++) {
19020
+ const t = tokens[i];
19021
+ const prev = result[result.length - 1];
19022
+ const next = tokens[i + 1];
19023
+ // number . number
19024
+ if (prev && t.text === '.' && /^\d+$/.test(prev.text) && next && /^\d+$/.test(next.text)) {
19025
+ prev.text += '.' + next.text;
19026
+ i++;
19027
+ continue;
19028
+ }
19029
+ // . number
19030
+ if (t.text === '.' && next && /^\d+$/.test(next.text)) {
19031
+ result.push({
19032
+ text: '.' + next.text,
19033
+ pos: t.pos
19034
+ });
19035
+ i++;
19036
+ continue;
19037
+ }
19038
+ // number .
19039
+ if (prev && t.text === '.' && /^\d+$/.test(prev.text)) {
19040
+ prev.text += '.';
19041
+ continue;
19042
+ }
19043
+ result.push({ ...t });
19044
+ }
19045
+ return result;
18926
19046
  }
18927
19047
  _processTokens(tokens, offset = 0) {
18928
19048
  if (this.highlight == 'C++' || this.highlight == 'CSS') {
@@ -20546,6 +20666,7 @@
20546
20666
  class DocMaker {
20547
20667
  root;
20548
20668
  _listQueued = undefined;
20669
+ _lastDomTarget = undefined;
20549
20670
  constructor(element) {
20550
20671
  this.root = element ?? document.body;
20551
20672
  }
@@ -20556,20 +20677,37 @@
20556
20677
  target = target ?? this.root;
20557
20678
  target.appendChild(document.createElement('br'));
20558
20679
  }
20559
- header(string, type, id) {
20680
+ header(string, type, id, options = {}) {
20560
20681
  console.assert(string !== undefined && type !== undefined);
20561
- let header = document.createElement(type);
20682
+ if (options.collapsable) {
20683
+ const collapsible = exports.LX.makeElement('div', exports.LX.mergeClass('my-4 px-6 cursor-pointer', options.className), `<${type} id="${id ?? ''}">${string}</${type}>`, this.root);
20684
+ const collapsibleContent = exports.LX.makeContainer(['100%', 'auto'], 'px-4', '', this.root);
20685
+ exports.LX.listen(collapsible, 'click', () => collapsible.querySelector('a.collapser').click());
20686
+ this._lastDomTarget = this.root;
20687
+ this.setDomTarget(collapsibleContent);
20688
+ if (options.collapsableContentCallback) {
20689
+ options.collapsableContentCallback();
20690
+ }
20691
+ exports.LX.makeCollapsible(collapsible, collapsibleContent, null, { collapsed: options.collapsed ?? false });
20692
+ this.setDomTarget(this._lastDomTarget);
20693
+ delete this._lastDomTarget;
20694
+ return collapsible;
20695
+ }
20696
+ const header = document.createElement(type);
20697
+ header.className = options.className ?? '';
20562
20698
  header.innerHTML = string;
20563
20699
  if (id)
20564
20700
  header.id = id;
20565
20701
  this.root.appendChild(header);
20702
+ return header;
20566
20703
  }
20567
- paragraph(string, sup = false, className) {
20704
+ paragraph(string, sup = false, className = '') {
20568
20705
  console.assert(string !== undefined);
20569
20706
  let paragraph = document.createElement(sup ? 'sup' : 'p');
20570
- paragraph.className = 'leading-relaxed ' + (className ?? '');
20707
+ paragraph.className = exports.LX.mergeClass('leading-relaxed', className);
20571
20708
  paragraph.innerHTML = string;
20572
20709
  this.root.appendChild(paragraph);
20710
+ return paragraph;
20573
20711
  }
20574
20712
  code(text, language = 'js') {
20575
20713
  console.assert(text !== undefined);
@@ -20582,11 +20720,11 @@
20582
20720
  };
20583
20721
  for (let i = 0; i < text.length; ++i) {
20584
20722
  const char = text[i];
20585
- const string = text.substr(i);
20723
+ const string = text.substring(i);
20586
20724
  const endLineIdx = string.indexOf('\n');
20587
20725
  const line = string.substring(0, endLineIdx > -1 ? endLineIdx : undefined);
20588
20726
  if (char == '@') {
20589
- const str = line.substr(1);
20727
+ const str = line.substring(1);
20590
20728
  if (!(str.indexOf('@') > -1) && !(str.indexOf('[') > -1)) {
20591
20729
  continue;
20592
20730
  }
@@ -20595,7 +20733,7 @@
20595
20733
  const skipTag = str[tagIndex - 1] == '|';
20596
20734
  // Highlight is specified
20597
20735
  if (text[i + 1] == '[') {
20598
- highlight = str.substr(1, 3);
20736
+ highlight = str.substring(1, 4);
20599
20737
  content = str.substring(5, tagIndex);
20600
20738
  if (skipTag) {
20601
20739
  const newString = str.substring(6 + content.length);
@@ -20668,12 +20806,14 @@
20668
20806
  pre.appendChild(code);
20669
20807
  container.appendChild(pre);
20670
20808
  this.root.appendChild(container);
20809
+ return container;
20671
20810
  }
20672
- list(list, type, target) {
20811
+ list(list, type, target, className = '') {
20673
20812
  const validTypes = ['bullet', 'numbered'];
20674
20813
  console.assert(list && list.length > 0 && validTypes.includes(type), 'Invalid list type or empty list' + type);
20675
20814
  const typeString = type == 'bullet' ? 'ul' : 'ol';
20676
20815
  let ul = document.createElement(typeString);
20816
+ ul.className = className;
20677
20817
  target = target ?? this.root;
20678
20818
  target.appendChild(ul);
20679
20819
  for (var el of list) {
@@ -20686,16 +20826,18 @@
20686
20826
  li.innerHTML = el;
20687
20827
  ul.appendChild(li);
20688
20828
  }
20829
+ return ul;
20689
20830
  }
20690
20831
  bulletList(list) {
20691
- this.list(list, 'bullet');
20832
+ return this.list(list, 'bullet');
20692
20833
  }
20693
20834
  numberedList(list) {
20694
- this.list(list, 'numbered');
20835
+ return this.list(list, 'numbered');
20695
20836
  }
20696
20837
  startCodeBulletList() {
20697
20838
  let ul = document.createElement('ul');
20698
20839
  this._listQueued = ul;
20840
+ return ul;
20699
20841
  }
20700
20842
  endCodeBulletList() {
20701
20843
  if (this._listQueued === undefined)
@@ -20732,35 +20874,34 @@
20732
20874
  else {
20733
20875
  this.root.appendChild(ul);
20734
20876
  }
20877
+ return ul;
20735
20878
  }
20736
- image(src, caption = '', parent) {
20879
+ image(src, caption = '', parent, className = '') {
20737
20880
  let img = document.createElement('img');
20738
20881
  img.src = src;
20739
20882
  img.alt = caption;
20740
- img.className = 'my-1';
20883
+ img.className = exports.LX.mergeClass('my-1', className);
20741
20884
  parent = parent ?? this.root;
20742
20885
  parent.appendChild(img);
20886
+ return img;
20743
20887
  }
20744
20888
  images(sources, captions = [], width, height) {
20745
20889
  const mobile = navigator && /Android|iPhone/i.test(navigator.userAgent);
20890
+ const div = document.createElement('div');
20746
20891
  if (!mobile) {
20747
- let div = document.createElement('div');
20748
20892
  div.style.width = width ?? 'auto';
20749
20893
  div.style.height = height ?? '256px';
20750
20894
  div.className = 'flex flex-row justify-center';
20751
- for (let i = 0; i < sources.length; ++i) {
20752
- this.image(sources[i], captions[i], div);
20753
- }
20754
- this.root.appendChild(div);
20755
20895
  }
20756
- else {
20757
- for (let i = 0; i < sources.length; ++i) {
20758
- this.image(sources[i], captions[i]);
20759
- }
20896
+ for (let i = 0; i < sources.length; ++i) {
20897
+ this.image(sources[i], captions[i], div);
20760
20898
  }
20899
+ this.root.appendChild(div);
20900
+ return div;
20761
20901
  }
20762
- video(src, caption = '', controls = true, autoplay = false) {
20902
+ video(src, caption = '', controls = true, autoplay = false, className = '') {
20763
20903
  let video = document.createElement('video');
20904
+ video.className = className;
20764
20905
  video.src = src;
20765
20906
  video.controls = controls;
20766
20907
  video.autoplay = autoplay;
@@ -20770,17 +20911,18 @@
20770
20911
  video.loop = true;
20771
20912
  video.alt = caption;
20772
20913
  this.root.appendChild(video);
20914
+ return video;
20773
20915
  }
20774
- note(text, warning = false, title, icon) {
20916
+ note(text, warning = false, title, icon, className = '') {
20775
20917
  console.assert(text !== undefined);
20776
- const note = exports.LX.makeContainer([], 'border-color rounded-xl overflow-hidden text-sm text-secondary-foreground my-6', '', this.root);
20777
- let header = document.createElement('div');
20918
+ const note = exports.LX.makeContainer([], exports.LX.mergeClass('border-color rounded-xl overflow-hidden text-sm text-secondary-foreground my-6', className), '', this.root);
20919
+ const header = document.createElement('div');
20778
20920
  header.className = 'flex bg-muted font-semibold px-3 py-2 gap-2 text-secondary-foreground';
20779
20921
  header.appendChild(exports.LX.makeIcon(icon ?? (warning ? 'MessageSquareWarning' : 'NotepadText')));
20780
20922
  header.innerHTML += title ?? (warning ? 'Important' : 'Note');
20781
20923
  note.appendChild(header);
20782
20924
  // Node body
20783
- exports.LX.makeContainer([], 'leading-6 p-3', text, note);
20925
+ return exports.LX.makeContainer([], 'leading-6 p-3', text, note);
20784
20926
  }
20785
20927
  classCtor(name, params, language = 'js') {
20786
20928
  let paramsHTML = '';
@@ -20799,6 +20941,7 @@
20799
20941
  let pr = document.createElement('p');
20800
20942
  pr.innerHTML = this.iCode("<span class='constructor'>" + name + '(' + paramsHTML + ')' + '</span>');
20801
20943
  this.root.appendChild(pr);
20944
+ return pr;
20802
20945
  }
20803
20946
  classMethod(name, desc, params, ret) {
20804
20947
  this.startCodeBulletList();