perfect-gui 5.1.3 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +30 -0
- package/dist/perfect-gui.js +454 -585
- package/package.json +5 -3
- package/src/components/{Button.js → Button.ts} +26 -12
- package/src/components/Color.ts +93 -0
- package/src/components/{Image.js → Image.ts} +40 -25
- package/src/components/List.ts +173 -0
- package/src/components/{Slider.js → Slider.ts} +78 -77
- package/src/components/Toggle.ts +98 -0
- package/src/components/{Vector2.js → Vector2.ts} +47 -36
- package/src/{index.js → index.ts} +287 -142
- package/src/plugins/three.js +2 -8
- package/tsconfig.json +111 -0
- package/src/components/Color.js +0 -107
- package/src/components/List.js +0 -178
- package/src/components/Toggle.js +0 -124
|
@@ -1,62 +1,159 @@
|
|
|
1
|
-
import Button from './components/Button
|
|
2
|
-
import Slider from './components/Slider
|
|
3
|
-
import Image from './components/Image
|
|
4
|
-
import Toggle from './components/Toggle
|
|
5
|
-
import List from './components/List
|
|
1
|
+
import Button from './components/Button';
|
|
2
|
+
import Slider from './components/Slider';
|
|
3
|
+
import Image from './components/Image';
|
|
4
|
+
import Toggle from './components/Toggle';
|
|
5
|
+
import List from './components/List';
|
|
6
6
|
import Color from './components/Color.js';
|
|
7
|
-
import Vector2 from './components/Vector2
|
|
7
|
+
import Vector2 from './components/Vector2';
|
|
8
8
|
import styles from './styles/styles.js';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import type { Options as SliderOptions } from './components/Slider';
|
|
11
|
+
import type { Options as ButtonOptions } from './components/Button';
|
|
12
|
+
import type { Options as ImageOptions } from './components/Image';
|
|
13
|
+
import type { Options as ToggleOptions } from './components/Toggle';
|
|
14
|
+
import type { Options as ListOptions, Values as ListValues } from './components/List';
|
|
15
|
+
import type { Options as ColorOptions } from './components/Color';
|
|
16
|
+
import type { Options as Vector2Options } from './components/Vector2';
|
|
17
|
+
|
|
18
|
+
declare global {
|
|
19
|
+
interface Window {
|
|
20
|
+
perfectGUI?: {
|
|
21
|
+
instanceCounter?: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
type FolderOptions = {
|
|
27
|
+
container: HTMLElement;
|
|
28
|
+
wrapper: HTMLElement;
|
|
29
|
+
parent: GUI;
|
|
30
|
+
firstParent: GUI;
|
|
31
|
+
closed: boolean;
|
|
32
|
+
label: string;
|
|
33
|
+
color: string;
|
|
34
|
+
maxHeight: number;
|
|
35
|
+
}
|
|
24
36
|
|
|
25
|
-
|
|
37
|
+
type Options = {
|
|
38
|
+
label?: string;
|
|
39
|
+
container?: HTMLElement | string;
|
|
40
|
+
isFolder?: boolean;
|
|
41
|
+
folderOptions?: FolderOptions;
|
|
42
|
+
onUpdate?: () => void;
|
|
43
|
+
color?: string;
|
|
44
|
+
opacity?: number;
|
|
45
|
+
position?: string;
|
|
46
|
+
maxHeight?: number;
|
|
47
|
+
width?: number;
|
|
48
|
+
closed?: boolean;
|
|
49
|
+
draggable?: boolean;
|
|
50
|
+
autoRepositioning?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type ScreenCorner = {
|
|
54
|
+
x: 'left' | 'right';
|
|
55
|
+
y: 'top' | 'bottom';
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default class GUI {
|
|
59
|
+
public firstParent: GUI;
|
|
60
|
+
private container: HTMLElement = document.body;
|
|
61
|
+
public wrapper!: HTMLElement;
|
|
62
|
+
public folders: GUI[];
|
|
63
|
+
private tabsArray: any[];
|
|
64
|
+
private label: string = '';
|
|
65
|
+
private backgroundColor: string | null = null;
|
|
66
|
+
private opacity: number = 1;
|
|
67
|
+
private maxHeight: number = window.innerHeight;
|
|
68
|
+
private initMaxHeight: number | null = null;
|
|
69
|
+
private screenCorner!: ScreenCorner;
|
|
70
|
+
private instanceId: number = 0;
|
|
71
|
+
private wrapperWidth: number = 290;
|
|
72
|
+
private stylesheet: HTMLStyleElement | null = null;
|
|
73
|
+
private closed: boolean = false;
|
|
74
|
+
public domElement: HTMLElement | null = null;
|
|
75
|
+
private hasBeenDragged: boolean = false;
|
|
76
|
+
private xOffset: number = 0;
|
|
77
|
+
private yOffset: number = 0;
|
|
78
|
+
private position = {
|
|
79
|
+
initX: 0,
|
|
80
|
+
initY: 0,
|
|
81
|
+
prevX: 0,
|
|
82
|
+
prevY: 0,
|
|
83
|
+
x: 0,
|
|
84
|
+
y: 0,
|
|
85
|
+
};
|
|
86
|
+
// folder properties
|
|
87
|
+
public isFolder: boolean = false;
|
|
88
|
+
public parent: GUI | null = null;
|
|
89
|
+
public imageContainer: HTMLElement | null = null;
|
|
90
|
+
public header!: HTMLElement;
|
|
91
|
+
public previousInnerScroll: number = 0;
|
|
92
|
+
|
|
93
|
+
// tab-related properties added dynamically
|
|
94
|
+
public getTab?: (index: number) => GUI | null;
|
|
95
|
+
public getTabElement?: (index: number) => HTMLElement | null;
|
|
96
|
+
public setActiveTab?: (index: number) => void;
|
|
97
|
+
public getActiveTab?: () => number;
|
|
98
|
+
public element?: HTMLElement;
|
|
99
|
+
|
|
100
|
+
public propReferences: any[];
|
|
101
|
+
public onUpdate: (() => void) | null = null;
|
|
102
|
+
|
|
103
|
+
constructor(options: Options = {}, isFolder = false) {
|
|
104
|
+
this.firstParent = this;
|
|
26
105
|
this.folders = [];
|
|
27
106
|
this.tabsArray = [];
|
|
107
|
+
this.propReferences = [];
|
|
28
108
|
|
|
29
109
|
if (options.isFolder) {
|
|
30
110
|
this._folderConstructor(options.folderOptions);
|
|
31
111
|
return;
|
|
32
112
|
}
|
|
33
113
|
|
|
34
|
-
if (
|
|
35
|
-
|
|
114
|
+
if (isFolder) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let positionType: 'absolute' | 'fixed' = 'fixed';
|
|
119
|
+
|
|
120
|
+
if (options.container) {
|
|
121
|
+
const container =
|
|
122
|
+
typeof options.container == 'string'
|
|
123
|
+
? document.querySelector(options.container)
|
|
124
|
+
: options.container;
|
|
125
|
+
if (container instanceof HTMLElement) {
|
|
126
|
+
this.container = container;
|
|
127
|
+
positionType = 'absolute';
|
|
128
|
+
}
|
|
36
129
|
}
|
|
130
|
+
|
|
131
|
+
this.screenCorner = this._parseScreenCorner(options.position);
|
|
37
132
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
133
|
+
if (options.width) {
|
|
134
|
+
this.wrapperWidth = options.width;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (typeof options.onUpdate === 'function') {
|
|
138
|
+
this.onUpdate = options.onUpdate;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.label = typeof options.label == 'string' ? options.label : '';
|
|
42
142
|
this.backgroundColor = options.color || null;
|
|
43
143
|
this.opacity = options.opacity || 1;
|
|
44
|
-
|
|
45
|
-
if (this.container
|
|
46
|
-
this.maxHeight = window.innerHeight;
|
|
47
|
-
} else {
|
|
144
|
+
|
|
145
|
+
if (this.container && this.container !== document.body) {
|
|
48
146
|
this.maxHeight = Math.min(
|
|
49
147
|
this.container.clientHeight,
|
|
50
148
|
window.innerHeight,
|
|
51
149
|
);
|
|
52
150
|
}
|
|
151
|
+
|
|
53
152
|
if (options.maxHeight) {
|
|
54
153
|
this.initMaxHeight = options.maxHeight;
|
|
55
154
|
this.maxHeight = Math.min(this.initMaxHeight, this.maxHeight);
|
|
56
155
|
}
|
|
57
156
|
|
|
58
|
-
this.screenCorner = this._parseScreenCorner(options.position);
|
|
59
|
-
|
|
60
157
|
if (!window.perfectGUI) {
|
|
61
158
|
window.perfectGUI = {};
|
|
62
159
|
}
|
|
@@ -67,7 +164,6 @@ export default class GUI {
|
|
|
67
164
|
}
|
|
68
165
|
this.instanceId = window.perfectGUI.instanceCounter;
|
|
69
166
|
|
|
70
|
-
this.wrapperWidth = options.width || 290;
|
|
71
167
|
this.stylesheet = document.createElement('style');
|
|
72
168
|
this.stylesheet.setAttribute('type', 'text/css');
|
|
73
169
|
this.stylesheet.setAttribute('id', 'lm-gui-stylesheet');
|
|
@@ -75,14 +171,17 @@ export default class GUI {
|
|
|
75
171
|
|
|
76
172
|
// Common styles
|
|
77
173
|
if (this.instanceId == 0) {
|
|
78
|
-
this._addStyles(`${styles(
|
|
174
|
+
this._addStyles(`${styles(positionType)}`);
|
|
79
175
|
}
|
|
80
176
|
|
|
81
177
|
// Instance specific styles
|
|
82
178
|
this._styleInstance();
|
|
83
179
|
|
|
84
180
|
this.closed = !!options.closed;
|
|
85
|
-
|
|
181
|
+
|
|
182
|
+
const [domElement, wrapper] = this._addWrapper();
|
|
183
|
+
this.domElement = domElement;
|
|
184
|
+
this.wrapper = wrapper;
|
|
86
185
|
this.domElement.setAttribute('data-corner-x', this.screenCorner.x);
|
|
87
186
|
this.domElement.setAttribute('data-corner-y', this.screenCorner.y);
|
|
88
187
|
|
|
@@ -91,8 +190,9 @@ export default class GUI {
|
|
|
91
190
|
}
|
|
92
191
|
this._handleResize();
|
|
93
192
|
|
|
94
|
-
|
|
95
|
-
|
|
193
|
+
if (options.draggable == true) {
|
|
194
|
+
this._makeDraggable();
|
|
195
|
+
}
|
|
96
196
|
}
|
|
97
197
|
|
|
98
198
|
_styleInstance() {
|
|
@@ -108,7 +208,8 @@ export default class GUI {
|
|
|
108
208
|
|
|
109
209
|
if (this.instanceId > 0) {
|
|
110
210
|
let existingDomInstances =
|
|
111
|
-
this.container.querySelectorAll('.p-gui');
|
|
211
|
+
this.container.querySelectorAll<HTMLElement>('.p-gui');
|
|
212
|
+
|
|
112
213
|
for (let i = 0; i < existingDomInstances.length; i++) {
|
|
113
214
|
if (
|
|
114
215
|
this.screenCorner.y ==
|
|
@@ -130,6 +231,8 @@ export default class GUI {
|
|
|
130
231
|
}
|
|
131
232
|
this.yOffset = 0;
|
|
132
233
|
this.position = {
|
|
234
|
+
initX: this.xOffset,
|
|
235
|
+
initY: this.yOffset,
|
|
133
236
|
prevX: this.xOffset,
|
|
134
237
|
prevY: this.yOffset,
|
|
135
238
|
x: this.xOffset,
|
|
@@ -146,18 +249,24 @@ export default class GUI {
|
|
|
146
249
|
}`);
|
|
147
250
|
}
|
|
148
251
|
|
|
149
|
-
_folderConstructor(folderOptions) {
|
|
150
|
-
|
|
252
|
+
_folderConstructor(folderOptions: FolderOptions | undefined) {
|
|
253
|
+
if (!folderOptions) {
|
|
254
|
+
throw Error('[perfect-gui] folderOptions is undefined');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.domElement = folderOptions.container;
|
|
151
258
|
this.isFolder = true;
|
|
152
259
|
this.parent = folderOptions.parent;
|
|
153
260
|
this.firstParent = folderOptions.firstParent;
|
|
154
|
-
this.wrapper = folderOptions.
|
|
261
|
+
this.wrapper = folderOptions.wrapper;
|
|
155
262
|
}
|
|
156
263
|
|
|
157
|
-
_parseScreenCorner(position) {
|
|
158
|
-
let parsedPosition = { x: 'right', y: 'top' };
|
|
264
|
+
_parseScreenCorner(position: string | undefined): ScreenCorner {
|
|
265
|
+
let parsedPosition: ScreenCorner = { x: 'right', y: 'top' };
|
|
159
266
|
|
|
160
|
-
if (position == undefined)
|
|
267
|
+
if (position == undefined) {
|
|
268
|
+
return parsedPosition;
|
|
269
|
+
}
|
|
161
270
|
else if (typeof position != 'string')
|
|
162
271
|
console.error('[perfect-gui] Position must be a string.');
|
|
163
272
|
|
|
@@ -167,7 +276,7 @@ export default class GUI {
|
|
|
167
276
|
return parsedPosition;
|
|
168
277
|
}
|
|
169
278
|
|
|
170
|
-
_getScrollbarWidth(element) {
|
|
279
|
+
_getScrollbarWidth(element: HTMLElement) {
|
|
171
280
|
if (element === document.body) {
|
|
172
281
|
return window.innerWidth - document.documentElement.clientWidth;
|
|
173
282
|
} else {
|
|
@@ -176,6 +285,9 @@ export default class GUI {
|
|
|
176
285
|
}
|
|
177
286
|
|
|
178
287
|
_handleResize() {
|
|
288
|
+
if (!this.domElement) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
179
291
|
if (this.container == document.body) {
|
|
180
292
|
this.maxHeight = window.innerHeight;
|
|
181
293
|
} else {
|
|
@@ -201,7 +313,7 @@ export default class GUI {
|
|
|
201
313
|
this.wrapperWidth -
|
|
202
314
|
scrollbar_width;
|
|
203
315
|
if (this.instanceId > 0) {
|
|
204
|
-
let existingDomInstances = this.container.querySelectorAll(
|
|
316
|
+
let existingDomInstances = this.container.querySelectorAll<HTMLElement>(
|
|
205
317
|
`.p-gui:not(#${this.domElement.id}):not([data-dragged])`,
|
|
206
318
|
);
|
|
207
319
|
for (let i = 0; i < existingDomInstances.length; i++) {
|
|
@@ -228,6 +340,8 @@ export default class GUI {
|
|
|
228
340
|
}
|
|
229
341
|
}
|
|
230
342
|
this.position = {
|
|
343
|
+
initX: this.xOffset,
|
|
344
|
+
initY: this.yOffset,
|
|
231
345
|
prevX: this.xOffset,
|
|
232
346
|
prevY: this.yOffset,
|
|
233
347
|
x: this.xOffset,
|
|
@@ -236,22 +350,25 @@ export default class GUI {
|
|
|
236
350
|
this.domElement.style.transform = `translate3d(${this.position.x}px, ${this.position.y}px, 0)`;
|
|
237
351
|
}
|
|
238
352
|
|
|
239
|
-
_addStyles(styles) {
|
|
240
|
-
this.stylesheet
|
|
353
|
+
_addStyles(styles: string) {
|
|
354
|
+
if (this.stylesheet) {
|
|
355
|
+
this.stylesheet.innerHTML += styles;
|
|
356
|
+
}
|
|
241
357
|
}
|
|
242
358
|
|
|
243
|
-
_addWrapper() {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
359
|
+
_addWrapper(): [HTMLDivElement, HTMLDivElement] {
|
|
360
|
+
const domElement = document.createElement('div');
|
|
361
|
+
domElement.id = 'p-gui-' + this.instanceId;
|
|
362
|
+
domElement.className =
|
|
363
|
+
'p-gui' + (this.closed ? ' p-gui--collapsed' : '');
|
|
364
|
+
domElement.setAttribute('data-lenis-prevent', '');
|
|
365
|
+
this.container.append(domElement);
|
|
249
366
|
|
|
250
367
|
this.header = document.createElement('div');
|
|
251
368
|
this.header.className = 'p-gui__header';
|
|
252
369
|
this.header.textContent = this.label;
|
|
253
370
|
this.header.style = `${this.backgroundColor ? 'border-color: ' + this.backgroundColor + ';' : ''}`;
|
|
254
|
-
|
|
371
|
+
domElement.append(this.header);
|
|
255
372
|
|
|
256
373
|
const close_btn = document.createElement('div');
|
|
257
374
|
close_btn.className = 'p-gui__header-close';
|
|
@@ -260,60 +377,61 @@ export default class GUI {
|
|
|
260
377
|
|
|
261
378
|
const content = document.createElement('div');
|
|
262
379
|
content.className = 'p-gui__content';
|
|
263
|
-
|
|
380
|
+
domElement.append(content);
|
|
381
|
+
|
|
382
|
+
const wrapper = document.createElement('div');
|
|
383
|
+
wrapper.className = 'p-gui__inner';
|
|
384
|
+
content.append(wrapper);
|
|
264
385
|
|
|
265
|
-
|
|
266
|
-
this.wrapper.className = 'p-gui__inner';
|
|
267
|
-
content.append(this.wrapper);
|
|
386
|
+
return [domElement, wrapper];
|
|
268
387
|
}
|
|
269
388
|
|
|
270
|
-
button(
|
|
389
|
+
button(options: ButtonOptions = {}) {
|
|
271
390
|
this.imageContainer = null;
|
|
272
|
-
const instance = new Button(this,
|
|
391
|
+
const instance = new Button(this, options);
|
|
273
392
|
return instance;
|
|
274
393
|
}
|
|
275
394
|
|
|
276
|
-
image(
|
|
395
|
+
image(path: string, options: ImageOptions = {}) {
|
|
277
396
|
if (!this.imageContainer) {
|
|
278
397
|
this.imageContainer = document.createElement('div');
|
|
279
398
|
this.imageContainer.className = 'p-gui__image-container';
|
|
280
399
|
this.wrapper.append(this.imageContainer);
|
|
281
400
|
}
|
|
282
|
-
|
|
283
|
-
return instance;
|
|
401
|
+
return new Image(this, path, options);
|
|
284
402
|
}
|
|
285
403
|
|
|
286
|
-
slider(
|
|
404
|
+
slider(obj: any, prop: string, options: SliderOptions) {
|
|
287
405
|
this.imageContainer = null;
|
|
288
|
-
const instance = new Slider(this,
|
|
406
|
+
const instance = new Slider(this, obj, prop, options);
|
|
289
407
|
return instance;
|
|
290
408
|
}
|
|
291
409
|
|
|
292
|
-
toggle(
|
|
410
|
+
toggle(obj: any, prop: string, options: ToggleOptions) {
|
|
293
411
|
this.imageContainer = null;
|
|
294
|
-
const instance = new Toggle(this,
|
|
412
|
+
const instance = new Toggle(this, obj, prop, options);
|
|
295
413
|
return instance;
|
|
296
414
|
}
|
|
297
415
|
|
|
298
|
-
list(
|
|
416
|
+
list(obj: any, prop: string, values: ListValues, options: ListOptions) {
|
|
299
417
|
this.imageContainer = null;
|
|
300
|
-
const instance = new List(this,
|
|
418
|
+
const instance = new List(this, obj, prop, values, options);
|
|
301
419
|
return instance;
|
|
302
420
|
}
|
|
303
421
|
|
|
304
|
-
color(
|
|
422
|
+
color(obj: any, prop: string, options: ColorOptions) {
|
|
305
423
|
this.imageContainer = null;
|
|
306
|
-
const instance = new Color(this,
|
|
424
|
+
const instance = new Color(this, obj, prop, options);
|
|
307
425
|
return instance;
|
|
308
426
|
}
|
|
309
427
|
|
|
310
|
-
vector2(
|
|
428
|
+
vector2(obj: any, propX: string, propY: string, options: Vector2Options) {
|
|
311
429
|
this.imageContainer = null;
|
|
312
|
-
const instance = new Vector2(this,
|
|
430
|
+
const instance = new Vector2(this, obj, propX, propY, options);
|
|
313
431
|
return instance;
|
|
314
432
|
}
|
|
315
433
|
|
|
316
|
-
folder(options
|
|
434
|
+
folder(options: FolderOptions) {
|
|
317
435
|
let closed =
|
|
318
436
|
typeof options.closed == 'boolean' ? options.closed : false;
|
|
319
437
|
let label = options.label || '';
|
|
@@ -333,7 +451,9 @@ export default class GUI {
|
|
|
333
451
|
}
|
|
334
452
|
|
|
335
453
|
let container_style = color ? `background-color: ${color};` : '';
|
|
336
|
-
container_style += maxHeight
|
|
454
|
+
container_style += maxHeight
|
|
455
|
+
? `max-height: ${maxHeight}px; overflow-y: auto;`
|
|
456
|
+
: '';
|
|
337
457
|
|
|
338
458
|
const container = document.createElement('div');
|
|
339
459
|
container.className = className;
|
|
@@ -357,20 +477,17 @@ export default class GUI {
|
|
|
357
477
|
container.classList.toggle('p-gui__folder--closed');
|
|
358
478
|
});
|
|
359
479
|
|
|
360
|
-
let folder = new
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
parent: this,
|
|
366
|
-
firstParent: this.firstParent,
|
|
367
|
-
},
|
|
480
|
+
let folder = new Folder({
|
|
481
|
+
container,
|
|
482
|
+
wrapper: folderInner,
|
|
483
|
+
parent: this,
|
|
484
|
+
firstParent: this.firstParent,
|
|
368
485
|
});
|
|
369
486
|
this.folders.push(folder);
|
|
370
487
|
return folder;
|
|
371
488
|
}
|
|
372
489
|
|
|
373
|
-
tabs(options = {}) {
|
|
490
|
+
tabs(options: { tabs?: string[]; active?: number; color?: string; maxHeight?: number} = {}) {
|
|
374
491
|
const tabs = Array.isArray(options.tabs) ? options.tabs : [];
|
|
375
492
|
const activeTab = options.active || 0;
|
|
376
493
|
const color = options.color || null;
|
|
@@ -384,7 +501,9 @@ export default class GUI {
|
|
|
384
501
|
}
|
|
385
502
|
|
|
386
503
|
let container_style = color ? `background-color: ${color};` : '';
|
|
387
|
-
container_style += maxHeight
|
|
504
|
+
container_style += maxHeight
|
|
505
|
+
? `max-height: ${maxHeight}px; overflow-y: auto;`
|
|
506
|
+
: '';
|
|
388
507
|
|
|
389
508
|
const container = document.createElement('div');
|
|
390
509
|
container.className = className;
|
|
@@ -402,11 +521,14 @@ export default class GUI {
|
|
|
402
521
|
container.append(tabsContent);
|
|
403
522
|
|
|
404
523
|
// Store tab instances for later access
|
|
405
|
-
const tabInstances = [];
|
|
524
|
+
const tabInstances: { gui: GUI; button: HTMLButtonElement; pane: HTMLElement }[] = [];
|
|
406
525
|
|
|
407
526
|
tabs.forEach((tabConfig, index) => {
|
|
408
|
-
const tabLabel =
|
|
409
|
-
|
|
527
|
+
const tabLabel =
|
|
528
|
+
typeof tabConfig === 'string'
|
|
529
|
+
? tabConfig
|
|
530
|
+
: tabConfig.label || `Tab ${index + 1}`;
|
|
531
|
+
|
|
410
532
|
// Create tab button
|
|
411
533
|
const tabButton = document.createElement('button');
|
|
412
534
|
tabButton.className = 'p-gui__tab-button';
|
|
@@ -425,20 +547,17 @@ export default class GUI {
|
|
|
425
547
|
tabsContent.append(tabPane);
|
|
426
548
|
|
|
427
549
|
// Create GUI instance for this tab
|
|
428
|
-
const tabGUI = new
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
parent: this,
|
|
434
|
-
firstParent: this.firstParent,
|
|
435
|
-
},
|
|
550
|
+
const tabGUI = new Folder({
|
|
551
|
+
container,
|
|
552
|
+
wrapper: tabPane,
|
|
553
|
+
parent: this,
|
|
554
|
+
firstParent: this.firstParent,
|
|
436
555
|
});
|
|
437
556
|
|
|
438
557
|
tabInstances.push({
|
|
439
558
|
gui: tabGUI,
|
|
440
559
|
button: tabButton,
|
|
441
|
-
pane: tabPane
|
|
560
|
+
pane: tabPane,
|
|
442
561
|
});
|
|
443
562
|
|
|
444
563
|
// Add click handler
|
|
@@ -456,27 +575,27 @@ export default class GUI {
|
|
|
456
575
|
});
|
|
457
576
|
|
|
458
577
|
// Create main tabs instance to return
|
|
459
|
-
const tabsInstance = new
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
},
|
|
578
|
+
const tabsInstance = new Folder({
|
|
579
|
+
container,
|
|
580
|
+
wrapper:
|
|
581
|
+
tabInstances[activeTab]?.pane ||
|
|
582
|
+
document.createElement('div'),
|
|
583
|
+
parent: this,
|
|
584
|
+
firstParent: this.firstParent,
|
|
467
585
|
});
|
|
468
586
|
|
|
469
587
|
// Add methods to access individual tabs
|
|
470
588
|
tabsInstance.getTab = (index) => tabInstances[index]?.gui || null;
|
|
471
|
-
tabsInstance.getTabElement = (index) =>
|
|
589
|
+
tabsInstance.getTabElement = (index) =>
|
|
590
|
+
tabInstances[index]?.button || null;
|
|
472
591
|
tabsInstance.setActiveTab = (index) => {
|
|
473
592
|
if (index >= 0 && index < tabInstances.length) {
|
|
474
593
|
tabInstances[index].button.click();
|
|
475
594
|
}
|
|
476
595
|
};
|
|
477
596
|
tabsInstance.getActiveTab = () => {
|
|
478
|
-
return tabInstances.findIndex(tab =>
|
|
479
|
-
tab.button.classList.contains('p-gui__tab-button--active')
|
|
597
|
+
return tabInstances.findIndex((tab) =>
|
|
598
|
+
tab.button.classList.contains('p-gui__tab-button--active'),
|
|
480
599
|
);
|
|
481
600
|
};
|
|
482
601
|
|
|
@@ -487,49 +606,52 @@ export default class GUI {
|
|
|
487
606
|
return tabsInstance;
|
|
488
607
|
}
|
|
489
608
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
this.header.addEventListener('pointerdown', dragMouseDown);
|
|
493
|
-
this.header.addEventListener('pointerup', dragMouseUp);
|
|
609
|
+
private _onPointerDown = (evt: PointerEvent) => {
|
|
610
|
+
evt.preventDefault();
|
|
494
611
|
|
|
495
|
-
|
|
496
|
-
|
|
612
|
+
this.position.initX = this.position.x;
|
|
613
|
+
this.position.initY = this.position.y;
|
|
497
614
|
|
|
498
|
-
|
|
499
|
-
|
|
615
|
+
this.position.prevX = evt.clientX;
|
|
616
|
+
this.position.prevY = evt.clientY;
|
|
500
617
|
|
|
501
|
-
|
|
502
|
-
|
|
618
|
+
this.container.addEventListener('pointermove', this._onPointerMove);
|
|
619
|
+
document.addEventListener('pointerup', this._onPointerUp);
|
|
620
|
+
};
|
|
503
621
|
|
|
504
|
-
|
|
505
|
-
|
|
622
|
+
private _onPointerMove = (evt: PointerEvent) => {
|
|
623
|
+
evt.preventDefault();
|
|
506
624
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
that.domElement.setAttribute('data-dragged', 'true');
|
|
512
|
-
}
|
|
625
|
+
if (!this.hasBeenDragged) {
|
|
626
|
+
this.hasBeenDragged = true;
|
|
627
|
+
this.domElement?.setAttribute('data-dragged', 'true');
|
|
628
|
+
}
|
|
513
629
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
that.position.y =
|
|
517
|
-
that.position.initY + ev.clientY - that.position.prevY;
|
|
630
|
+
this.position.x = this.position.initX + evt.clientX - this.position.prevX;
|
|
631
|
+
this.position.y = this.position.initY + evt.clientY - this.position.prevY;
|
|
518
632
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
that.position.x +
|
|
522
|
-
'px,' +
|
|
523
|
-
that.position.y +
|
|
524
|
-
'px,0)';
|
|
633
|
+
if (this.domElement) {
|
|
634
|
+
this.domElement.style.transform = `translate3d(${this.position.x}px, ${this.position.y}px, 0)`;
|
|
525
635
|
}
|
|
636
|
+
};
|
|
526
637
|
|
|
527
|
-
|
|
528
|
-
|
|
638
|
+
private _onPointerUp = () => {
|
|
639
|
+
this.container.removeEventListener('pointermove', this._onPointerMove);
|
|
640
|
+
document.removeEventListener('pointerup', this._onPointerUp);
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
_makeDraggable() {
|
|
644
|
+
if (!this.domElement || !this.header) {
|
|
645
|
+
return;
|
|
529
646
|
}
|
|
647
|
+
|
|
648
|
+
this.header.addEventListener('pointerdown', this._onPointerDown);
|
|
530
649
|
}
|
|
531
650
|
|
|
532
651
|
toggleClose() {
|
|
652
|
+
if (!this.domElement) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
533
655
|
this.closed = !this.closed;
|
|
534
656
|
|
|
535
657
|
if (this.closed) {
|
|
@@ -543,14 +665,16 @@ export default class GUI {
|
|
|
543
665
|
}
|
|
544
666
|
|
|
545
667
|
kill() {
|
|
546
|
-
this.domElement
|
|
668
|
+
if (this.domElement) {
|
|
669
|
+
this.domElement.remove();
|
|
670
|
+
}
|
|
547
671
|
}
|
|
548
672
|
|
|
549
|
-
_mapLinear(x, a1, a2, b1, b2) {
|
|
673
|
+
_mapLinear(x: number, a1: number, a2: number, b1: number, b2: number): number {
|
|
550
674
|
return b1 + ((x - a1) * (b2 - b1)) / (a2 - a1);
|
|
551
675
|
}
|
|
552
676
|
|
|
553
|
-
_countDecimals(num) {
|
|
677
|
+
_countDecimals(num: number) {
|
|
554
678
|
// Convert the number to a string
|
|
555
679
|
const numStr = num.toString();
|
|
556
680
|
|
|
@@ -574,3 +698,24 @@ export default class GUI {
|
|
|
574
698
|
}
|
|
575
699
|
}
|
|
576
700
|
}
|
|
701
|
+
|
|
702
|
+
type FolderParams = {
|
|
703
|
+
container: HTMLElement,
|
|
704
|
+
wrapper: HTMLElement,
|
|
705
|
+
parent: GUI,
|
|
706
|
+
firstParent: GUI,
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
export class Folder extends GUI {
|
|
710
|
+
public parent: GUI;
|
|
711
|
+
public firstParent: GUI;
|
|
712
|
+
|
|
713
|
+
constructor(folderOptions: FolderParams) {
|
|
714
|
+
super({}, true);
|
|
715
|
+
this.isFolder = true;
|
|
716
|
+
this.domElement = folderOptions.container;
|
|
717
|
+
this.wrapper = folderOptions.wrapper;
|
|
718
|
+
this.parent = folderOptions.parent;
|
|
719
|
+
this.firstParent = folderOptions.firstParent;
|
|
720
|
+
}
|
|
721
|
+
}
|