perfect-gui 4.2.0 → 4.2.3

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/README.md CHANGED
@@ -16,10 +16,24 @@ A nice, simple and (probably not) perfect GUI for JavaScript.
16
16
 
17
17
  ## Install
18
18
 
19
+ ### With NPM
20
+
19
21
  ```bash
20
22
  npm i perfect-gui
21
23
  ```
22
24
 
25
+ ### Import from a CDN
26
+
27
+ ```javascript
28
+ <script type="importmap">
29
+ {
30
+ "imports": {
31
+ "perfect-gui": "https://unpkg.com/perfect-gui@latest/dist/perfect-gui.mjs",
32
+ }
33
+ }
34
+ </script>
35
+ ```
36
+
23
37
  ## Hello world
24
38
 
25
39
  ```javascript
@@ -0,0 +1,725 @@
1
+ function w(y) {
2
+ return (
3
+ /* css */
4
+ `
5
+ .p-gui {
6
+ --main-border-radius: 5px;
7
+ --color-bg: #121212;
8
+ --color-border: #484848;
9
+ --color-border-2: rgba(255,255,255,.1);
10
+ --color-accent: #1681ca;
11
+ --color-accent-hover: #218fda;
12
+
13
+ position: ${y};
14
+ top: 0;
15
+ left: 0;
16
+ transform: translate3d(0,0,0);
17
+ padding-top: 21px;
18
+ background: var(--color-bg);
19
+ display: flex;
20
+ justify-content: center;
21
+ flex-wrap: wrap;
22
+ font-family: Verdana, Arial, sans-serif;
23
+ width: 290px;
24
+ overflow: auto;
25
+ box-shadow: 0 0 2px black;
26
+ box-sizing: border-box;
27
+ z-index: 99999;
28
+ user-select: none;
29
+ border-bottom-right-radius: 3px;
30
+ border-bottom-left-radius: 3px;
31
+ cursor: auto;
32
+ border-radius: var(--main-border-radius);
33
+ border: 1px solid var(--color-border);
34
+ }
35
+
36
+ .p-gui * {
37
+ font-size: 11px;
38
+ }
39
+
40
+ .p-gui::-webkit-scrollbar,
41
+ .p-gui *::-webkit-scrollbar {
42
+ width: 10px;
43
+ }
44
+
45
+ .p-gui::-webkit-scrollbar-track,
46
+ .p-gui *::-webkit-scrollbar-track {
47
+ background: #2f2f2f;
48
+ border-radius: 3px;
49
+ }
50
+
51
+ .p-gui::-webkit-scrollbar-thumb,
52
+ .p-gui *::-webkit-scrollbar-thumb {
53
+ background: #757576;
54
+ border-radius: 10px;
55
+ box-sizing: border-box;
56
+ border: 1px solid #2f2f2f;
57
+ }
58
+
59
+ .p-gui--collapsed {
60
+ height: 0;
61
+ padding: 21px 10px 0 10px;
62
+ overflow: hidden;
63
+ }
64
+
65
+ .p-gui__header {
66
+ position: absolute;
67
+ top: 0;
68
+ left: 0;
69
+ width: 100%;
70
+ height: 20px;
71
+ background-color: rgba(0, 0, 0, .8);
72
+ cursor: grab;
73
+ color: grey;
74
+ font-size: 10px;
75
+ line-height: 20px;
76
+ padding-left: 12px;
77
+ box-sizing: border-box;
78
+ touch-action: none;
79
+ }
80
+
81
+ .p-gui__header-close {
82
+ width: 20px;
83
+ height: 20px;
84
+ position: absolute;
85
+ top: 0;
86
+ right: 5px;
87
+ cursor: pointer;
88
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUAQMAAAC3R49OAAAABlBMVEUAAAD///+l2Z/dAAAAAXRSTlMAQObYZgAAABFJREFUCNdjIAb8//8BjIkAAOrOBd3TR0jRAAAAAElFTkSuQmCC);
89
+ background-size: 50% 50%;
90
+ background-position: center;
91
+ background-repeat: no-repeat;
92
+ }
93
+
94
+ .p-gui--collapsed .p-gui__header-close {
95
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUAQMAAAC3R49OAAAABlBMVEUAAAD///+l2Z/dAAAAAXRSTlMAQObYZgAAABVJREFUCNdjYEhgIIj///8AwsSoBQD43QydY5mb0QAAAABJRU5ErkJggg==);
96
+ }
97
+
98
+ .p-gui__image-container {
99
+ width: 100%;
100
+ display: grid;
101
+ grid-template-columns: repeat(auto-fill, 32%);
102
+ justify-content: space-between;
103
+ padding: 0 2%;
104
+ }
105
+
106
+ .p-gui__image {
107
+ aspect-ratio: 1 / 1;
108
+ background-size: cover;
109
+ cursor: pointer;
110
+ position: relative;
111
+ margin-top: 1px;
112
+ margin-bottom: 19px;
113
+ }
114
+
115
+ .p-gui__image-text {
116
+ position: absolute;
117
+ bottom: -15px;
118
+ color: #eee;
119
+ text-shadow: 0 -1px 0 #111;
120
+ white-space: nowrap;
121
+ width: 100%;
122
+ overflow: hidden;
123
+ text-overflow: ellipsis;
124
+ }
125
+
126
+ .p-gui__button,
127
+ .p-gui__switch,
128
+ .p-gui__list,
129
+ .p-gui__vector2,
130
+ .p-gui__color {
131
+ width: 100%;
132
+ padding: 7px 13px;
133
+ color: white;
134
+ cursor: pointer;
135
+ position: relative;
136
+ box-sizing: border-box;
137
+ margin-bottom: 3px;
138
+ margin: 3px;
139
+
140
+ border: 1px solid var(--color-border-2);
141
+ border-radius: var(--main-border-radius);
142
+ }
143
+
144
+ .p-gui__vector2 {
145
+ padding: 7px;
146
+ }
147
+
148
+ .p-gui__button,
149
+ .p-gui__switch {
150
+ margin-right: 4px;
151
+ margin-left: 4px;
152
+ }
153
+
154
+ .p-gui__button {
155
+ background: var(--color-accent);
156
+ text-align: center;
157
+ color: white;
158
+ border: none;
159
+ }
160
+
161
+ .p-gui__button:hover {
162
+ background: var(--color-accent-hover);
163
+ }
164
+
165
+ .p-gui__switch {
166
+ background: rgba(255, 255, 255, .05);
167
+ }
168
+
169
+ .p-gui__switch:hover {
170
+ background: rgba(255, 255, 255, .1);
171
+ }
172
+
173
+ .p-gui__folder .p-gui__button,
174
+ .p-gui__folder .p-gui__switch {
175
+ margin-right: 0;
176
+ margin-left: 0;
177
+ }
178
+
179
+ .p-gui__vector2 {
180
+ background: transparent;
181
+ aspect-ratio: 1;
182
+ padding-bottom: 0;
183
+ }
184
+
185
+ .p-gui__vector2-area {
186
+ position: relative;
187
+ background: rgba(0, 0, 0, .3);
188
+ margin-top: 8px;
189
+ width: 100%;
190
+ height: calc(100% - 28px);
191
+ touch-action: none;
192
+ }
193
+
194
+ .p-gui__vector2-line {
195
+ position: absolute;
196
+ background: white;
197
+ opacity: .3;
198
+ pointer-events: none;
199
+ }
200
+
201
+ .p-gui__vector2-line-x {
202
+ width: 100%;
203
+ height: 1px;
204
+ left: 0;
205
+ top: 50%;
206
+ transform: translateY(-50%);
207
+ }
208
+
209
+ .p-gui__vector2-line-y {
210
+ width: 1px;
211
+ height: 100%;
212
+ top: 0;
213
+ left: 50%;
214
+ transform: translateX(-50%);
215
+ }
216
+
217
+ .p-gui__vector2-dot {
218
+ position: absolute;
219
+ top: 0;
220
+ left: 0;
221
+ width: 8px;
222
+ height: 8px;
223
+ border-radius: 50%;
224
+ background: #d5d5d5;
225
+ border: 2px solid #ff9999;
226
+ transform: translate(-50%, -50%);
227
+ pointer-events: none;
228
+ }
229
+
230
+ .p-gui__switch-checkbox {
231
+ width: 5px;
232
+ height: 5px;
233
+ background-color: rgba(0, 0, 0, .5);
234
+ border: 1px solid grey;
235
+ position: absolute;
236
+ top: 0;
237
+ right: 10px;
238
+ bottom: 0;
239
+ margin: auto;
240
+ border-radius: 50%;
241
+ pointer-events: none;
242
+ }
243
+
244
+ .p-gui__switch-checkbox--active {
245
+ background-color: #00ff89;
246
+ box-shadow: 0 0 7px #00ff89;
247
+ }
248
+
249
+ .p-gui__list,
250
+ .p-gui__color {
251
+ cursor: default;
252
+ }
253
+
254
+ .p-gui__list-dropdown,
255
+ .p-gui__color-picker {
256
+ position: absolute;
257
+ right: 5px;
258
+ top: 0;
259
+ bottom: 0;
260
+ margin: auto;
261
+ height: 21px;
262
+ cursor: pointer;
263
+ border-radius: 3px;
264
+ border: 1px solid var(--color-border-2);
265
+ }
266
+
267
+ .p-gui__list-dropdown {
268
+ background: rgba(255, 255, 255,.05);
269
+ color: white;
270
+ padding: 0 12px;
271
+ top: 0px;
272
+ }
273
+
274
+ .p-gui__list-dropdown:hover {
275
+ background: rgba(255, 255, 255, .1);
276
+ }
277
+
278
+ .p-gui__color-picker {
279
+ -webkit-appearance: none;
280
+ padding: 0;
281
+ background-color: transparent;
282
+ border: 1px solid #222222;
283
+ overflow: hidden;
284
+ }
285
+
286
+ .p-gui__color-picker::-webkit-color-swatch-wrapper {
287
+ padding: 0;
288
+ }
289
+ .p-gui__color-picker::-webkit-color-swatch {
290
+ border: none;
291
+ }
292
+
293
+ .p-gui__slider {
294
+ width: 100%;
295
+ margin-bottom: 8px;
296
+ padding: 7px;
297
+ color: white;
298
+ position: relative;
299
+ min-height: 14px;
300
+ }
301
+
302
+ .p-gui__slider-ctrl {
303
+ -webkit-appearance: none;
304
+ padding: 0;
305
+ font: inherit;
306
+ outline: none;
307
+ opacity: .8;
308
+ background: var(--color-accent);
309
+ box-sizing: border-box;
310
+ cursor: pointer;
311
+ position: absolute;
312
+ bottom: -4px; /* 5px height -1px de dépassement du curseur */
313
+ right: 0;
314
+ height: 5px;
315
+ width: 100%;
316
+ margin: 0;
317
+ }
318
+
319
+ /* la zone de déplacement */
320
+ .p-gui__slider-ctrl::-webkit-slider-runnable-track {
321
+ height: 13px;
322
+ border: none;
323
+ border-radius: 0;
324
+ background-color: transparent; /* supprimé définie sur l'input */
325
+ }
326
+
327
+ /* Curseur */
328
+ .p-gui__slider-ctrl::-webkit-slider-thumb {
329
+ -webkit-appearance: none; /* également nécessaire sur le curseur */
330
+ width: 15px;
331
+ height: 7px;
332
+ border: none; /* pris en compte sur Webkit et Edge */
333
+ background: white; /* pris en compte sur Webkit only */
334
+ position: relative;
335
+ top: 3px;
336
+ border-radius: 1px;
337
+ }
338
+
339
+ .p-gui__slider-value,
340
+ .p-gui__vector-value {
341
+ display: inline-block;
342
+ position: absolute;
343
+ right: 7px;
344
+ }
345
+
346
+ .p-gui__folder {
347
+ width: 100%;
348
+ position: relative;
349
+ background: #434343;
350
+ overflow: auto;
351
+ margin-bottom: 3px;
352
+ display: flex;
353
+ flex-wrap: wrap;
354
+ border-left: 3px solid grey;
355
+ border-bottom: 1px solid grey;
356
+ padding: 0 3px;
357
+ }
358
+
359
+ .p-gui__folder:last-of-type {
360
+ margin-bottom: 0;
361
+ border-bottom: none;
362
+ }
363
+
364
+ .p-gui__folder--first {
365
+ margin-top: 0;
366
+ }
367
+
368
+ .p-gui__folder--closed {
369
+ height: 32px;
370
+ overflow: hidden;
371
+ }
372
+
373
+ .p-gui__folder-header {
374
+ padding: 10px 5px;
375
+ background-color: rgba(0, 0, 0, .5);
376
+ color: white;
377
+ cursor: pointer;
378
+ width: 100%;
379
+ margin: 0 -2px 2px -3px;
380
+ }
381
+
382
+ .p-gui__folder-header:hover {
383
+ background-color: rgba(0, 0, 0, .75);
384
+ }
385
+
386
+ .p-gui__folder-arrow {
387
+ width: 8px;
388
+ height: 8px;
389
+ display: inline-block;
390
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAHlBMVEUAAAD///////////////////////////////////8kfJuVAAAACXRSTlMA9Z1fCdMo1yxEJnA0AAAAK0lEQVQI12PABlRgjKkJUMZMYRhjpgqMAZSEMICSaIzpDWiKhdENhEhgAgATSg5jyWnYewAAAABJRU5ErkJggg==);
391
+ background-size: contain;
392
+ margin-right: 5px;
393
+ transform: rotate(90deg)
394
+ }
395
+
396
+ .p-gui__folder--closed .p-gui__folder-arrow {
397
+ transform: rotate(0deg);
398
+ }
399
+ `
400
+ );
401
+ }
402
+ class h {
403
+ constructor(e = {}) {
404
+ if (e.container ? (this.container = typeof e.container == "string" ? document.querySelector(e.container) : e.container, this.position_type = "absolute") : (this.container = document.body, this.position_type = "fixed"), this.propReferences = [], this.folders = [], e.isFolder) {
405
+ this._folderConstructor(e.folderOptions);
406
+ return;
407
+ }
408
+ this.name = e != null && typeof e.name == "string" ? e.name : "", this.backgroundColor = e.color || null, this.container == document.body ? this.maxHeight = window.innerHeight : this.maxHeight = Math.min(this.container.clientHeight, window.innerHeight), e.maxHeight && (this.initMaxHeight = e.maxHeight, this.maxHeight = Math.min(this.initMaxHeight, this.maxHeight)), this.screenCorner = this._parseScreenCorner(e.position), this instanceof h && (typeof h[h.instanceCounter] != "number" ? h[h.instanceCounter] = 0 : h[h.instanceCounter]++), this.instanceId = h[h.instanceCounter], this.wrapperWidth = e.width || 290, this.stylesheet = document.createElement("style"), this.stylesheet.setAttribute("type", "text/css"), this.stylesheet.setAttribute("id", "lm-gui-stylesheet"), document.head.append(this.stylesheet), this.instanceId == 0 && this._addStyles(`${w(this.position_type)}`), this._styleInstance(), this._addWrapper(), this.wrapper.setAttribute("data-corner-x", this.screenCorner.x), this.wrapper.setAttribute("data-corner-y", this.screenCorner.y), e.autoRepositioning != !1 && window.addEventListener("resize", this._handleResize.bind(this)), this._handleResize(), this.hasBeenDragged = !1, e.draggable == !0 && this._makeDraggable(), this.closed = !1, e.closed && this.toggleClose();
409
+ }
410
+ _styleInstance() {
411
+ let e = this._getScrollbarWidth(this.container);
412
+ if (this.screenCorner.x == "left" ? this.xOffset = 0 : this.xOffset = this.container.clientWidth - this.wrapperWidth - e, this.instanceId > 0) {
413
+ let t = this.container.querySelectorAll(".p-gui");
414
+ for (let i = 0; i < t.length; i++)
415
+ this.screenCorner.y == t[i].dataset.cornerY && (this.screenCorner.x == "left" && t[i].dataset.cornerX == "left" ? this.xOffset += t[i].offsetWidth : this.screenCorner.x == "right" && t[i].dataset.cornerX == "right" && (this.xOffset -= t[i].offsetWidth));
416
+ }
417
+ this.yOffset = 0, this.position = {
418
+ prevX: this.xOffset,
419
+ prevY: this.yOffset,
420
+ x: this.xOffset,
421
+ y: this.yOffset
422
+ }, this._addStyles(`#p-gui-${this.instanceId} {
423
+ width: ${this.wrapperWidth}px;
424
+ max-height: ${this.maxHeight}px;
425
+ transform: translate3d(${this.xOffset}px,${this.yOffset}px,0);
426
+ ${this.screenCorner.y == "top" ? "" : "top: auto; bottom: 0;"}
427
+ ${this.backgroundColor ? "background: " + this.backgroundColor + ";" : ""}
428
+ }`);
429
+ }
430
+ _folderConstructor(e) {
431
+ this.wrapper = e.wrapper;
432
+ }
433
+ _parseScreenCorner(e) {
434
+ let t = { x: "right", y: "top" };
435
+ return e == null || (typeof e != "string" && console.error("[perfect-gui] Position must be a string."), e.includes("left") && (t.x = "left"), e.includes("bottom") && (t.y = "bottom")), t;
436
+ }
437
+ _getScrollbarWidth(e) {
438
+ return e === document.body ? window.innerWidth - document.documentElement.clientWidth : e.offsetWidth - e.clientWidth;
439
+ }
440
+ _handleResize() {
441
+ if (this.container == document.body ? this.maxHeight = window.innerHeight : this.maxHeight = Math.min(this.container.clientHeight, window.innerHeight), this.initMaxHeight && (this.maxHeight = Math.min(this.initMaxHeight, this.maxHeight)), this.wrapper.style.maxHeight = this.maxHeight + "px", this.hasBeenDragged)
442
+ return;
443
+ let e = this._getScrollbarWidth(this.container);
444
+ if (this.xOffset = this.screenCorner.x == "left" ? 0 : this.container.clientWidth - this.wrapperWidth - e, this.instanceId > 0) {
445
+ let t = this.container.querySelectorAll(`.p-gui:not(#${this.wrapper.id}):not([data-dragged])`);
446
+ for (let i = 0; i < t.length && !(parseInt(t[i].id.replace("p-gui-", "")) > this.instanceId); i++)
447
+ this.screenCorner.y == t[i].dataset.cornerY && (this.screenCorner.x == "left" && t[i].dataset.cornerX == "left" ? this.xOffset += t[i].offsetWidth : this.screenCorner.x == "right" && t[i].dataset.cornerX == "right" && (this.xOffset -= t[i].offsetWidth));
448
+ }
449
+ this.position = { prevX: this.xOffset, prevY: this.yOffset, x: this.xOffset, y: this.yOffset }, this.wrapper.style.transform = `translate3d(${this.position.x}px, ${this.position.y}px, 0)`;
450
+ }
451
+ _createElement(e) {
452
+ e.el = e.el || "div";
453
+ var t = document.createElement(e.el);
454
+ if (e.id && (t.id = e.id), e.class && (t.className = e.class), e.inline && (t.style = e.inline), e.href && (t.href = e.href), e.onclick && (t.onclick = e.onclick), e.onchange && (t.onchange = e.onchange), e.textContent && (t.textContent = e.textContent), e.innerHTML && (t.innerHTML = e.innerHTML), e.type && (t.type = e.type), e.value && (t.value = e.value), e.customAttributes)
455
+ for (var i in e.customAttributes)
456
+ t.setAttribute(i, e.customAttributes[i]);
457
+ return e.parent = e.parent ? e.parent : this.wrapper, e.parent.append(t), t;
458
+ }
459
+ _addStyles(e) {
460
+ this.stylesheet.innerHTML += e;
461
+ }
462
+ _addWrapper() {
463
+ this.wrapper = this._createElement({
464
+ parent: this.container,
465
+ id: "p-gui-" + this.instanceId,
466
+ class: "p-gui"
467
+ }), this.header = this._createElement({
468
+ parent: this.wrapper,
469
+ class: "p-gui__header",
470
+ textContent: this.name,
471
+ inline: `${this.backgroundColor ? "border-color: " + this.backgroundColor + ";" : ""}`
472
+ }), this._createElement({
473
+ parent: this.header,
474
+ class: "p-gui__header-close",
475
+ onclick: this.toggleClose.bind(this)
476
+ });
477
+ }
478
+ button(e, t) {
479
+ let i = "";
480
+ typeof e != "string" ? typeof e == "object" && (e != null && e.hasOwnProperty("name")) ? i = e.name == "" ? " " : e.name : i = " " : i = e == "" ? " " : e, this.imageContainer = null, typeof t != "function" && (t = () => {
481
+ });
482
+ const r = this._createElement({
483
+ class: "p-gui__button",
484
+ textContent: i,
485
+ onclick: t
486
+ });
487
+ typeof e.color == "string" && (r.style.setProperty("--color-accent", e.color), r.style.setProperty("--color-accent-hover", e.hoverColor || e.color));
488
+ }
489
+ image(e = {}, t) {
490
+ if (typeof e != "object")
491
+ throw Error(`[GUI] image() first parameter must be an object. Received: ${typeof e}.`);
492
+ let i;
493
+ if (typeof e.path == "string")
494
+ i = e.path;
495
+ else
496
+ throw typeof e.path == null ? Error("[GUI] image() path must be provided.") : Error("[GUI] image() path must be a string.");
497
+ let r = i.replace(/^.*[\\\/]/, ""), o;
498
+ e.name == null ? o = r : o = typeof e.name == "string" && e.name || " ", this.imageContainer || (this.imageContainer = this._createElement({
499
+ class: "p-gui__image-container"
500
+ }));
501
+ var n = this._createElement({
502
+ class: "p-gui__image",
503
+ inline: `background-image: url(${i})`,
504
+ parent: this.imageContainer
505
+ });
506
+ this._createElement({
507
+ parent: n,
508
+ class: "p-gui__image-text",
509
+ textContent: o
510
+ }), typeof t == "function" && (n.onclick = () => t({ path: i, text: o }));
511
+ }
512
+ slider(e = {}, t) {
513
+ if (typeof e != "object")
514
+ throw Error(`[GUI] slider() first parameter must be an object. Received: ${typeof e}.`);
515
+ let i = typeof e.name == "string" && e.name || " ", r = !1, o = null, n = e.obj || e.object, s = e.prop || e.property, a = typeof e.value == "number" ? e.value : null, l = e.min ?? 0, f = e.max ?? 1, g = e.step || (f - l) / 100;
516
+ if (a !== null)
517
+ (s != null || n != null) && console.warn('[GUI] slider() "obj" and "property" parameters are ignored when a "value" parameter is used.');
518
+ else if (s != null && n != null) {
519
+ if (typeof s != "string")
520
+ throw Error(`[GUI] slider() "prop" (or "property") parameter must be an string. Received: ${typeof s}.`);
521
+ if (typeof n != "object")
522
+ throw Error(`[GUI] slider() "obj" (or "object") parameter must be an object. Received: ${typeof n}.`);
523
+ i == " " && (i = s), o = this.propReferences.push(n[s]) - 1, r = !0;
524
+ } else
525
+ (s != null && n == null || s == null && n == null) && console.warn('[GUI] slider() "obj" and "prop" parameters must be used together.'), a = (f - l) / 2;
526
+ this.imageContainer = null;
527
+ var d = this._createElement({
528
+ class: "p-gui__slider",
529
+ textContent: i
530
+ }), u = this._createElement({
531
+ parent: d,
532
+ el: "input",
533
+ class: "p-gui__slider-ctrl",
534
+ customAttributes: {
535
+ type: "range",
536
+ min: l,
537
+ max: f,
538
+ step: g,
539
+ value: r ? n[s] : a
540
+ }
541
+ }), _ = this._createElement({
542
+ parent: d,
543
+ class: "p-gui__slider-value",
544
+ textContent: String(r ? n[s] : a)
545
+ });
546
+ u.addEventListener("input", () => {
547
+ _.textContent = u.value, r && (n[s] = u.value), typeof t == "function" && t(parseFloat(u.value));
548
+ }), r && Object.defineProperty(n, s, {
549
+ set: (b) => {
550
+ this.propReferences[o] = b, u.value = b, _.textContent = String(b);
551
+ },
552
+ get: () => this.propReferences[o]
553
+ });
554
+ }
555
+ toggle(e = {}, t) {
556
+ if (typeof e != "object")
557
+ throw Error(`[GUI] toggle() first parameter must be an object. Received: ${typeof e}.`);
558
+ let i = typeof e.name == "string" && e.name || " ", r = e.value === !0;
559
+ this.imageContainer = null;
560
+ let o = this._createElement({
561
+ class: "p-gui__switch",
562
+ onclick: (s) => {
563
+ let a = s.target.childNodes[1], l = !0;
564
+ a.classList.contains("p-gui__switch-checkbox--active") && (l = !1), a.classList.toggle("p-gui__switch-checkbox--active"), typeof t == "function" && t(l);
565
+ },
566
+ textContent: i
567
+ }), n = r ? " p-gui__switch-checkbox--active" : "";
568
+ this._createElement({
569
+ parent: o,
570
+ class: "p-gui__switch-checkbox" + n
571
+ });
572
+ }
573
+ list(e = {}, t) {
574
+ if (typeof e != "object")
575
+ throw Error(`[GUI] list() first parameter must be an object. Received: ${typeof e}.`);
576
+ let i = typeof e.name == "string" ? e.name : " ", r = Array.isArray(e.values) ? e.values : null;
577
+ t = typeof t == "function" ? t : null, this.imageContainer = null;
578
+ let o = this._createElement({
579
+ class: "p-gui__list",
580
+ textContent: i
581
+ }), n = this._createElement({
582
+ parent: o,
583
+ el: "select",
584
+ class: "p-gui__list-dropdown",
585
+ onchange: (s) => {
586
+ t && t(s.target.value);
587
+ }
588
+ });
589
+ r.forEach((s) => {
590
+ this._createElement({
591
+ parent: n,
592
+ el: "option",
593
+ customAttributes: {
594
+ value: s
595
+ },
596
+ textContent: s
597
+ });
598
+ });
599
+ }
600
+ options(e, t) {
601
+ if (typeof e != "object")
602
+ throw Error(`[GUI] options() first parameter must be an object. Received: ${typeof e}.`);
603
+ this.list(e, t);
604
+ }
605
+ vector2(e = {}, t) {
606
+ if (typeof e != "object")
607
+ throw Error(`[GUI] vector2() first parameter must be an object. Received: ${typeof e}.`);
608
+ let i = typeof e.name == "string" && e.name || " ";
609
+ const r = e.x.min ?? 0, o = e.x.max ?? 1, n = e.y.min ?? 0, s = e.y.max ?? 1, a = e.x.obj || e.x.object, l = e.x.prop || e.x.property, f = this.propReferences.push(a[l]) - 1, g = e.y.obj || e.y.object, d = e.y.prop || e.y.property, u = this.propReferences.push(g[d]) - 1;
610
+ t = typeof t == "function" ? t : null, this.imageContainer = null;
611
+ const _ = this._createElement({
612
+ class: "p-gui__vector2",
613
+ textContent: i
614
+ }), b = this._createElement({
615
+ parent: _,
616
+ class: "p-gui__vector-value",
617
+ textContent: a[l] + ", " + g[d]
618
+ }), p = this._createElement({
619
+ parent: _,
620
+ el: "div",
621
+ class: "p-gui__vector2-area",
622
+ onclick: (c) => {
623
+ a[l] = parseFloat(this._mapLinear(c.offsetX, 0, p.clientWidth, r, o).toFixed(2)), g[d] = parseFloat(this._mapLinear(c.offsetY, 0, p.clientHeight, s, n).toFixed(2)), t && t(a[l], a[d]);
624
+ }
625
+ });
626
+ let m = !1;
627
+ p.addEventListener("pointerdown", (c) => {
628
+ m = !0;
629
+ }), p.addEventListener("pointerup", () => {
630
+ m = !1;
631
+ }), p.addEventListener("pointermove", (c) => {
632
+ m && (a[l] = parseFloat(this._mapLinear(c.offsetX, 0, p.clientWidth, r, o).toFixed(2)), g[d] = parseFloat(this._mapLinear(c.offsetY, 0, p.clientHeight, s, n).toFixed(2)), t && t(a[l], a[d]));
633
+ }), this._createElement({
634
+ parent: p,
635
+ class: "p-gui__vector2-line p-gui__vector2-line-x"
636
+ }), this._createElement({
637
+ parent: p,
638
+ class: "p-gui__vector2-line p-gui__vector2-line-y"
639
+ });
640
+ const x = this._createElement({
641
+ parent: p,
642
+ class: "p-gui__vector2-dot"
643
+ });
644
+ x.style.left = this._mapLinear(a[l], r, o, 0, p.clientWidth) + "px", x.style.top = this._mapLinear(g[d], n, s, p.clientHeight, 0) + "px", Object.defineProperty(a, l, {
645
+ set: (c) => {
646
+ this.propReferences[f] = c, x.style.left = this._mapLinear(c, r, o, 0, p.clientWidth) + "px", b.textContent = String(c) + ", " + g[d];
647
+ },
648
+ get: () => this.propReferences[f]
649
+ }), Object.defineProperty(g, d, {
650
+ set: (c) => {
651
+ this.propReferences[u] = c, x.style.top = this._mapLinear(c, n, s, p.clientHeight, 0) + "px", b.textContent = a[l] + ", " + String(c);
652
+ },
653
+ get: () => this.propReferences[u]
654
+ });
655
+ }
656
+ color(e = {}, t) {
657
+ if (typeof e != "object")
658
+ throw Error(`[GUI] color() first parameter must be an object. Received: ${typeof e}.`);
659
+ let i = typeof e.name == "string" && e.name || " ", r;
660
+ typeof e.value == "string" && (e.value.length != 7 || e.value[0] != "#" ? console.error(`[GUI] color() 'value' parameter must be an hexadecimal string in the format "#ffffff". Received: "${e.value}".`) : r = e.value), r || (r = "#000000");
661
+ const o = this._createElement({
662
+ el: "div",
663
+ class: "p-gui__color",
664
+ textContent: i
665
+ }), n = this._createElement({
666
+ parent: o,
667
+ el: "input",
668
+ class: "p-gui__color-picker",
669
+ type: "color",
670
+ value: r
671
+ });
672
+ typeof t == "function" && n.addEventListener("input", () => {
673
+ t(n.value);
674
+ });
675
+ }
676
+ folder(e = {}) {
677
+ let t = typeof e.closed == "boolean" ? e.closed : !1, i = e.name || "", r = e.color || null, o = e.maxHeight || null;
678
+ this.imageContainer = null;
679
+ let n = "p-gui__folder";
680
+ this.folders.length == 0 && (n += " p-gui__folder--first"), t && (n += " p-gui__folder--closed");
681
+ let s = r ? `background-color: ${r};` : "";
682
+ s += o ? `max-height: ${o}px;` : "";
683
+ let a = this._createElement({
684
+ class: n,
685
+ inline: s
686
+ });
687
+ this._createElement({
688
+ innerHTML: `<span class="p-gui__folder-arrow"></span>${i}`,
689
+ class: "p-gui__folder-header",
690
+ onclick: function() {
691
+ this.parentNode.classList.toggle("p-gui__folder--closed");
692
+ },
693
+ parent: a
694
+ });
695
+ let l = new h({ isFolder: !0, folderOptions: {
696
+ wrapper: a
697
+ } });
698
+ return this.folders.push(l), l;
699
+ }
700
+ _makeDraggable() {
701
+ var e = this;
702
+ this.header.addEventListener("pointerdown", t), this.header.addEventListener("pointerup", r);
703
+ function t(o) {
704
+ o.preventDefault(), e.position.initX = e.position.x, e.position.initY = e.position.y, e.position.prevX = o.clientX, e.position.prevY = o.clientY, document.addEventListener("pointermove", i);
705
+ }
706
+ function i(o) {
707
+ o.preventDefault(), e.hasBeenDragged || (e.hasBeenDragged = !0, e.wrapper.setAttribute("data-dragged", "true")), e.position.x = e.position.initX + o.clientX - e.position.prevX, e.position.y = e.position.initY + o.clientY - e.position.prevY, e.wrapper.style.transform = "translate3d(" + e.position.x + "px," + e.position.y + "px,0)";
708
+ }
709
+ function r(o) {
710
+ document.removeEventListener("pointermove", i);
711
+ }
712
+ }
713
+ toggleClose() {
714
+ this.closed = !this.closed, this.wrapper.classList.toggle("p-gui--collapsed");
715
+ }
716
+ kill() {
717
+ this.wrapper.remove();
718
+ }
719
+ _mapLinear(e, t, i, r, o) {
720
+ return r + (e - t) * (o - r) / (i - t);
721
+ }
722
+ }
723
+ export {
724
+ h as default
725
+ };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "perfect-gui",
3
- "version": "4.2.0",
3
+ "version": "4.2.3",
4
4
  "description": "Nice and simple GUI for JavaScript",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "build": "vite build"
8
8
  },
9
9
  "repository": {
10
10
  "type": "git",
@@ -18,5 +18,8 @@
18
18
  "bugs": {
19
19
  "url": "https://github.com/thibka/perfect-gui/issues"
20
20
  },
21
- "homepage": "https://thibka.github.io/perfect-gui/public/"
21
+ "homepage": "https://thibka.github.io/perfect-gui/public/",
22
+ "devDependencies": {
23
+ "vite": "^4.5.0"
24
+ }
22
25
  }
package/src/index.js CHANGED
@@ -221,16 +221,16 @@ export default class GUI {
221
221
  });
222
222
  }
223
223
 
224
- button(name, callback) {
225
- if (typeof name != 'string') {
226
- if (typeof name == 'object' && name?.hasOwnProperty('name')) {
227
- name = name.name;
224
+ button(options, callback) {
225
+ let name = '';
226
+ if (typeof options != 'string') {
227
+ if (typeof options == 'object' && options?.hasOwnProperty('name')) {
228
+ name = options.name == '' ? ' ' : options.name;
228
229
  } else {
229
230
  name = ' ';
230
231
  }
231
- }
232
- if (name === '') {
233
- name = ' ';
232
+ } else {
233
+ name = options == '' ? ' ' : options;
234
234
  }
235
235
 
236
236
  this.imageContainer = null;
@@ -238,12 +238,30 @@ export default class GUI {
238
238
  if (typeof callback != 'function') {
239
239
  callback = () => {};
240
240
  }
241
+
242
+ /* let create_options = {
243
+ class: 'p-gui__button',
244
+ textContent: name,
245
+ onclick: callback
246
+ };
247
+
248
+ if (typeof options.color == 'string') {
249
+ create_options.inline = 'background-color: ' + options.color;
250
+ }
241
251
 
242
- this._createElement({
252
+ this._createElement(create_options); */
253
+
254
+
255
+ const el = this._createElement({
243
256
  class: 'p-gui__button',
244
257
  textContent: name,
245
258
  onclick: callback
246
259
  });
260
+
261
+ if (typeof options.color == 'string') {
262
+ el.style.setProperty('--color-accent', options.color);
263
+ el.style.setProperty('--color-accent-hover', options.hoverColor || options.color);
264
+ }
247
265
  }
248
266
 
249
267
  image(params = {}, callback) {
package/vite.config.js ADDED
@@ -0,0 +1,11 @@
1
+ import { resolve } from "path";
2
+ import { defineConfig } from "vite";
3
+
4
+ export default defineConfig({
5
+ build: {
6
+ lib: {
7
+ entry: resolve(__dirname, "src/index.js"),
8
+ name: "Perfect GUI"
9
+ }
10
+ },
11
+ });