@rogieking/figui3 1.2.7 → 1.2.9
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/example.html +58 -27
- package/fig.css +92 -14
- package/fig.js +190 -7
- package/package.json +1 -1
package/example.html
CHANGED
|
@@ -23,14 +23,17 @@
|
|
|
23
23
|
<h2>UI3 Components</h2>
|
|
24
24
|
</fig-header>
|
|
25
25
|
<fig-content>
|
|
26
|
-
|
|
27
|
-
<
|
|
26
|
+
<fig-input-joystick text="true"></fig-input-joystick>
|
|
27
|
+
<fig-header>
|
|
28
|
+
<h2>Details</h2>
|
|
29
|
+
</fig-header>
|
|
28
30
|
<details>
|
|
29
31
|
<summary>Advanced settings</summary>
|
|
30
32
|
<p>Some more content here</p>
|
|
31
33
|
</details>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
<fig-header>
|
|
35
|
+
<h2>Avatar</h2>
|
|
36
|
+
</fig-header>
|
|
34
37
|
<fig-field>
|
|
35
38
|
<label>Default</label>
|
|
36
39
|
<fig-avatar src="https://avatars.githubusercontent.com/u/12345678?v=4"
|
|
@@ -53,15 +56,18 @@
|
|
|
53
56
|
name="Rogie King"></fig-avatar>
|
|
54
57
|
</fig-field>
|
|
55
58
|
|
|
56
|
-
<
|
|
59
|
+
<fig-header>
|
|
60
|
+
<h2>Tabs</h2>
|
|
61
|
+
</fig-header>
|
|
57
62
|
<fig-field>
|
|
58
63
|
<fig-tabs>
|
|
59
64
|
<fig-tab selected>Tab #1</fig-tab>
|
|
60
65
|
<fig-tab>Tab #2</fig-tab>
|
|
61
66
|
</fig-tabs>
|
|
62
67
|
</fig-field>
|
|
63
|
-
<
|
|
64
|
-
|
|
68
|
+
<fig-header>
|
|
69
|
+
<h2>Segmented control</h2>
|
|
70
|
+
</fig-header>
|
|
65
71
|
<fig-field>
|
|
66
72
|
<fig-segmented-control>
|
|
67
73
|
<fig-segment selected>One</fig-segment>
|
|
@@ -69,7 +75,9 @@
|
|
|
69
75
|
<fig-segment>Three</fig-segment>
|
|
70
76
|
</fig-segmented-control>
|
|
71
77
|
</fig-field>
|
|
72
|
-
<
|
|
78
|
+
<fig-header>
|
|
79
|
+
<h2>Image</h2>
|
|
80
|
+
</fig-header>
|
|
73
81
|
<fig-field>
|
|
74
82
|
<label>Default</label>
|
|
75
83
|
<fig-image src="https://avatars.githubusercontent.com/u/12345678?v=4"></fig-image>
|
|
@@ -86,7 +94,9 @@
|
|
|
86
94
|
size="large"></fig-image>
|
|
87
95
|
</fig-field>
|
|
88
96
|
<br /><br />
|
|
89
|
-
<
|
|
97
|
+
<fig-header>
|
|
98
|
+
<h2>Button</h2>
|
|
99
|
+
</fig-header>
|
|
90
100
|
<fig-field>
|
|
91
101
|
<label>Primary Button</label>
|
|
92
102
|
<fig-button>Primary</fig-button>
|
|
@@ -127,8 +137,9 @@
|
|
|
127
137
|
fill="currentColor"></path>
|
|
128
138
|
</svg></fig-button>
|
|
129
139
|
</fig-field>
|
|
130
|
-
|
|
131
|
-
|
|
140
|
+
<fig-header>
|
|
141
|
+
<h2>Combo button</h2>
|
|
142
|
+
</fig-header>
|
|
132
143
|
<fig-field>
|
|
133
144
|
<label>Primary (compact dropdown</label>
|
|
134
145
|
<fig-button-combo>
|
|
@@ -315,8 +326,9 @@
|
|
|
315
326
|
<fig-button>Save</fig-button>
|
|
316
327
|
</footer>
|
|
317
328
|
</fig-dialog>
|
|
318
|
-
|
|
319
|
-
|
|
329
|
+
<fig-header>
|
|
330
|
+
<h2>Dropdown</h2>
|
|
331
|
+
</fig-header>
|
|
320
332
|
<fig-field>
|
|
321
333
|
<label>Dropdown</label>
|
|
322
334
|
<fig-dropdown>
|
|
@@ -392,7 +404,9 @@
|
|
|
392
404
|
<span slot="prepend">X</span>
|
|
393
405
|
</fig-input-text>
|
|
394
406
|
</fig-field>
|
|
395
|
-
<
|
|
407
|
+
<fig-header>
|
|
408
|
+
<h2>Color input</h2>
|
|
409
|
+
</fig-header>
|
|
396
410
|
<fig-field>
|
|
397
411
|
<label>Color swatch</label>
|
|
398
412
|
<fig-input-color value="#FF000066"></fig-input-color>
|
|
@@ -408,11 +422,15 @@
|
|
|
408
422
|
alpha="true"
|
|
409
423
|
text="true"></fig-input-color>
|
|
410
424
|
</fig-field>
|
|
411
|
-
<
|
|
425
|
+
<fig-header>
|
|
426
|
+
<h2>Checkbox</h2>
|
|
427
|
+
</fig-header>
|
|
412
428
|
<fig-field>
|
|
413
429
|
<fig-checkbox label="Checkbox"></fig-checkbox>
|
|
414
430
|
</fig-field>
|
|
415
|
-
<
|
|
431
|
+
<fig-header>
|
|
432
|
+
<h2>Radio</h2>
|
|
433
|
+
</fig-header>
|
|
416
434
|
<fig-field>
|
|
417
435
|
<label>Radio buttons</label>
|
|
418
436
|
<fig-radio label="Radio #1"
|
|
@@ -420,7 +438,9 @@
|
|
|
420
438
|
<fig-radio label="Radio #2"
|
|
421
439
|
name="r1"></fig-radio>
|
|
422
440
|
</fig-field>
|
|
423
|
-
<
|
|
441
|
+
<fig-header>
|
|
442
|
+
<h2>Switch</h2>
|
|
443
|
+
</fig-header>
|
|
424
444
|
<fig-field>
|
|
425
445
|
<label>Switches</label>
|
|
426
446
|
<fig-switch on="true"
|
|
@@ -430,7 +450,9 @@
|
|
|
430
450
|
<fig-switch disabled
|
|
431
451
|
label="Disabled"></fig-switch>
|
|
432
452
|
</fig-field>
|
|
433
|
-
<
|
|
453
|
+
<fig-header>
|
|
454
|
+
<h2>Chit</h2>
|
|
455
|
+
</fig-header>
|
|
434
456
|
<fig-field>
|
|
435
457
|
<label>Chit</label>
|
|
436
458
|
<hstack>
|
|
@@ -473,13 +495,17 @@
|
|
|
473
495
|
</hstack>
|
|
474
496
|
</fig-field>
|
|
475
497
|
|
|
476
|
-
<
|
|
498
|
+
<fig-header>
|
|
499
|
+
<h2>Tooltip</h2>
|
|
500
|
+
</fig-header>
|
|
477
501
|
<p>Some paragraph text here with a
|
|
478
502
|
<fig-tooltip text="Tooltip text">
|
|
479
503
|
<em>Tooltip</em>
|
|
480
504
|
</fig-tooltip> for more information.
|
|
481
505
|
</p>
|
|
482
|
-
<
|
|
506
|
+
<fig-header>
|
|
507
|
+
<h2>Field</h2>
|
|
508
|
+
</fig-header>
|
|
483
509
|
<fig-field direction="horizontal">
|
|
484
510
|
<label>Horizontal</label>
|
|
485
511
|
<fig-input-text value=""
|
|
@@ -490,7 +516,9 @@
|
|
|
490
516
|
<fig-input-text value=""
|
|
491
517
|
placeholder="Field placeholder"></fig-input-text>
|
|
492
518
|
</fig-field>
|
|
493
|
-
<
|
|
519
|
+
<fig-header>
|
|
520
|
+
<h2>Slider</h2>
|
|
521
|
+
</fig-header>
|
|
494
522
|
<fig-field>
|
|
495
523
|
<label>Default slider</label>
|
|
496
524
|
<fig-slider default="25"
|
|
@@ -524,7 +552,7 @@
|
|
|
524
552
|
<label>Stepper slider</label>
|
|
525
553
|
<fig-slider type="stepper"
|
|
526
554
|
value="25"
|
|
527
|
-
default="
|
|
555
|
+
default="75"
|
|
528
556
|
step="25">
|
|
529
557
|
<datalist>
|
|
530
558
|
<option value="0"></option>
|
|
@@ -538,9 +566,8 @@
|
|
|
538
566
|
<fig-field direction="horizontal">
|
|
539
567
|
<label>Stepper slider (auto)</label>
|
|
540
568
|
<fig-slider type="stepper"
|
|
541
|
-
value="
|
|
542
|
-
|
|
543
|
-
min="0"
|
|
569
|
+
value="3"
|
|
570
|
+
min="1"
|
|
544
571
|
max="10"
|
|
545
572
|
step="1"
|
|
546
573
|
text="true">
|
|
@@ -560,10 +587,14 @@
|
|
|
560
587
|
</datalist>
|
|
561
588
|
</fig-slider>
|
|
562
589
|
</fig-field>
|
|
563
|
-
<
|
|
590
|
+
<fig-header>
|
|
591
|
+
<h2>Spinner</h2>
|
|
592
|
+
</fig-header>
|
|
564
593
|
<fig-spinner></fig-spinner>
|
|
565
594
|
|
|
566
|
-
<
|
|
595
|
+
<fig-header>
|
|
596
|
+
<h2>Misc.</h2>
|
|
597
|
+
</fig-header>
|
|
567
598
|
<hstack>
|
|
568
599
|
<fig-tooltip text="Tooltip"
|
|
569
600
|
delay="0">
|
package/fig.css
CHANGED
|
@@ -444,7 +444,7 @@
|
|
|
444
444
|
@media (prefers-color-scheme: dark) {
|
|
445
445
|
:root {
|
|
446
446
|
--icon-chevron: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5.87868 7.12132L8 9.24264L10.1213 7.12132' stroke='rgb(255 255 255 / 100%)' stroke-linecap='round'/%3E%3C/svg%3E%0A");
|
|
447
|
-
--handle-shadow: 0px 0 0 0.75px rgba(
|
|
447
|
+
--handle-shadow: 0px 0 0 0.75px 0px 0 0 0.75px rgba(0, 0, 0, 0.1),
|
|
448
448
|
0px 0px 0.5px 0px rgba(255, 255, 255, 0.1);
|
|
449
449
|
--figma-color-bg-ghost-hover: rgba(255, 255, 255, 0.05);
|
|
450
450
|
--figma-color-bordertranslucent: rgba(255, 255, 255, 0.1);
|
|
@@ -1224,7 +1224,7 @@ input[type="checkbox"].switch:after {
|
|
|
1224
1224
|
height: calc(1rem - 2px);
|
|
1225
1225
|
border-radius: 0.5rem;
|
|
1226
1226
|
margin: 1px;
|
|
1227
|
-
transform: translate(calc(-0.5rem
|
|
1227
|
+
transform: translate(calc(-0.5rem));
|
|
1228
1228
|
transition: var(--input-transition);
|
|
1229
1229
|
box-shadow: var(--handle-shadow);
|
|
1230
1230
|
}
|
|
@@ -1247,6 +1247,9 @@ input[type="checkbox"].switch:checked:after {
|
|
|
1247
1247
|
input[type="checkbox"].switch:disabled {
|
|
1248
1248
|
background-color: var(--figma-color-bg-tertiary);
|
|
1249
1249
|
cursor: not-allowed;
|
|
1250
|
+
&:after {
|
|
1251
|
+
background-color: var(--figma-color-bg);
|
|
1252
|
+
}
|
|
1250
1253
|
}
|
|
1251
1254
|
|
|
1252
1255
|
input[type="checkbox"].switch:focus {
|
|
@@ -1494,18 +1497,6 @@ fig-slider {
|
|
|
1494
1497
|
&::before {
|
|
1495
1498
|
display: none;
|
|
1496
1499
|
}
|
|
1497
|
-
/* Default tick */
|
|
1498
|
-
&::after {
|
|
1499
|
-
content: "";
|
|
1500
|
-
display: block;
|
|
1501
|
-
width: var(--slider-tick-size);
|
|
1502
|
-
height: var(--slider-tick-size);
|
|
1503
|
-
border-radius: 100%;
|
|
1504
|
-
background: var(--figma-color-icon);
|
|
1505
|
-
position: absolute;
|
|
1506
|
-
left: calc(var(--default) * 100% - var(--slider-tick-size) / 2);
|
|
1507
|
-
top: calc(50% - var(--slider-tick-size) / 2);
|
|
1508
|
-
}
|
|
1509
1500
|
}
|
|
1510
1501
|
}
|
|
1511
1502
|
|
|
@@ -1729,6 +1720,9 @@ fig-slider {
|
|
|
1729
1720
|
font-size: 0;
|
|
1730
1721
|
background: var(--figma-color-icon-tertiary);
|
|
1731
1722
|
display: block;
|
|
1723
|
+
&[default] {
|
|
1724
|
+
background: var(--figma-color-icon);
|
|
1725
|
+
}
|
|
1732
1726
|
|
|
1733
1727
|
&:first-child:last-child {
|
|
1734
1728
|
margin: 0 auto;
|
|
@@ -2280,3 +2274,87 @@ fig-segmented-control {
|
|
|
2280
2274
|
transform: rotate(360deg);
|
|
2281
2275
|
}
|
|
2282
2276
|
}
|
|
2277
|
+
|
|
2278
|
+
fig-input-joystick {
|
|
2279
|
+
--size: 1.5rem;
|
|
2280
|
+
display: inline-flex;
|
|
2281
|
+
gap: var(--spacer-2);
|
|
2282
|
+
.fig-input-joystick-plane-container {
|
|
2283
|
+
display: flex;
|
|
2284
|
+
width: 1.5rem;
|
|
2285
|
+
height: 1.5rem;
|
|
2286
|
+
place-items: center;
|
|
2287
|
+
}
|
|
2288
|
+
.fig-input-joystick-plane {
|
|
2289
|
+
display: inline-grid;
|
|
2290
|
+
place-items: center;
|
|
2291
|
+
position: relative;
|
|
2292
|
+
width: var(--size);
|
|
2293
|
+
height: var(--size);
|
|
2294
|
+
flex-shrink: 0;
|
|
2295
|
+
&:hover {
|
|
2296
|
+
cursor: grab;
|
|
2297
|
+
--size: 3rem;
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
.fig-input-joystick-plane > * {
|
|
2301
|
+
grid-area: 1/1;
|
|
2302
|
+
}
|
|
2303
|
+
.fig-input-joystick-guides {
|
|
2304
|
+
position: absolute;
|
|
2305
|
+
width: var(--size);
|
|
2306
|
+
height: var(--size);
|
|
2307
|
+
border: 1px solid var(--figma-color-border);
|
|
2308
|
+
border-radius: var(--radius-medium);
|
|
2309
|
+
overflow: hidden;
|
|
2310
|
+
background: var(--figma-color-bg-secondary);
|
|
2311
|
+
|
|
2312
|
+
&:before {
|
|
2313
|
+
content: "";
|
|
2314
|
+
position: absolute;
|
|
2315
|
+
height: 0;
|
|
2316
|
+
border-left: 1px solid var(--figma-color-border);
|
|
2317
|
+
height: 100%;
|
|
2318
|
+
top: 0;
|
|
2319
|
+
left: calc(50% - 0.5px);
|
|
2320
|
+
pointer-events: none;
|
|
2321
|
+
}
|
|
2322
|
+
&:after {
|
|
2323
|
+
content: "";
|
|
2324
|
+
position: absolute;
|
|
2325
|
+
height: 0;
|
|
2326
|
+
border-top: 1px solid var(--figma-color-border);
|
|
2327
|
+
width: 100%;
|
|
2328
|
+
top: calc(50% - 0.5px);
|
|
2329
|
+
left: 0;
|
|
2330
|
+
pointer-events: none;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
.fig-input-joystick-plane:hover .fig-input-joystick-guides {
|
|
2334
|
+
background: linear-gradient(
|
|
2335
|
+
45deg,
|
|
2336
|
+
transparent calc(50% - 0.5px),
|
|
2337
|
+
var(--figma-color-border) calc(50% - 0.5px),
|
|
2338
|
+
var(--figma-color-border) calc(50% + 0.5px),
|
|
2339
|
+
transparent calc(50% + 0.5px)
|
|
2340
|
+
),
|
|
2341
|
+
linear-gradient(
|
|
2342
|
+
-45deg,
|
|
2343
|
+
transparent calc(50% - 0.5px),
|
|
2344
|
+
var(--figma-color-border) calc(50% - 0.5px),
|
|
2345
|
+
var(--figma-color-border) calc(50% + 0.5px),
|
|
2346
|
+
transparent calc(50% + 0.5px)
|
|
2347
|
+
),
|
|
2348
|
+
var(--figma-color-bg-secondary);
|
|
2349
|
+
}
|
|
2350
|
+
.fig-input-joystick-handle {
|
|
2351
|
+
position: absolute;
|
|
2352
|
+
z-index: 1;
|
|
2353
|
+
width: 0.5rem;
|
|
2354
|
+
height: 0.5rem;
|
|
2355
|
+
background: var(--figma-color-icon-onbrand);
|
|
2356
|
+
box-shadow: var(--handle-shadow);
|
|
2357
|
+
border-radius: 50%;
|
|
2358
|
+
transform: translate(-50%, -50%);
|
|
2359
|
+
}
|
|
2360
|
+
}
|
package/fig.js
CHANGED
|
@@ -673,7 +673,6 @@ class FigSlider extends HTMLElement {
|
|
|
673
673
|
}
|
|
674
674
|
#regenerateInnerHTML() {
|
|
675
675
|
this.value = Number(this.getAttribute("value") || 0);
|
|
676
|
-
this.default = this.getAttribute("default") || null;
|
|
677
676
|
this.type = this.getAttribute("type") || "range";
|
|
678
677
|
this.text = this.getAttribute("text") || false;
|
|
679
678
|
this.units = this.getAttribute("units") || "";
|
|
@@ -685,6 +684,7 @@ class FigSlider extends HTMLElement {
|
|
|
685
684
|
this.max = Number(this.getAttribute("max") || defaults.max);
|
|
686
685
|
this.step = Number(this.getAttribute("step") || defaults.step);
|
|
687
686
|
this.color = this.getAttribute("color") || defaults?.color;
|
|
687
|
+
this.default = this.getAttribute("default") || this.min;
|
|
688
688
|
|
|
689
689
|
if (this.color) {
|
|
690
690
|
this.style.setProperty("--color", this.color);
|
|
@@ -758,6 +758,14 @@ class FigSlider extends HTMLElement {
|
|
|
758
758
|
this.inputContainer.append(this.datalist);
|
|
759
759
|
this.input.setAttribute("list", this.datalist.getAttribute("id"));
|
|
760
760
|
}
|
|
761
|
+
if (this.datalist) {
|
|
762
|
+
let defaultOption = this.datalist.querySelector(
|
|
763
|
+
`option[value='${this.default}']`
|
|
764
|
+
);
|
|
765
|
+
if (defaultOption) {
|
|
766
|
+
defaultOption.setAttribute("default", "true");
|
|
767
|
+
}
|
|
768
|
+
}
|
|
761
769
|
if (this.figInputText) {
|
|
762
770
|
this.figInputText.removeEventListener("input", this.handleTextInput);
|
|
763
771
|
this.figInputText.addEventListener(
|
|
@@ -843,15 +851,14 @@ class FigSlider extends HTMLElement {
|
|
|
843
851
|
}
|
|
844
852
|
}
|
|
845
853
|
#calculateNormal(value) {
|
|
846
|
-
let min = Number(this.
|
|
847
|
-
let max = Number(this.
|
|
848
|
-
|
|
849
|
-
return (val - min) / (max - min);
|
|
854
|
+
let min = Number(this.min);
|
|
855
|
+
let max = Number(this.max);
|
|
856
|
+
return (Number(value) - min) / (max - min);
|
|
850
857
|
}
|
|
851
858
|
#syncProperties() {
|
|
852
859
|
let complete = this.#calculateNormal(this.value);
|
|
853
|
-
let defaultValue = this.#calculateNormal(this.default);
|
|
854
860
|
this.style.setProperty("--slider-complete", complete);
|
|
861
|
+
let defaultValue = this.#calculateNormal(this.default);
|
|
855
862
|
this.style.setProperty("--default", defaultValue);
|
|
856
863
|
this.style.setProperty("--unchanged", complete === defaultValue ? 1 : 0);
|
|
857
864
|
}
|
|
@@ -885,6 +892,8 @@ class FigInputText extends HTMLElement {
|
|
|
885
892
|
this.value = this.getAttribute("value") || "";
|
|
886
893
|
this.type = this.getAttribute("type") || "text";
|
|
887
894
|
this.placeholder = this.getAttribute("placeholder") || "";
|
|
895
|
+
this.name = this.getAttribute("name") || null;
|
|
896
|
+
|
|
888
897
|
if (this.type === "number") {
|
|
889
898
|
if (this.getAttribute("step")) {
|
|
890
899
|
this.step = Number(this.getAttribute("step"));
|
|
@@ -903,6 +912,7 @@ class FigInputText extends HTMLElement {
|
|
|
903
912
|
|
|
904
913
|
let html = `<input
|
|
905
914
|
type="${this.type}"
|
|
915
|
+
${this.name ? `name="${this.name}"` : ""}
|
|
906
916
|
placeholder="${this.placeholder}"
|
|
907
917
|
value="${
|
|
908
918
|
this.type === "number" ? this.#transformNumber(this.value) : this.value
|
|
@@ -1031,6 +1041,7 @@ class FigInputText extends HTMLElement {
|
|
|
1031
1041
|
"min",
|
|
1032
1042
|
"max",
|
|
1033
1043
|
"transform",
|
|
1044
|
+
"name",
|
|
1034
1045
|
];
|
|
1035
1046
|
}
|
|
1036
1047
|
|
|
@@ -1071,8 +1082,12 @@ class FigInputText extends HTMLElement {
|
|
|
1071
1082
|
this.input.setAttribute(name, newValue);
|
|
1072
1083
|
}
|
|
1073
1084
|
break;
|
|
1085
|
+
case "name":
|
|
1086
|
+
this[name] = this.input[name] = newValue;
|
|
1087
|
+
this.input.setAttribute("name", newValue);
|
|
1088
|
+
break;
|
|
1074
1089
|
default:
|
|
1075
|
-
this[name] = this.input[name] =
|
|
1090
|
+
this[name] = this.input[name] = newValue;
|
|
1076
1091
|
break;
|
|
1077
1092
|
}
|
|
1078
1093
|
}
|
|
@@ -1696,3 +1711,171 @@ class FigImage extends HTMLElement {
|
|
|
1696
1711
|
}
|
|
1697
1712
|
}
|
|
1698
1713
|
window.customElements.define("fig-image", FigImage);
|
|
1714
|
+
|
|
1715
|
+
class FigInputJoystick extends HTMLElement {
|
|
1716
|
+
constructor() {
|
|
1717
|
+
super();
|
|
1718
|
+
|
|
1719
|
+
this.position = { x: 0.5, y: 0.5 };
|
|
1720
|
+
this.value = [0.5, 0.5];
|
|
1721
|
+
this.isDragging = false;
|
|
1722
|
+
this.isShiftHeld = false;
|
|
1723
|
+
|
|
1724
|
+
// Initialize position
|
|
1725
|
+
requestAnimationFrame(() => {
|
|
1726
|
+
this.precision = this.getAttribute("precision") || 3;
|
|
1727
|
+
this.precision = parseInt(this.precision);
|
|
1728
|
+
this.transform = this.getAttribute("transform") || 1;
|
|
1729
|
+
this.transform = Number(this.transform);
|
|
1730
|
+
this.text = this.getAttribute("text") === "true";
|
|
1731
|
+
|
|
1732
|
+
this.render();
|
|
1733
|
+
|
|
1734
|
+
this.setupListeners();
|
|
1735
|
+
|
|
1736
|
+
this.cursor.style.left = `${this.position.x * 100}%`;
|
|
1737
|
+
this.cursor.style.top = `${this.position.y * 100}%`;
|
|
1738
|
+
if (this.text) {
|
|
1739
|
+
this.xInput.value = this.position.x.toFixed(this.precision);
|
|
1740
|
+
this.yInput.value = this.position.y.toFixed(this.precision);
|
|
1741
|
+
}
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
render() {
|
|
1746
|
+
this.innerHTML = `
|
|
1747
|
+
<div class="fig-input-joystick-plane-container">
|
|
1748
|
+
<div class="fig-input-joystick-plane">
|
|
1749
|
+
<div class="fig-input-joystick-guides"></div>
|
|
1750
|
+
<div class="fig-input-joystick-handle"></div>
|
|
1751
|
+
</div>
|
|
1752
|
+
</div>
|
|
1753
|
+
${
|
|
1754
|
+
this.text
|
|
1755
|
+
? `<fig-input-text
|
|
1756
|
+
type="number"
|
|
1757
|
+
name="x"
|
|
1758
|
+
step="0.01"
|
|
1759
|
+
value="${this.position.x}"
|
|
1760
|
+
min="0"
|
|
1761
|
+
max="1">
|
|
1762
|
+
<span slot="prepend">X</span>
|
|
1763
|
+
</fig-input-text>
|
|
1764
|
+
<fig-input-text
|
|
1765
|
+
type="number"
|
|
1766
|
+
name="y"
|
|
1767
|
+
step="0.01"
|
|
1768
|
+
min="0"
|
|
1769
|
+
max="1"
|
|
1770
|
+
value="${this.position.y}">
|
|
1771
|
+
<span slot="prepend">Y</span>
|
|
1772
|
+
</fig-input-text>`
|
|
1773
|
+
: ""
|
|
1774
|
+
}
|
|
1775
|
+
`;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
setupListeners() {
|
|
1779
|
+
this.plane = this.querySelector(".fig-input-joystick-plane");
|
|
1780
|
+
this.cursor = this.querySelector(".fig-input-joystick-handle");
|
|
1781
|
+
if (this.text) {
|
|
1782
|
+
this.xInput = this.querySelector("fig-input-text[name='x']");
|
|
1783
|
+
this.yInput = this.querySelector("fig-input-text[name='y']");
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
this.plane.addEventListener("mousedown", this.handleMouseDown.bind(this));
|
|
1787
|
+
window.addEventListener("keydown", this.handleKeyDown.bind(this));
|
|
1788
|
+
window.addEventListener("keyup", this.handleKeyUp.bind(this));
|
|
1789
|
+
|
|
1790
|
+
this.xInput.addEventListener("input", this.handleXInput.bind(this));
|
|
1791
|
+
this.yInput.addEventListener("input", this.handleYInput.bind(this));
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
handleXInput(e) {
|
|
1795
|
+
this.position.x = e.target.value;
|
|
1796
|
+
this.#syncHandlePosition();
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
handleYInput(e) {
|
|
1800
|
+
this.position.y = e.target.value;
|
|
1801
|
+
this.#syncHandlePosition();
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
snapToGuide(value) {
|
|
1805
|
+
if (!this.isShiftHeld) return value;
|
|
1806
|
+
if (value < 0.1) return 0;
|
|
1807
|
+
if (value > 0.9) return 1;
|
|
1808
|
+
if (value > 0.4 && value < 0.6) return 0.5;
|
|
1809
|
+
return value;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
snapToDiagonal(x, y) {
|
|
1813
|
+
if (!this.isShiftHeld) return { x, y };
|
|
1814
|
+
const diff = Math.abs(x - y);
|
|
1815
|
+
if (diff < 0.1) return { x: (x + y) / 2, y: (x + y) / 2 };
|
|
1816
|
+
if (Math.abs(1 - x - y) < 0.1) return { x, y: 1 - x };
|
|
1817
|
+
return { x, y };
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
updatePosition(e) {
|
|
1821
|
+
const rect = this.plane.getBoundingClientRect();
|
|
1822
|
+
let x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
|
1823
|
+
let y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height));
|
|
1824
|
+
|
|
1825
|
+
// Invert Y coordinate to match typical coordinate system
|
|
1826
|
+
y = 1 - y;
|
|
1827
|
+
|
|
1828
|
+
x = this.snapToGuide(x);
|
|
1829
|
+
y = this.snapToGuide(y);
|
|
1830
|
+
|
|
1831
|
+
const snapped = this.snapToDiagonal(x, y);
|
|
1832
|
+
this.position = snapped;
|
|
1833
|
+
this.value = [snapped.x, snapped.y];
|
|
1834
|
+
|
|
1835
|
+
this.cursor.style.left = `${snapped.x * 100}%`;
|
|
1836
|
+
this.cursor.style.top = `${(1 - snapped.y) * 100}%`; // Invert Y for display
|
|
1837
|
+
if (this.text) {
|
|
1838
|
+
this.xInput.setAttribute("value", snapped.x.toFixed(3));
|
|
1839
|
+
this.yInput.setAttribute("value", snapped.y.toFixed(3));
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
this.dispatchEvent(new CustomEvent("input", { detail: this.position }));
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
#syncHandlePosition() {
|
|
1846
|
+
this.cursor.style.left = `${this.position.x * 100}%`;
|
|
1847
|
+
this.cursor.style.top = `${(1 - this.position.y) * 100}%`;
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
handleMouseDown(e) {
|
|
1851
|
+
this.isDragging = true;
|
|
1852
|
+
this.updatePosition(e);
|
|
1853
|
+
|
|
1854
|
+
this.plane.style.cursor = "grabbing";
|
|
1855
|
+
|
|
1856
|
+
const handleMouseMove = (e) => {
|
|
1857
|
+
if (this.isDragging) this.updatePosition(e);
|
|
1858
|
+
};
|
|
1859
|
+
|
|
1860
|
+
const handleMouseUp = () => {
|
|
1861
|
+
this.isDragging = false;
|
|
1862
|
+
this.plane.style.cursor = "";
|
|
1863
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
1864
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
1865
|
+
this.dispatchEvent(new CustomEvent("change", { detail: this.position }));
|
|
1866
|
+
};
|
|
1867
|
+
|
|
1868
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
1869
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
handleKeyDown(e) {
|
|
1873
|
+
if (e.key === "Shift") this.isShiftHeld = true;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
handleKeyUp(e) {
|
|
1877
|
+
if (e.key === "Shift") this.isShiftHeld = false;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
customElements.define("fig-input-joystick", FigInputJoystick);
|