lexgui 8.3.2 → 8.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/components/BaseComponent.d.ts +4 -2
- package/build/components/Empty.d.ts +8 -0
- package/build/core/Namespace.js +1 -1
- package/build/core/Namespace.js.map +1 -1
- package/build/core/Panel.d.ts +14 -7
- package/build/extensions/AssetView.d.ts +3 -2
- package/build/extensions/AssetView.js +37 -19
- package/build/extensions/AssetView.js.map +1 -1
- package/build/extensions/CodeEditor.d.ts +11 -2
- package/build/extensions/CodeEditor.js +214 -40
- package/build/extensions/CodeEditor.js.map +1 -1
- package/build/lexgui.all.js +420 -77
- package/build/lexgui.all.js.map +1 -1
- package/build/lexgui.all.min.js +1 -1
- package/build/lexgui.all.module.js +420 -77
- package/build/lexgui.all.module.js.map +1 -1
- package/build/lexgui.all.module.min.js +1 -1
- package/build/lexgui.css +38 -2
- package/build/lexgui.js +383 -58
- package/build/lexgui.js.map +1 -1
- package/build/lexgui.min.css +1 -1
- package/build/lexgui.min.js +1 -1
- package/build/lexgui.module.js +383 -58
- package/build/lexgui.module.js.map +1 -1
- package/build/lexgui.module.min.js +1 -1
- package/changelog.md +28 -1
- package/examples/all-components.html +1 -0
- package/examples/asset-view.html +7 -33
- package/examples/code-editor.html +8 -0
- package/package.json +1 -1
package/build/lexgui.all.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
exports.LX = g$2.LX;
|
|
17
17
|
if (!exports.LX) {
|
|
18
18
|
exports.LX = {
|
|
19
|
-
version: '8.
|
|
19
|
+
version: '8.4.1',
|
|
20
20
|
ready: false,
|
|
21
21
|
extensions: [], // Store extensions used
|
|
22
22
|
extraCommandbarEntries: [], // User specific entries for command bar
|
|
@@ -436,6 +436,8 @@
|
|
|
436
436
|
ComponentType[ComponentType["LABEL"] = 39] = "LABEL";
|
|
437
437
|
ComponentType[ComponentType["BLANK"] = 40] = "BLANK";
|
|
438
438
|
ComponentType[ComponentType["RATE"] = 41] = "RATE";
|
|
439
|
+
ComponentType[ComponentType["EMPTY"] = 42] = "EMPTY";
|
|
440
|
+
ComponentType[ComponentType["DESCRIPTION"] = 43] = "DESCRIPTION";
|
|
439
441
|
})(exports.ComponentType || (exports.ComponentType = {}));
|
|
440
442
|
exports.LX.ComponentType = exports.ComponentType;
|
|
441
443
|
/**
|
|
@@ -737,6 +739,9 @@
|
|
|
737
739
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
738
740
|
wValue.style.width = `calc( 100% - ${realNameWidth})`;
|
|
739
741
|
};
|
|
742
|
+
this.onSetDisabled = (disabled) => {
|
|
743
|
+
wValue.disabled = disabled;
|
|
744
|
+
};
|
|
740
745
|
// In case of swap, set if a change has to be performed
|
|
741
746
|
this.setState = function (v, skipCallback) {
|
|
742
747
|
const swapInput = wValue.querySelector('input');
|
|
@@ -1474,6 +1479,12 @@
|
|
|
1474
1479
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
1475
1480
|
container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
|
|
1476
1481
|
};
|
|
1482
|
+
this.onSetDisabled = (disabled) => {
|
|
1483
|
+
vecinput.disabled = disabled;
|
|
1484
|
+
const slider = this.root.querySelector('input[type="range"]');
|
|
1485
|
+
if (slider)
|
|
1486
|
+
slider.disabled = disabled;
|
|
1487
|
+
};
|
|
1477
1488
|
this.setLimits = (newMin, newMax, newStep) => { };
|
|
1478
1489
|
var container = document.createElement('div');
|
|
1479
1490
|
container.className = 'lexnumber';
|
|
@@ -1504,7 +1515,7 @@
|
|
|
1504
1515
|
if (!options.skipSlider && options.min !== undefined && options.max !== undefined) {
|
|
1505
1516
|
let sliderBox = exports.LX.makeContainer(['100%', 'auto'], 'z-1 input-box', '', box);
|
|
1506
1517
|
let slider = document.createElement('input');
|
|
1507
|
-
slider.className = 'lexinputslider';
|
|
1518
|
+
slider.className = 'lexinputslider disabled:pointer-events-none disabled:opacity-50';
|
|
1508
1519
|
slider.min = options.min;
|
|
1509
1520
|
slider.max = options.max;
|
|
1510
1521
|
slider.step = options.step ?? 1;
|
|
@@ -1641,6 +1652,11 @@
|
|
|
1641
1652
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
1642
1653
|
container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
|
|
1643
1654
|
};
|
|
1655
|
+
this.onSetDisabled = (disabled) => {
|
|
1656
|
+
const input = this.root.querySelector('input');
|
|
1657
|
+
if (input)
|
|
1658
|
+
input.disabled = disabled;
|
|
1659
|
+
};
|
|
1644
1660
|
this.valid = (v, matchField) => {
|
|
1645
1661
|
v = v ?? this.value();
|
|
1646
1662
|
if (!options.pattern)
|
|
@@ -1800,6 +1816,9 @@
|
|
|
1800
1816
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
1801
1817
|
container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
|
|
1802
1818
|
};
|
|
1819
|
+
this.onSetDisabled = (disabled) => {
|
|
1820
|
+
selectedOption?.setDisabled(disabled);
|
|
1821
|
+
};
|
|
1803
1822
|
let container = document.createElement('div');
|
|
1804
1823
|
container.className = 'lexselect';
|
|
1805
1824
|
this.root.appendChild(container);
|
|
@@ -2074,6 +2093,13 @@
|
|
|
2074
2093
|
this._trigger(new IEvent$1(name, values, event), callback);
|
|
2075
2094
|
}
|
|
2076
2095
|
};
|
|
2096
|
+
this.onSetDisabled = (disabled) => {
|
|
2097
|
+
if (this.root.dataset['opened'] == 'true' && disabled) {
|
|
2098
|
+
this.root.dataset['opened'] = false;
|
|
2099
|
+
this.root.querySelector('.lexarrayitems').toggleAttribute('hidden', true);
|
|
2100
|
+
}
|
|
2101
|
+
toggleButton.setDisabled(disabled);
|
|
2102
|
+
};
|
|
2077
2103
|
// Add open array button
|
|
2078
2104
|
let container = document.createElement('div');
|
|
2079
2105
|
container.className = 'lexarray shrink-1 grow-1 ml-4';
|
|
@@ -2165,9 +2191,10 @@
|
|
|
2165
2191
|
const container = exports.LX.makeContainer(['100%', 'auto'], 'lexcard max-w-sm flex flex-col gap-4 bg-card border-color rounded-xl py-6', '', this.root);
|
|
2166
2192
|
if (options.header) {
|
|
2167
2193
|
const hasAction = options.header.action !== undefined;
|
|
2194
|
+
const actionButtonOptions = options.header.action.options ?? {};
|
|
2168
2195
|
let header = exports.LX.makeContainer(['100%', 'auto'], `flex ${hasAction ? 'flex-row gap-4' : 'flex-col gap-1'} px-6`, '', container);
|
|
2169
2196
|
if (hasAction) {
|
|
2170
|
-
const actionBtn = new Button(null, options.header.action.name, options.header.action.callback, { buttonClass: 'secondary' });
|
|
2197
|
+
const actionBtn = new Button(null, options.header.action.name, options.header.action.callback, { buttonClass: 'secondary', ...actionButtonOptions });
|
|
2171
2198
|
header.appendChild(actionBtn.root);
|
|
2172
2199
|
const titleDescBox = exports.LX.makeContainer(['75%', 'auto'], `flex flex-col gap-1`, '');
|
|
2173
2200
|
header.prepend(titleDescBox);
|
|
@@ -2234,6 +2261,9 @@
|
|
|
2234
2261
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
2235
2262
|
container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
|
|
2236
2263
|
};
|
|
2264
|
+
this.onSetDisabled = (disabled) => {
|
|
2265
|
+
checkbox.disabled = disabled;
|
|
2266
|
+
};
|
|
2237
2267
|
let container = document.createElement('div');
|
|
2238
2268
|
container.className = 'flex items-center gap-2 my-0 mx-auto [&_span]:truncate [&_span]:flex-auto-fill';
|
|
2239
2269
|
this.root.appendChild(container);
|
|
@@ -2862,7 +2892,12 @@
|
|
|
2862
2892
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
2863
2893
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
2864
2894
|
};
|
|
2865
|
-
|
|
2895
|
+
this.onSetDisabled = (disabled) => {
|
|
2896
|
+
textComponent.setDisabled(disabled);
|
|
2897
|
+
sampleContainer.classList.toggle('pointer-events-none', disabled);
|
|
2898
|
+
sampleContainer.classList.toggle('opacity-50', disabled);
|
|
2899
|
+
};
|
|
2900
|
+
let container = document.createElement('span');
|
|
2866
2901
|
container.className = 'lexcolor';
|
|
2867
2902
|
this.root.appendChild(container);
|
|
2868
2903
|
this.picker = new ColorPicker(value, {
|
|
@@ -3026,6 +3061,11 @@
|
|
|
3026
3061
|
this._trigger(new IEvent$1(name, newValue, event), callback);
|
|
3027
3062
|
}
|
|
3028
3063
|
};
|
|
3064
|
+
this.onSetDisabled = (disabled) => {
|
|
3065
|
+
substrButton.setDisabled(disabled);
|
|
3066
|
+
addButton.setDisabled(disabled);
|
|
3067
|
+
input.disabled = disabled;
|
|
3068
|
+
};
|
|
3029
3069
|
this.count = value;
|
|
3030
3070
|
const min = options.min ?? 0;
|
|
3031
3071
|
const max = options.max ?? 100;
|
|
@@ -3771,6 +3811,12 @@
|
|
|
3771
3811
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
3772
3812
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
3773
3813
|
};
|
|
3814
|
+
this.onSetDisabled = (disabled) => {
|
|
3815
|
+
const buttons = this.root.querySelectorAll('button');
|
|
3816
|
+
buttons.forEach((b) => {
|
|
3817
|
+
b.disabled = disabled;
|
|
3818
|
+
});
|
|
3819
|
+
};
|
|
3774
3820
|
const container = exports.LX.makeContainer(['auto', 'auto'], 'lexdate flex flex-row');
|
|
3775
3821
|
this.root.appendChild(container);
|
|
3776
3822
|
if (!dateAsRange) {
|
|
@@ -4163,6 +4209,52 @@
|
|
|
4163
4209
|
exports.LX.CanvasDial = CanvasDial;
|
|
4164
4210
|
exports.LX.Dial = Dial;
|
|
4165
4211
|
|
|
4212
|
+
// Empty.ts @jxarco
|
|
4213
|
+
/**
|
|
4214
|
+
* @class Empty
|
|
4215
|
+
* @description Empty Component
|
|
4216
|
+
*/
|
|
4217
|
+
class Empty extends BaseComponent$1 {
|
|
4218
|
+
constructor(name, options = {}) {
|
|
4219
|
+
options.hideName = true;
|
|
4220
|
+
super(exports.ComponentType.EMPTY, name, null, options);
|
|
4221
|
+
this.root.classList.add('place-content-center');
|
|
4222
|
+
const container = exports.LX.makeContainer(['100%', 'auto'], 'lexcard max-w-sm flex flex-col gap-4 bg-card border-color rounded-xl py-6', '', this.root);
|
|
4223
|
+
if (options.header) {
|
|
4224
|
+
let header = exports.LX.makeContainer(['100%', 'auto'], `flex flex-col gap-4 px-6 items-center`, '', container);
|
|
4225
|
+
if (options.header.icon) {
|
|
4226
|
+
const icon = exports.LX.makeIcon(options.header.icon, { iconClass: 'bg-secondary p-2 rounded-lg!', svgClass: 'lg' });
|
|
4227
|
+
header.appendChild(icon);
|
|
4228
|
+
}
|
|
4229
|
+
else if (options.header.avatar) {
|
|
4230
|
+
const avatar = new exports.LX.Avatar(options.header.avatar);
|
|
4231
|
+
header.appendChild(avatar.root);
|
|
4232
|
+
}
|
|
4233
|
+
if (options.header.title) {
|
|
4234
|
+
exports.LX.makeElement('div', 'text-center text-foreground leading-none font-medium', options.header.title, header);
|
|
4235
|
+
}
|
|
4236
|
+
if (options.header.description) {
|
|
4237
|
+
exports.LX.makeElement('div', 'text-sm text-center text-balance text-muted-foreground', options.header.description, header);
|
|
4238
|
+
}
|
|
4239
|
+
}
|
|
4240
|
+
if (options.actions) {
|
|
4241
|
+
const content = exports.LX.makeContainer(['100%', 'auto'], 'flex flex-row gap-1 px-6 justify-center', '', container);
|
|
4242
|
+
for (let a of options.actions) {
|
|
4243
|
+
const action = new exports.LX.Button(null, a.name, a.callback, { buttonClass: "sm outline", ...a.options });
|
|
4244
|
+
content.appendChild(action.root);
|
|
4245
|
+
}
|
|
4246
|
+
}
|
|
4247
|
+
if (options.footer) {
|
|
4248
|
+
const footer = exports.LX.makeContainer(['100%', 'auto'], 'flex flex-col gap-1 px-6', '', container);
|
|
4249
|
+
const elements = [].concat(options.footer);
|
|
4250
|
+
for (let e of elements) {
|
|
4251
|
+
footer.appendChild(e.root ? e.root : e);
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
exports.LX.Empty = Empty;
|
|
4257
|
+
|
|
4166
4258
|
// FileInput.ts @jxarco
|
|
4167
4259
|
/**
|
|
4168
4260
|
* @class FileInput
|
|
@@ -4178,6 +4270,9 @@
|
|
|
4178
4270
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
4179
4271
|
input.style.width = `calc( 100% - ${realNameWidth})`;
|
|
4180
4272
|
};
|
|
4273
|
+
this.onSetDisabled = (disabled) => {
|
|
4274
|
+
input.disabled = disabled;
|
|
4275
|
+
};
|
|
4181
4276
|
// Create hidden input
|
|
4182
4277
|
let input = document.createElement('input');
|
|
4183
4278
|
input.className = 'lexfileinput';
|
|
@@ -4385,6 +4480,9 @@
|
|
|
4385
4480
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
4386
4481
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
4387
4482
|
};
|
|
4483
|
+
this.onSetDisabled = (disabled) => {
|
|
4484
|
+
this.setLayers(value);
|
|
4485
|
+
};
|
|
4388
4486
|
const container = exports.LX.makeElement('div', 'lexlayers grid', '', this.root);
|
|
4389
4487
|
const maxBits = options.maxBits ?? 16;
|
|
4390
4488
|
this.setLayers = (val) => {
|
|
@@ -4461,6 +4559,9 @@
|
|
|
4461
4559
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
4462
4560
|
listContainer.style.width = `calc( 100% - ${realNameWidth})`;
|
|
4463
4561
|
};
|
|
4562
|
+
this.onSetDisabled = (disabled) => {
|
|
4563
|
+
this._updateValues(values);
|
|
4564
|
+
};
|
|
4464
4565
|
this._updateValues = (newValues) => {
|
|
4465
4566
|
values = newValues;
|
|
4466
4567
|
listContainer.innerHTML = '';
|
|
@@ -4928,16 +5029,19 @@
|
|
|
4928
5029
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
4929
5030
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
4930
5031
|
};
|
|
5032
|
+
this.onSetDisabled = (disabled) => {
|
|
5033
|
+
openerButton.setDisabled(disabled);
|
|
5034
|
+
};
|
|
4931
5035
|
var container = document.createElement('div');
|
|
4932
5036
|
container.className = 'lexmap2d';
|
|
4933
5037
|
this.root.appendChild(container);
|
|
4934
5038
|
this.map2d = new CanvasMap2D(points, callback, options);
|
|
4935
|
-
const
|
|
4936
|
-
const
|
|
4937
|
-
this._popover = new Popover(
|
|
5039
|
+
const icon = exports.LX.makeIcon(options.mapIcon ?? 'SquareMousePointer');
|
|
5040
|
+
const openerButton = new Button(null, 'Open Map', () => {
|
|
5041
|
+
this._popover = new Popover(openerButton.root, [this.map2d]);
|
|
4938
5042
|
}, { buttonClass: `outline justify-between`, disabled: this.disabled });
|
|
4939
|
-
|
|
4940
|
-
container.appendChild(
|
|
5043
|
+
openerButton.root.querySelector('button').appendChild(icon);
|
|
5044
|
+
container.appendChild(openerButton.root);
|
|
4941
5045
|
exports.LX.doAsync(this.onResize.bind(this));
|
|
4942
5046
|
}
|
|
4943
5047
|
}
|
|
@@ -5644,6 +5748,9 @@
|
|
|
5644
5748
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
5645
5749
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
5646
5750
|
};
|
|
5751
|
+
this.onSetDisabled = (disabled) => {
|
|
5752
|
+
_refreshInput(value);
|
|
5753
|
+
};
|
|
5647
5754
|
const container = document.createElement('div');
|
|
5648
5755
|
container.className = 'lexotp flex flex-row items-center';
|
|
5649
5756
|
this.root.appendChild(container);
|
|
@@ -5657,7 +5764,7 @@
|
|
|
5657
5764
|
for (let j = 0; j < g.length; ++j) {
|
|
5658
5765
|
let number = valueString[itemsCount++];
|
|
5659
5766
|
number = number == 'x' ? '' : number;
|
|
5660
|
-
const slotDom = exports.LX.makeContainer(['36px', '30px'], 'lexotpslot border-t-color border-b-color border-l-color px-3 cursor-text select-none font-medium outline-none', number, container);
|
|
5767
|
+
const slotDom = exports.LX.makeContainer(['36px', '30px'], 'lexotpslot content-center border-t-color border-b-color border-l-color px-3 cursor-text select-none font-medium outline-none', number, container);
|
|
5661
5768
|
slotDom.tabIndex = '1';
|
|
5662
5769
|
if (this.disabled) {
|
|
5663
5770
|
slotDom.classList.add('disabled');
|
|
@@ -6061,6 +6168,9 @@
|
|
|
6061
6168
|
slider.style.setProperty('--range-fix-max-offset', `${diffMaxOffset}rem`);
|
|
6062
6169
|
}
|
|
6063
6170
|
};
|
|
6171
|
+
this.onSetDisabled = (disabled) => {
|
|
6172
|
+
slider.disabled = disabled;
|
|
6173
|
+
};
|
|
6064
6174
|
const container = document.createElement('div');
|
|
6065
6175
|
container.className = 'lexrange relative py-3';
|
|
6066
6176
|
this.root.appendChild(container);
|
|
@@ -6169,6 +6279,9 @@
|
|
|
6169
6279
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
6170
6280
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
6171
6281
|
};
|
|
6282
|
+
this.onSetDisabled = (disabled) => {
|
|
6283
|
+
container.dataset['disabled'] = disabled.toString();
|
|
6284
|
+
};
|
|
6172
6285
|
const container = document.createElement('div');
|
|
6173
6286
|
container.className = 'lexrate relative data-[disabled=true]:pointer-events-none';
|
|
6174
6287
|
container.dataset['disabled'] = this.disabled.toString();
|
|
@@ -7312,6 +7425,9 @@
|
|
|
7312
7425
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
7313
7426
|
tagsContainer.style.width = `calc( 100% - ${realNameWidth})`;
|
|
7314
7427
|
};
|
|
7428
|
+
this.onSetDisabled = (disabled) => {
|
|
7429
|
+
this.generateTags(arrayValue);
|
|
7430
|
+
};
|
|
7315
7431
|
// Show tags
|
|
7316
7432
|
const tagsContainer = document.createElement('div');
|
|
7317
7433
|
tagsContainer.className = 'inline-flex flex-wrap gap-1 bg-card/50 rounded-lg pad-xs [&_input]:w-2/3';
|
|
@@ -7380,6 +7496,11 @@
|
|
|
7380
7496
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
7381
7497
|
container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
|
|
7382
7498
|
};
|
|
7499
|
+
this.onSetDisabled = (disabled) => {
|
|
7500
|
+
const textarea = this.root.querySelector('textarea');
|
|
7501
|
+
if (textarea)
|
|
7502
|
+
textarea.disabled = disabled;
|
|
7503
|
+
};
|
|
7383
7504
|
let container = document.createElement('div');
|
|
7384
7505
|
container.className = 'lextextarea';
|
|
7385
7506
|
container.style.display = 'flex';
|
|
@@ -7497,6 +7618,9 @@
|
|
|
7497
7618
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
7498
7619
|
container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
|
|
7499
7620
|
};
|
|
7621
|
+
this.onSetDisabled = (disabled) => {
|
|
7622
|
+
toggle.disabled = disabled;
|
|
7623
|
+
};
|
|
7500
7624
|
var container = document.createElement('div');
|
|
7501
7625
|
container.className = 'flex flex-row gap-2 items-center';
|
|
7502
7626
|
this.root.appendChild(container);
|
|
@@ -7566,6 +7690,12 @@
|
|
|
7566
7690
|
const realNameWidth = this.root.domName?.style.width ?? '0px';
|
|
7567
7691
|
container.style.width = `calc( 100% - ${realNameWidth})`;
|
|
7568
7692
|
};
|
|
7693
|
+
this.onSetDisabled = (disabled) => {
|
|
7694
|
+
const inputs = this.root.querySelectorAll('input');
|
|
7695
|
+
inputs.forEach((i) => {
|
|
7696
|
+
i.disabled = disabled;
|
|
7697
|
+
});
|
|
7698
|
+
};
|
|
7569
7699
|
this.setLimits = (newMin, newMax, newStep) => { };
|
|
7570
7700
|
const vectorInputs = [];
|
|
7571
7701
|
var container = document.createElement('div');
|
|
@@ -8310,6 +8440,19 @@
|
|
|
8310
8440
|
component.type = exports.ComponentType.LABEL;
|
|
8311
8441
|
return component;
|
|
8312
8442
|
}
|
|
8443
|
+
/**
|
|
8444
|
+
* @method addDescription
|
|
8445
|
+
* @param {String} value Information string
|
|
8446
|
+
* @param {Object} options Text options
|
|
8447
|
+
*/
|
|
8448
|
+
addDescription(value, options = {}) {
|
|
8449
|
+
options.disabled = true;
|
|
8450
|
+
options.fitHeight = true;
|
|
8451
|
+
options.inputClass = exports.LX.mergeClass('bg-none', options.inputClass);
|
|
8452
|
+
const component = this.addTextArea(null, value, null, options);
|
|
8453
|
+
component.type = exports.ComponentType.DESCRIPTION;
|
|
8454
|
+
return component;
|
|
8455
|
+
}
|
|
8313
8456
|
/**
|
|
8314
8457
|
* @method addButton
|
|
8315
8458
|
* @param {String} name Component name
|
|
@@ -8348,18 +8491,22 @@
|
|
|
8348
8491
|
}
|
|
8349
8492
|
/**
|
|
8350
8493
|
* @method addCard
|
|
8351
|
-
* @param {String} name
|
|
8352
|
-
* @param {Object} options
|
|
8353
|
-
* text: Card text
|
|
8354
|
-
* link: Card link
|
|
8355
|
-
* title: Card dom title
|
|
8356
|
-
* src: url of the image
|
|
8357
|
-
* callback (Function): function to call on click
|
|
8494
|
+
* @param {String} name
|
|
8495
|
+
* @param {Object} options
|
|
8358
8496
|
*/
|
|
8359
8497
|
addCard(name, options = {}) {
|
|
8360
8498
|
const component = new Card(name, options);
|
|
8361
8499
|
return this._attachComponent(component);
|
|
8362
8500
|
}
|
|
8501
|
+
/**
|
|
8502
|
+
* @method addEmpty
|
|
8503
|
+
* @param {String} name
|
|
8504
|
+
* @param {Object} options
|
|
8505
|
+
*/
|
|
8506
|
+
addEmpty(name, options = {}) {
|
|
8507
|
+
const component = new Empty(name, options);
|
|
8508
|
+
return this._attachComponent(component);
|
|
8509
|
+
}
|
|
8363
8510
|
/**
|
|
8364
8511
|
* @method addForm
|
|
8365
8512
|
* @param {String} name Component name
|
|
@@ -11174,6 +11321,8 @@
|
|
|
11174
11321
|
// Watch for trigger being removed from the DOM before mouseleave fires
|
|
11175
11322
|
rafId = requestAnimationFrame(_watchConnection);
|
|
11176
11323
|
exports.LX.doAsync(() => {
|
|
11324
|
+
if (!tooltipDom)
|
|
11325
|
+
return;
|
|
11177
11326
|
const position = [0, 0];
|
|
11178
11327
|
const offsetX = parseFloat(trigger.dataset['tooltipOffsetX'] ?? _offsetX);
|
|
11179
11328
|
const offsetY = parseFloat(trigger.dataset['tooltipOffsetY'] ?? _offsetY);
|
|
@@ -13339,7 +13488,9 @@
|
|
|
13339
13488
|
// using a fullscreen SVG with "rect" elements
|
|
13340
13489
|
_generateMask(reference) {
|
|
13341
13490
|
this.tourContainer.innerHTML = ''; // Clear previous content
|
|
13491
|
+
const scrollTop = document.scrollingElement?.scrollTop ?? 0;
|
|
13342
13492
|
this.tourMask = exports.LX.makeContainer(['100%', '100%'], 'tour-mask absolute inset-0');
|
|
13493
|
+
this.tourMask.style.top = `${scrollTop}px`;
|
|
13343
13494
|
this.tourContainer.appendChild(this.tourMask);
|
|
13344
13495
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
13345
13496
|
svg.style.width = '100%';
|
|
@@ -13402,7 +13553,7 @@
|
|
|
13402
13553
|
// Reference Highlight
|
|
13403
13554
|
const refContainer = exports.LX.makeContainer(['0', '0'], 'tour-ref-mask absolute');
|
|
13404
13555
|
refContainer.style.left = `${boundingX - hOffset - 1}px`;
|
|
13405
|
-
refContainer.style.top = `${boundingY - vOffset - 1}px`;
|
|
13556
|
+
refContainer.style.top = `${boundingY - vOffset - 1 + scrollTop}px`;
|
|
13406
13557
|
refContainer.style.width = `${boundingWidth + hOffset * 2 + 2}px`;
|
|
13407
13558
|
refContainer.style.height = `${boundingHeight + vOffset * 2 + 2}px`;
|
|
13408
13559
|
this.tourContainer.appendChild(refContainer);
|
|
@@ -14447,12 +14598,12 @@
|
|
|
14447
14598
|
getText(separator = '\n') {
|
|
14448
14599
|
return this._lines.join(separator);
|
|
14449
14600
|
}
|
|
14450
|
-
setText(text) {
|
|
14601
|
+
setText(text, silent = false) {
|
|
14451
14602
|
this._lines = text.split(/\r?\n/);
|
|
14452
14603
|
if (this._lines.length === 0) {
|
|
14453
14604
|
this._lines = [''];
|
|
14454
14605
|
}
|
|
14455
|
-
if (this.onChange)
|
|
14606
|
+
if (!silent && this.onChange)
|
|
14456
14607
|
this.onChange(this);
|
|
14457
14608
|
}
|
|
14458
14609
|
getCharAt(line, col) {
|
|
@@ -14616,6 +14767,7 @@
|
|
|
14616
14767
|
_lastPushTime = 0;
|
|
14617
14768
|
_groupThresholdMs;
|
|
14618
14769
|
_maxSteps;
|
|
14770
|
+
_savedDepth = 0;
|
|
14619
14771
|
constructor(groupThresholdMs = 2000, maxSteps = 200) {
|
|
14620
14772
|
this._groupThresholdMs = groupThresholdMs;
|
|
14621
14773
|
this._maxSteps = maxSteps;
|
|
@@ -14687,11 +14839,19 @@
|
|
|
14687
14839
|
canRedo() {
|
|
14688
14840
|
return this._redoStack.length > 0;
|
|
14689
14841
|
}
|
|
14842
|
+
markSaved() {
|
|
14843
|
+
this._flush();
|
|
14844
|
+
this._savedDepth = this._undoStack.length;
|
|
14845
|
+
}
|
|
14846
|
+
isModified() {
|
|
14847
|
+
return this._undoStack.length !== this._savedDepth || this._pendingOps.length > 0;
|
|
14848
|
+
}
|
|
14690
14849
|
clear() {
|
|
14691
14850
|
this._undoStack.length = 0;
|
|
14692
14851
|
this._redoStack.length = 0;
|
|
14693
14852
|
this._pendingOps.length = 0;
|
|
14694
14853
|
this._lastPushTime = 0;
|
|
14854
|
+
this._savedDepth = 0;
|
|
14695
14855
|
}
|
|
14696
14856
|
_flush() {
|
|
14697
14857
|
if (this._pendingOps.length === 0)
|
|
@@ -15260,8 +15420,36 @@
|
|
|
15260
15420
|
exports.LX.Panel;
|
|
15261
15421
|
exports.LX.Tabs;
|
|
15262
15422
|
exports.LX.NodeTree;
|
|
15263
|
-
/** Matches hex color literals: #rgb #rgba #rrggbb #rrggbbaa */
|
|
15264
15423
|
const HEX_COLOR_RE = /#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})\b/g;
|
|
15424
|
+
const URL_REGEX = /(https?:\/\/[^\s"'<>)\]]+)/g;
|
|
15425
|
+
/**
|
|
15426
|
+
* Returns true if the string token at `idx` in the token list is a module import path.
|
|
15427
|
+
*/
|
|
15428
|
+
function isImportPath(tokens, idx) {
|
|
15429
|
+
const isWs = (t) => /^\s+$/.test(t.value);
|
|
15430
|
+
const isImportWord = (t) => t.value === 'require' || t.value === 'import';
|
|
15431
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
15432
|
+
const t = tokens[i];
|
|
15433
|
+
if (isWs(t))
|
|
15434
|
+
continue;
|
|
15435
|
+
if (t.type === 'keyword' && t.value === 'from')
|
|
15436
|
+
return true;
|
|
15437
|
+
if (isImportWord(t))
|
|
15438
|
+
return true;
|
|
15439
|
+
if (t.type === 'symbol' && t.value === '(') {
|
|
15440
|
+
for (let j = i - 1; j >= 0; j--) {
|
|
15441
|
+
const t2 = tokens[j];
|
|
15442
|
+
if (isWs(t2))
|
|
15443
|
+
continue;
|
|
15444
|
+
if (isImportWord(t2))
|
|
15445
|
+
return true;
|
|
15446
|
+
break;
|
|
15447
|
+
}
|
|
15448
|
+
}
|
|
15449
|
+
break;
|
|
15450
|
+
}
|
|
15451
|
+
return false;
|
|
15452
|
+
}
|
|
15265
15453
|
/**
|
|
15266
15454
|
* Scans a raw token value for hex color literals and returns HTML with each
|
|
15267
15455
|
* color wrapped in a swatch span. Non-color text is HTML-escaped.
|
|
@@ -15304,6 +15492,15 @@
|
|
|
15304
15492
|
this.thumb = exports.LX.makeElement('div');
|
|
15305
15493
|
this.thumb.addEventListener('mousedown', (e) => this._onMouseDown(e));
|
|
15306
15494
|
this.root.appendChild(this.thumb);
|
|
15495
|
+
this.root.addEventListener('mousedown', (e) => {
|
|
15496
|
+
if (e.target === this.thumb)
|
|
15497
|
+
return;
|
|
15498
|
+
const clickPos = this._vertical ? e.offsetY : e.offsetX;
|
|
15499
|
+
const thumbSize = this._vertical ? this.thumb.offsetHeight : this.thumb.offsetWidth;
|
|
15500
|
+
const delta = (clickPos - thumbSize / 2) - this._thumbPos;
|
|
15501
|
+
this._onDrag?.(delta);
|
|
15502
|
+
this._onMouseDown(e); // continue as drag from new position
|
|
15503
|
+
});
|
|
15307
15504
|
}
|
|
15308
15505
|
setThumbRatio(ratio) {
|
|
15309
15506
|
this._thumbRatio = exports.LX.clamp(ratio, 0, 1);
|
|
@@ -15427,6 +15624,7 @@
|
|
|
15427
15624
|
onReady;
|
|
15428
15625
|
onCreateFile;
|
|
15429
15626
|
onCodeChange;
|
|
15627
|
+
onOpenPath;
|
|
15430
15628
|
onHoverSymbol;
|
|
15431
15629
|
_inputArea;
|
|
15432
15630
|
// State:
|
|
@@ -15507,6 +15705,7 @@
|
|
|
15507
15705
|
this.onSelectTab = options.onSelectTab;
|
|
15508
15706
|
this.onReady = options.onReady;
|
|
15509
15707
|
this.onCodeChange = options.onCodeChange;
|
|
15708
|
+
this.onOpenPath = options.onOpenPath;
|
|
15510
15709
|
this.onHoverSymbol = options.onHoverSymbol;
|
|
15511
15710
|
this.language = Tokenizer.getLanguage(this.highlight) ?? Tokenizer.getLanguage('Plain Text');
|
|
15512
15711
|
this.symbolTable = new SymbolTable();
|
|
@@ -15717,19 +15916,31 @@
|
|
|
15717
15916
|
this.codeArea.root.addEventListener('mousedown', this._onMouseDown.bind(this));
|
|
15718
15917
|
this.codeArea.root.addEventListener('contextmenu', this._onMouseDown.bind(this));
|
|
15719
15918
|
this.codeArea.root.addEventListener('mouseover', (e) => {
|
|
15720
|
-
const
|
|
15919
|
+
const target = e.target;
|
|
15920
|
+
const link = target.closest('.code-link');
|
|
15721
15921
|
if (link && e.ctrlKey)
|
|
15722
15922
|
link.classList.add('hovered');
|
|
15923
|
+
const path = target.closest('.code-path');
|
|
15924
|
+
if (path && e.ctrlKey)
|
|
15925
|
+
path.classList.add('hovered');
|
|
15723
15926
|
});
|
|
15724
15927
|
this.codeArea.root.addEventListener('mouseout', (e) => {
|
|
15725
|
-
const
|
|
15928
|
+
const target = e.target;
|
|
15929
|
+
const link = target.closest('.code-link');
|
|
15726
15930
|
if (link)
|
|
15727
15931
|
link.classList.remove('hovered');
|
|
15932
|
+
const path = target.closest('.code-path');
|
|
15933
|
+
if (path)
|
|
15934
|
+
path.classList.remove('hovered');
|
|
15728
15935
|
});
|
|
15729
15936
|
this.codeArea.root.addEventListener('mousemove', (e) => {
|
|
15730
|
-
const
|
|
15937
|
+
const target = e.target;
|
|
15938
|
+
const link = target.closest('.code-link');
|
|
15731
15939
|
if (link)
|
|
15732
15940
|
link.classList.toggle('hovered', e.ctrlKey);
|
|
15941
|
+
const path = target.closest('.code-path');
|
|
15942
|
+
if (path)
|
|
15943
|
+
path.classList.toggle('hovered', e.ctrlKey);
|
|
15733
15944
|
this._onCodeAreaMouseMove(e);
|
|
15734
15945
|
});
|
|
15735
15946
|
this.codeArea.root.addEventListener('mouseleave', () => {
|
|
@@ -15828,7 +16039,7 @@
|
|
|
15828
16039
|
setText(text, language, detectLang = false) {
|
|
15829
16040
|
if (!this.currentTab)
|
|
15830
16041
|
return;
|
|
15831
|
-
this.doc.setText(this._normalizeText(text));
|
|
16042
|
+
this.doc.setText(this._normalizeText(text), true);
|
|
15832
16043
|
this.cursorSet.set(0, 0);
|
|
15833
16044
|
this.undoManager.clear();
|
|
15834
16045
|
this._lineStates = [];
|
|
@@ -16019,10 +16230,14 @@
|
|
|
16019
16230
|
const codeTab = {
|
|
16020
16231
|
name,
|
|
16021
16232
|
dom,
|
|
16022
|
-
doc: new CodeDocument(
|
|
16233
|
+
doc: new CodeDocument((doc) => {
|
|
16234
|
+
this._setTabModified(name, true);
|
|
16235
|
+
this.onCodeChange?.(doc);
|
|
16236
|
+
}),
|
|
16023
16237
|
cursorSet: new CursorSet(),
|
|
16024
16238
|
undoManager: new UndoManager(),
|
|
16025
16239
|
language: langName,
|
|
16240
|
+
modified: false,
|
|
16026
16241
|
title: options.title ?? name
|
|
16027
16242
|
};
|
|
16028
16243
|
this._openedTabs[name] = codeTab;
|
|
@@ -16046,7 +16261,7 @@
|
|
|
16046
16261
|
// Move into the sizer..
|
|
16047
16262
|
this.codeSizer.appendChild(dom);
|
|
16048
16263
|
if (options.text) {
|
|
16049
|
-
codeTab.doc.setText(options.text);
|
|
16264
|
+
codeTab.doc.setText(options.text, true);
|
|
16050
16265
|
codeTab.cursorSet.set(0, 0);
|
|
16051
16266
|
codeTab.undoManager.clear();
|
|
16052
16267
|
this._renderAllLines();
|
|
@@ -16137,7 +16352,7 @@
|
|
|
16137
16352
|
title: options.title ?? name,
|
|
16138
16353
|
language: langName
|
|
16139
16354
|
});
|
|
16140
|
-
this.doc.setText(text);
|
|
16355
|
+
this.doc.setText(text, true);
|
|
16141
16356
|
this.setLanguage(langName, ext);
|
|
16142
16357
|
this.cursorSet.set(0, 0);
|
|
16143
16358
|
this.undoManager.clear();
|
|
@@ -16198,7 +16413,7 @@
|
|
|
16198
16413
|
language: langName
|
|
16199
16414
|
});
|
|
16200
16415
|
if (results.length === 0) {
|
|
16201
|
-
this.doc.setText(processedText);
|
|
16416
|
+
this.doc.setText(processedText, true);
|
|
16202
16417
|
this.setLanguage(langName, ext);
|
|
16203
16418
|
this.cursorSet.set(0, 0);
|
|
16204
16419
|
this.undoManager.clear();
|
|
@@ -16240,6 +16455,30 @@
|
|
|
16240
16455
|
}
|
|
16241
16456
|
}, 20);
|
|
16242
16457
|
}
|
|
16458
|
+
_findTabByPath(importPath) {
|
|
16459
|
+
// By now only uses base name
|
|
16460
|
+
const importBase = importPath.split('/').pop().replace(/\.\w+$/, '').toLowerCase();
|
|
16461
|
+
const allNames = new Set([
|
|
16462
|
+
...Object.keys(this._openedTabs),
|
|
16463
|
+
...Object.keys(this._loadedTabs),
|
|
16464
|
+
...Object.keys(this._storedTabs),
|
|
16465
|
+
]);
|
|
16466
|
+
for (const name of allNames) {
|
|
16467
|
+
const tabBase = name.split('/').pop().replace(/\.\w+$/, '').toLowerCase();
|
|
16468
|
+
if (tabBase === importBase)
|
|
16469
|
+
return name;
|
|
16470
|
+
}
|
|
16471
|
+
return null;
|
|
16472
|
+
}
|
|
16473
|
+
_setTabModified(name, modified) {
|
|
16474
|
+
const tab = this._openedTabs[name];
|
|
16475
|
+
if (!tab || tab.modified === modified)
|
|
16476
|
+
return;
|
|
16477
|
+
tab.modified = modified;
|
|
16478
|
+
const tabEl = this.tabs?.tabDOMs?.[name];
|
|
16479
|
+
if (tabEl)
|
|
16480
|
+
tabEl.toggleAttribute('data-modified', modified);
|
|
16481
|
+
}
|
|
16243
16482
|
_onSelectTab(isNewTabButton, event, name) {
|
|
16244
16483
|
if (this.disableEdition) {
|
|
16245
16484
|
return;
|
|
@@ -16465,7 +16704,6 @@
|
|
|
16465
16704
|
const lineText = this.doc.getLine(lineIndex);
|
|
16466
16705
|
const result = Tokenizer.tokenizeLine(lineText, this.language, prevState);
|
|
16467
16706
|
const langClass = this.language.name.toLowerCase().replace(/[^a-z]/g, '');
|
|
16468
|
-
const URL_REGEX = /(https?:\/\/[^\s"'<>)\]]+)/g;
|
|
16469
16707
|
// Pre-compute which token index gets the bracket-highlight class
|
|
16470
16708
|
let bracketTokenIdx = -1;
|
|
16471
16709
|
if (lineIndex === this._bracketOpenLine) {
|
|
@@ -16493,15 +16731,20 @@
|
|
|
16493
16731
|
const cls = TOKEN_CLASS_MAP[token.type];
|
|
16494
16732
|
const tokenCol = colOffset;
|
|
16495
16733
|
colOffset += token.value.length;
|
|
16734
|
+
// Inject content depending on type of token: color, url, path?
|
|
16496
16735
|
let content;
|
|
16497
16736
|
if (token.type === 'comment') {
|
|
16498
|
-
// Escape then inject clickable URL spans
|
|
16499
16737
|
const escaped = token.value
|
|
16500
16738
|
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
16501
16739
|
content = escaped.replace(URL_REGEX, `<span class="code-link" data-url="$1">$1</span>`);
|
|
16502
16740
|
}
|
|
16741
|
+
else if (token.type === 'string' && isImportPath(result.tokens, ti)) {
|
|
16742
|
+
const inner = token.value.slice(1, -1); // strip surrounding quotes
|
|
16743
|
+
const q = token.value[0];
|
|
16744
|
+
const escapedInner = inner.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
16745
|
+
content = `${q}<span class="code-path" data-path="${inner}">${escapedInner}</span>${q}`;
|
|
16746
|
+
}
|
|
16503
16747
|
else {
|
|
16504
|
-
// Escape and inject color swatches for hex color strings
|
|
16505
16748
|
content = injectColorSpans(token.value, lineIndex, tokenCol);
|
|
16506
16749
|
}
|
|
16507
16750
|
const bracketClass = ti === bracketTokenIdx ? ' code-bracket-active' : '';
|
|
@@ -16771,6 +17014,8 @@
|
|
|
16771
17014
|
e.preventDefault();
|
|
16772
17015
|
if (this.onSave) {
|
|
16773
17016
|
this.onSave(this.getText(), this);
|
|
17017
|
+
this.undoManager.markSaved();
|
|
17018
|
+
this._setTabModified(this.currentTab.name, false);
|
|
16774
17019
|
}
|
|
16775
17020
|
return;
|
|
16776
17021
|
case 'z':
|
|
@@ -16793,6 +17038,17 @@
|
|
|
16793
17038
|
e.preventDefault();
|
|
16794
17039
|
this._doPaste();
|
|
16795
17040
|
return;
|
|
17041
|
+
case 'home':
|
|
17042
|
+
e.preventDefault();
|
|
17043
|
+
this.cursorSet.set(0, 0);
|
|
17044
|
+
this._afterCursorMove();
|
|
17045
|
+
return;
|
|
17046
|
+
case 'end':
|
|
17047
|
+
e.preventDefault();
|
|
17048
|
+
const lastLine = this.doc.lineCount - 1;
|
|
17049
|
+
this.cursorSet.set(lastLine, this.doc.getLine(lastLine).length);
|
|
17050
|
+
this._afterCursorMove();
|
|
17051
|
+
return;
|
|
16796
17052
|
case ' ':
|
|
16797
17053
|
e.preventDefault();
|
|
16798
17054
|
// Also call user callback if provided
|
|
@@ -17565,6 +17821,8 @@
|
|
|
17565
17821
|
}
|
|
17566
17822
|
this._rebuildLines();
|
|
17567
17823
|
this._afterCursorMove();
|
|
17824
|
+
if (this.currentTab)
|
|
17825
|
+
this._setTabModified(this.currentTab.name, this.undoManager.isModified());
|
|
17568
17826
|
}
|
|
17569
17827
|
}
|
|
17570
17828
|
_doRedo() {
|
|
@@ -17576,6 +17834,8 @@
|
|
|
17576
17834
|
}
|
|
17577
17835
|
this._rebuildLines();
|
|
17578
17836
|
this._afterCursorMove();
|
|
17837
|
+
if (this.currentTab)
|
|
17838
|
+
this._setTabModified(this.currentTab.name, this.undoManager.isModified());
|
|
17579
17839
|
}
|
|
17580
17840
|
}
|
|
17581
17841
|
// Mouse input events:
|
|
@@ -17586,7 +17846,7 @@
|
|
|
17586
17846
|
return;
|
|
17587
17847
|
if (this.autocomplete && this.autocomplete.contains(e.target))
|
|
17588
17848
|
return;
|
|
17589
|
-
// Ctrl+click: open link
|
|
17849
|
+
// Ctrl+click: open link or import path
|
|
17590
17850
|
if (e.ctrlKey && e.button === 0) {
|
|
17591
17851
|
const target = e.target;
|
|
17592
17852
|
const link = target.closest('.code-link');
|
|
@@ -17594,6 +17854,15 @@
|
|
|
17594
17854
|
window.open(link.dataset.url, '_blank');
|
|
17595
17855
|
return;
|
|
17596
17856
|
}
|
|
17857
|
+
const pathEl = target.closest('.code-path');
|
|
17858
|
+
if (pathEl?.dataset.path) {
|
|
17859
|
+
const rawPath = pathEl.dataset.path;
|
|
17860
|
+
const tabName = this._findTabByPath(rawPath);
|
|
17861
|
+
if (tabName)
|
|
17862
|
+
this.loadTab(tabName);
|
|
17863
|
+
this.onOpenPath?.(rawPath, this);
|
|
17864
|
+
return;
|
|
17865
|
+
}
|
|
17597
17866
|
}
|
|
17598
17867
|
e.preventDefault(); // Prevent browser from stealing focus from _inputArea
|
|
17599
17868
|
this._wasPaired = false;
|
|
@@ -17641,18 +17910,55 @@
|
|
|
17641
17910
|
}
|
|
17642
17911
|
this._afterCursorMove();
|
|
17643
17912
|
this._inputArea.focus();
|
|
17644
|
-
// Track mouse for drag selection
|
|
17645
|
-
|
|
17646
|
-
|
|
17647
|
-
|
|
17648
|
-
|
|
17649
|
-
const
|
|
17913
|
+
// Track mouse for drag selection (with auto-scroll when outside editor window/area)
|
|
17914
|
+
let lastMouseX = 0;
|
|
17915
|
+
let lastMouseY = 0;
|
|
17916
|
+
let rafId = null;
|
|
17917
|
+
const updateSelection = () => {
|
|
17918
|
+
const currentRect = this.codeContainer.getBoundingClientRect();
|
|
17919
|
+
const mx = lastMouseX - currentRect.left - this.xPadding;
|
|
17920
|
+
const my = lastMouseY - currentRect.top;
|
|
17921
|
+
const ml = exports.LX.clamp(Math.floor(my / this.lineHeight), 0, this.doc.lineCount - 1);
|
|
17922
|
+
const mc = exports.LX.clamp(Math.round(mx / this.charWidth), 0, this.doc.getLine(ml).length);
|
|
17650
17923
|
const sel = this.cursorSet.getPrimary();
|
|
17651
17924
|
sel.head = { line: ml, col: mc };
|
|
17652
17925
|
this._renderCursors();
|
|
17653
17926
|
this._renderSelections();
|
|
17654
17927
|
};
|
|
17928
|
+
const autoScroll = () => {
|
|
17929
|
+
const scrollerRect = this.codeScroller.getBoundingClientRect();
|
|
17930
|
+
const overshootY = lastMouseY < scrollerRect.top ? lastMouseY - scrollerRect.top
|
|
17931
|
+
: lastMouseY > scrollerRect.bottom ? lastMouseY - scrollerRect.bottom : 0;
|
|
17932
|
+
const overshootX = lastMouseX < scrollerRect.left ? lastMouseX - scrollerRect.left
|
|
17933
|
+
: lastMouseX > scrollerRect.right ? lastMouseX - scrollerRect.right : 0;
|
|
17934
|
+
if (overshootY === 0 && overshootX === 0) {
|
|
17935
|
+
rafId = null;
|
|
17936
|
+
return;
|
|
17937
|
+
}
|
|
17938
|
+
const speedY = Math.sign(overshootY) * Math.min(Math.abs(overshootY) * 0.3, 15);
|
|
17939
|
+
const speedX = Math.sign(overshootX) * Math.min(Math.abs(overshootX) * 0.3, 15);
|
|
17940
|
+
this.codeScroller.scrollTop += speedY;
|
|
17941
|
+
this.codeScroller.scrollLeft += speedX;
|
|
17942
|
+
this._syncScrollBars();
|
|
17943
|
+
updateSelection();
|
|
17944
|
+
rafId = requestAnimationFrame(autoScroll);
|
|
17945
|
+
};
|
|
17946
|
+
const onMouseMove = (me) => {
|
|
17947
|
+
lastMouseX = me.clientX;
|
|
17948
|
+
lastMouseY = me.clientY;
|
|
17949
|
+
updateSelection();
|
|
17950
|
+
const scrollerRect = this.codeScroller.getBoundingClientRect();
|
|
17951
|
+
const isOutside = me.clientY < scrollerRect.top || me.clientY > scrollerRect.bottom
|
|
17952
|
+
|| me.clientX < scrollerRect.left || me.clientX > scrollerRect.right;
|
|
17953
|
+
if (isOutside && rafId === null) {
|
|
17954
|
+
rafId = requestAnimationFrame(autoScroll);
|
|
17955
|
+
}
|
|
17956
|
+
};
|
|
17655
17957
|
const onMouseUp = () => {
|
|
17958
|
+
if (rafId !== null) {
|
|
17959
|
+
cancelAnimationFrame(rafId);
|
|
17960
|
+
rafId = null;
|
|
17961
|
+
}
|
|
17656
17962
|
document.removeEventListener('mousemove', onMouseMove);
|
|
17657
17963
|
document.removeEventListener('mouseup', onMouseUp);
|
|
17658
17964
|
};
|
|
@@ -17713,7 +18019,10 @@
|
|
|
17713
18019
|
const suggestions = [];
|
|
17714
18020
|
const added = new Set();
|
|
17715
18021
|
const addSuggestion = (s) => {
|
|
17716
|
-
if (
|
|
18022
|
+
if (added.has(s.label)) {
|
|
18023
|
+
suggestions[suggestions.findIndex(x => x.label === s.label)] = s;
|
|
18024
|
+
}
|
|
18025
|
+
else {
|
|
17717
18026
|
suggestions.push(s);
|
|
17718
18027
|
added.add(s.label);
|
|
17719
18028
|
}
|
|
@@ -17726,9 +18035,12 @@
|
|
|
17726
18035
|
return suggestion.label.toLowerCase().startsWith(w);
|
|
17727
18036
|
};
|
|
17728
18037
|
// Get first suggestions from symbol table
|
|
18038
|
+
const _skipKinds = new Set(['constructor-call', 'method-call']);
|
|
17729
18039
|
const allSymbols = this.symbolTable.getAllSymbols();
|
|
17730
18040
|
for (const symbol of allSymbols) {
|
|
17731
|
-
|
|
18041
|
+
if (_skipKinds.has(symbol.kind))
|
|
18042
|
+
continue;
|
|
18043
|
+
const s = { label: symbol.name, kind: symbol.kind, scope: symbol.scope };
|
|
17732
18044
|
if (filterSuggestion(s, word))
|
|
17733
18045
|
addSuggestion(s);
|
|
17734
18046
|
}
|
|
@@ -17762,7 +18074,7 @@
|
|
|
17762
18074
|
// Render suggestions
|
|
17763
18075
|
suggestions.forEach((suggestion, index) => {
|
|
17764
18076
|
const item = document.createElement('pre');
|
|
17765
|
-
item.
|
|
18077
|
+
item.suggestionData = suggestion;
|
|
17766
18078
|
if (index === this._selectedAutocompleteIndex)
|
|
17767
18079
|
item.classList.add('selected');
|
|
17768
18080
|
const currSuggestionLabel = suggestion.label;
|
|
@@ -17791,11 +18103,15 @@
|
|
|
17791
18103
|
break;
|
|
17792
18104
|
case 'type':
|
|
17793
18105
|
iconName = 'Type';
|
|
17794
|
-
iconClass = 'text-
|
|
18106
|
+
iconClass = 'text-purple-500';
|
|
17795
18107
|
break;
|
|
17796
18108
|
case 'function':
|
|
17797
18109
|
iconName = 'Function';
|
|
17798
|
-
iconClass = 'text-
|
|
18110
|
+
iconClass = 'text-teal-500';
|
|
18111
|
+
break;
|
|
18112
|
+
case 'constant':
|
|
18113
|
+
iconName = 'Pi';
|
|
18114
|
+
iconClass = 'text-rose-600';
|
|
17799
18115
|
break;
|
|
17800
18116
|
case 'method':
|
|
17801
18117
|
iconName = 'Box';
|
|
@@ -17809,14 +18125,6 @@
|
|
|
17809
18125
|
iconName = 'Layers';
|
|
17810
18126
|
iconClass = 'text-blue-300';
|
|
17811
18127
|
break;
|
|
17812
|
-
case 'constructor-call':
|
|
17813
|
-
iconName = 'Hammer';
|
|
17814
|
-
iconClass = 'text-green-500';
|
|
17815
|
-
break;
|
|
17816
|
-
case 'method-call':
|
|
17817
|
-
iconName = 'Parentheses';
|
|
17818
|
-
iconClass = 'text-gray-400';
|
|
17819
|
-
break;
|
|
17820
18128
|
}
|
|
17821
18129
|
item.appendChild(exports.LX.makeIcon(iconName, { iconClass: 'ml-1 mr-2', svgClass: 'sm ' + iconClass }));
|
|
17822
18130
|
// Highlight the written part
|
|
@@ -17831,7 +18139,13 @@
|
|
|
17831
18139
|
var postWord = document.createElement('span');
|
|
17832
18140
|
postWord.textContent = currSuggestionLabel.substring(hIndex + word.length);
|
|
17833
18141
|
item.appendChild(postWord);
|
|
17834
|
-
if (suggestion.
|
|
18142
|
+
if (suggestion.detail) {
|
|
18143
|
+
const detail = document.createElement('span');
|
|
18144
|
+
detail.textContent = ` ${suggestion.detail}`;
|
|
18145
|
+
detail.className = 'kind text-muted-foreground text-xs! ml-2';
|
|
18146
|
+
item.appendChild(detail);
|
|
18147
|
+
}
|
|
18148
|
+
else if (suggestion.kind) {
|
|
17835
18149
|
const kind = document.createElement('span');
|
|
17836
18150
|
kind.textContent = ` (${suggestion.kind})`;
|
|
17837
18151
|
kind.className = 'kind text-muted-foreground text-xs! ml-2';
|
|
@@ -17877,9 +18191,12 @@
|
|
|
17877
18191
|
* Insert the selected autocomplete word at cursor.
|
|
17878
18192
|
*/
|
|
17879
18193
|
_doAutocompleteWord() {
|
|
17880
|
-
const
|
|
17881
|
-
if (!
|
|
18194
|
+
const suggestion = this._getSelectedAutoCompleteSuggestion();
|
|
18195
|
+
if (!suggestion)
|
|
17882
18196
|
return;
|
|
18197
|
+
const text = suggestion.insertText ?? suggestion.label;
|
|
18198
|
+
const cursorOffset = suggestion.cursorOffset; // only valid in single line autocomplete
|
|
18199
|
+
const selectLength = suggestion.selectLength;
|
|
17883
18200
|
const cursor = this.cursorSet.getPrimary().head;
|
|
17884
18201
|
const { start, end } = this._getWordAtCursor();
|
|
17885
18202
|
const line = cursor.line;
|
|
@@ -17891,7 +18208,13 @@
|
|
|
17891
18208
|
const insertOp = this.doc.insert(line, start, text);
|
|
17892
18209
|
const insertedLines = text.split(/\r?\n/);
|
|
17893
18210
|
if (insertedLines.length === 1) {
|
|
17894
|
-
|
|
18211
|
+
const cursorCol = start + (cursorOffset ?? text.length);
|
|
18212
|
+
this.cursorSet.set(line, cursorCol);
|
|
18213
|
+
if (selectLength) {
|
|
18214
|
+
const sel = this.cursorSet.getPrimary();
|
|
18215
|
+
sel.anchor = { line, col: cursorCol };
|
|
18216
|
+
sel.head = { line, col: cursorCol + selectLength };
|
|
18217
|
+
}
|
|
17895
18218
|
}
|
|
17896
18219
|
else {
|
|
17897
18220
|
this.cursorSet.set(line + insertedLines.length - 1, insertedLines[insertedLines.length - 1].length);
|
|
@@ -17902,11 +18225,11 @@
|
|
|
17902
18225
|
this._afterCursorMove();
|
|
17903
18226
|
this._doHideAutocomplete();
|
|
17904
18227
|
}
|
|
17905
|
-
|
|
18228
|
+
_getSelectedAutoCompleteSuggestion() {
|
|
17906
18229
|
if (!this.autocomplete || !this._isAutoCompleteActive)
|
|
17907
18230
|
return null;
|
|
17908
18231
|
const pre = this.autocomplete.childNodes[this._selectedAutocompleteIndex];
|
|
17909
|
-
return pre.
|
|
18232
|
+
return pre.suggestionData;
|
|
17910
18233
|
}
|
|
17911
18234
|
_afterCursorMove() {
|
|
17912
18235
|
this._renderCursors();
|
|
@@ -18147,6 +18470,8 @@
|
|
|
18147
18470
|
this._hoverWord = '';
|
|
18148
18471
|
}
|
|
18149
18472
|
_onCodeAreaMouseMove(e) {
|
|
18473
|
+
if (!this.currentTab)
|
|
18474
|
+
return;
|
|
18150
18475
|
// Only show hover when no button is pressed (no dragging)
|
|
18151
18476
|
if (e.buttons !== 0) {
|
|
18152
18477
|
this._clearHoverPopup();
|
|
@@ -19325,7 +19650,7 @@
|
|
|
19325
19650
|
}
|
|
19326
19651
|
}
|
|
19327
19652
|
else if (isFolder) {
|
|
19328
|
-
that.
|
|
19653
|
+
that._requestEnterFolder(item);
|
|
19329
19654
|
return;
|
|
19330
19655
|
}
|
|
19331
19656
|
const onSelect = that._callbacks['select'];
|
|
@@ -19543,17 +19868,17 @@
|
|
|
19543
19868
|
if (!this.prevData.length || !this.currentFolder)
|
|
19544
19869
|
return;
|
|
19545
19870
|
this.nextData.push(this.currentFolder);
|
|
19546
|
-
this._enterFolder(this.prevData.pop(), false);
|
|
19871
|
+
this._enterFolder(this.prevData.pop(), false, true);
|
|
19547
19872
|
}, { buttonClass: 'ghost', title: 'Go Back', tooltip: true, icon: 'ArrowLeft' });
|
|
19548
19873
|
panel.addButton(null, 'GoForwardButton', () => {
|
|
19549
19874
|
if (!this.nextData.length || !this.currentFolder)
|
|
19550
19875
|
return;
|
|
19551
|
-
this._enterFolder(this.nextData.pop());
|
|
19876
|
+
this._enterFolder(this.nextData.pop(), false, true);
|
|
19552
19877
|
}, { buttonClass: 'ghost', title: 'Go Forward', tooltip: true, icon: 'ArrowRight' });
|
|
19553
19878
|
panel.addButton(null, 'GoUpButton', () => {
|
|
19554
19879
|
const parentFolder = this.currentFolder?.parent;
|
|
19555
19880
|
if (parentFolder)
|
|
19556
|
-
this._enterFolder(parentFolder);
|
|
19881
|
+
this._enterFolder(parentFolder, false, true);
|
|
19557
19882
|
}, { buttonClass: 'ghost', title: 'Go Upper Folder', tooltip: true, icon: 'ArrowUp' });
|
|
19558
19883
|
panel.addButton(null, 'RefreshButton', () => {
|
|
19559
19884
|
this._refreshContent(undefined, undefined, true);
|
|
@@ -19593,7 +19918,7 @@
|
|
|
19593
19918
|
this._updatePath();
|
|
19594
19919
|
}
|
|
19595
19920
|
else {
|
|
19596
|
-
this.
|
|
19921
|
+
this._requestEnterFolder(node.type === 'folder' ? node : node.parent);
|
|
19597
19922
|
this._previewAsset(node);
|
|
19598
19923
|
if (node.type !== 'folder') {
|
|
19599
19924
|
this.content.querySelectorAll('.lexassetitem').forEach((i) => i.classList.remove('selected'));
|
|
@@ -19965,12 +20290,41 @@
|
|
|
19965
20290
|
this.toolsPanel.refresh();
|
|
19966
20291
|
this._refreshContent();
|
|
19967
20292
|
}
|
|
19968
|
-
|
|
20293
|
+
_requestEnterFolder(folderItem, storeCurrent = true) {
|
|
20294
|
+
if (!folderItem) {
|
|
20295
|
+
return;
|
|
20296
|
+
}
|
|
20297
|
+
const onBeforeEnterFolder = this._callbacks['beforeEnterFolder'];
|
|
20298
|
+
const onEnterFolder = this._callbacks['enterFolder'];
|
|
20299
|
+
const resolve = (...args) => {
|
|
20300
|
+
const child = this.currentData[0];
|
|
20301
|
+
const sameFolder = child?.parent?.metadata?.uid === folderItem.metadata?.uid;
|
|
20302
|
+
const mustRefresh = args[0] || !sameFolder;
|
|
20303
|
+
this._enterFolder(folderItem, storeCurrent, mustRefresh);
|
|
20304
|
+
const event = {
|
|
20305
|
+
type: 'enter-folder',
|
|
20306
|
+
to: folderItem,
|
|
20307
|
+
userInitiated: true
|
|
20308
|
+
};
|
|
20309
|
+
if (onEnterFolder)
|
|
20310
|
+
onEnterFolder(event, ...args);
|
|
20311
|
+
};
|
|
20312
|
+
if (onBeforeEnterFolder) {
|
|
20313
|
+
const event = {
|
|
20314
|
+
type: 'enter-folder',
|
|
20315
|
+
to: folderItem,
|
|
20316
|
+
userInitiated: true
|
|
20317
|
+
};
|
|
20318
|
+
onBeforeEnterFolder(event, resolve);
|
|
20319
|
+
}
|
|
20320
|
+
else {
|
|
20321
|
+
resolve();
|
|
20322
|
+
}
|
|
20323
|
+
}
|
|
20324
|
+
_enterFolder(folderItem, storeCurrent, mustRefresh) {
|
|
19969
20325
|
if (!folderItem) {
|
|
19970
20326
|
return;
|
|
19971
20327
|
}
|
|
19972
|
-
const child = this.currentData[0];
|
|
19973
|
-
const sameFolder = child?.parent?.metadata?.uid === folderItem.metadata?.uid;
|
|
19974
20328
|
if (storeCurrent) {
|
|
19975
20329
|
this.prevData.push(this.currentFolder ?? {
|
|
19976
20330
|
id: '/',
|
|
@@ -19979,17 +20333,6 @@
|
|
|
19979
20333
|
metadata: {}
|
|
19980
20334
|
});
|
|
19981
20335
|
}
|
|
19982
|
-
let mustRefresh = !sameFolder;
|
|
19983
|
-
const onEnterFolder = this._callbacks['enterFolder'];
|
|
19984
|
-
if (onEnterFolder !== undefined) {
|
|
19985
|
-
const event = {
|
|
19986
|
-
type: 'enter_folder',
|
|
19987
|
-
to: folderItem,
|
|
19988
|
-
userInitiated: true
|
|
19989
|
-
};
|
|
19990
|
-
const r = await onEnterFolder(event);
|
|
19991
|
-
mustRefresh = mustRefresh || r;
|
|
19992
|
-
}
|
|
19993
20336
|
// Update this after the event since the user might have added or modified the data
|
|
19994
20337
|
this.currentFolder = folderItem;
|
|
19995
20338
|
this.currentData = this.currentFolder?.children ?? [];
|