@rogieking/figui3 6.9.8 → 6.10.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/components.css +28 -4
- package/dist/components.css +1 -1
- package/dist/fig-lab.css +1 -1
- package/dist/fig-lab.js +27 -29
- package/dist/fig.css +1 -1
- package/fig-lab.css +51 -53
- package/fig-lab.js +165 -57
- package/package.json +1 -1
package/fig-lab.css
CHANGED
|
@@ -9,23 +9,37 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
fig-field-slider {
|
|
12
|
-
--fig-field-slider-elastic-distance: var(--spacer-2);
|
|
12
|
+
--fig-field-slider-elastic-distance: calc(var(--spacer-2) + 0.25rem);
|
|
13
13
|
--fig-field-slider-elastic-size: 0px;
|
|
14
|
-
--fig-field-slider-elastic-
|
|
15
|
-
--fig-field-slider-elastic-
|
|
14
|
+
--fig-field-slider-elastic-scale: 1;
|
|
15
|
+
--fig-field-slider-elastic-origin: left center;
|
|
16
|
+
--fig-field-slider-elastic-transition: 0.18s cubic-bezier(0.2, 1.45, 0.35, 1);
|
|
16
17
|
--fig-field-slider-height: 2rem;
|
|
18
|
+
--fig-field-slider-vertical-padding: var(--spacer-1);
|
|
19
|
+
--fig-field-slider-horizontal-padding: var(--spacer-3);
|
|
17
20
|
--figma-focus-outline-offset: 1px;
|
|
18
21
|
--fig-field-slider-progress-shadow: inset 0px 0.75px 0px 0px light-dark(transparent, rgba(255, 255, 255, 0.1));
|
|
19
22
|
--field-text-shadow: 0 1px 1.5px
|
|
20
23
|
light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
|
|
24
|
+
--fig-field-slider-fig-slider-height: calc(var(--fig-field-slider-height) - var(--fig-field-slider-vertical-padding) * 2);
|
|
25
|
+
--fig-field-slider-fig-slider-thumb-height: calc(var(--fig-field-slider-fig-slider-height) - var(--spacer-2-5));
|
|
26
|
+
|
|
21
27
|
display: block;
|
|
22
28
|
position: relative;
|
|
23
29
|
width: 100%;
|
|
24
30
|
height: var(--fig-field-slider-height);
|
|
25
31
|
border-radius: var(--radius-medium);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
32
|
+
transform-origin: var(--fig-field-slider-elastic-origin);
|
|
33
|
+
transition: transform var(--fig-field-slider-elastic-transition);
|
|
34
|
+
padding-top: var(--fig-field-slider-vertical-padding);
|
|
35
|
+
padding-bottom: var(--fig-field-slider-vertical-padding);
|
|
36
|
+
padding-left: var(--fig-field-slider-horizontal-padding);
|
|
37
|
+
padding-right: var(--fig-field-slider-horizontal-padding);
|
|
38
|
+
|
|
39
|
+
&[size="large"]{
|
|
40
|
+
--fig-field-slider-vertical-padding: 0px;
|
|
41
|
+
--fig-field-slider-fig-slider-thumb-height: calc(var(--fig-field-slider-fig-slider-height) - var(--spacer-3));
|
|
42
|
+
}
|
|
29
43
|
|
|
30
44
|
label {
|
|
31
45
|
pointer-events: none;
|
|
@@ -57,7 +71,7 @@ fig-field-slider {
|
|
|
57
71
|
|
|
58
72
|
fig-field:not([direction="vertical"]) {
|
|
59
73
|
position: relative;
|
|
60
|
-
padding-left: var(--spacer-2
|
|
74
|
+
padding-left: var(--spacer-2);
|
|
61
75
|
display: flex;
|
|
62
76
|
height: 100%;
|
|
63
77
|
|
|
@@ -83,8 +97,8 @@ fig-field-slider {
|
|
|
83
97
|
inset: 0;
|
|
84
98
|
padding: 0;
|
|
85
99
|
background-color: transparent;
|
|
86
|
-
--slider-height:
|
|
87
|
-
--slider-field-height:
|
|
100
|
+
--slider-height: var(--fig-field-slider-fig-slider-height);
|
|
101
|
+
--slider-field-height: calc(var(--fig-field-slider-height) - var(--fig-field-slider-vertical-padding) * 2);
|
|
88
102
|
--slider-thumb-width: var(--spacer-1);
|
|
89
103
|
--slider-thumb-color: light-dark(
|
|
90
104
|
var(--figma-color-text-secondary),
|
|
@@ -94,7 +108,7 @@ fig-field-slider {
|
|
|
94
108
|
var(--spacer-2) + (var(--spacer-3) - var(--spacer-2)) *
|
|
95
109
|
min(var(--slider-complete), calc(1 - var(--slider-complete))) * 2
|
|
96
110
|
);*/
|
|
97
|
-
--slider-thumb-height:
|
|
111
|
+
--slider-thumb-height: var(--fig-field-slider-fig-slider-thumb-height);
|
|
98
112
|
--slider-border-radius: var(--radius-medium);
|
|
99
113
|
--slider-tick-width: 0.125rem;
|
|
100
114
|
--slider-tick-height: var(--spacer-2);
|
|
@@ -317,8 +331,7 @@ fig-field-slider {
|
|
|
317
331
|
}
|
|
318
332
|
|
|
319
333
|
&[data-elastic-dragging="true"] {
|
|
320
|
-
|
|
321
|
-
transform: translateX(var(--fig-field-slider-elastic-position-offset));
|
|
334
|
+
transform: scaleX(var(--fig-field-slider-elastic-scale));
|
|
322
335
|
transition: none;
|
|
323
336
|
}
|
|
324
337
|
}
|
|
@@ -540,10 +553,18 @@ fig-input-oscillator {
|
|
|
540
553
|
|
|
541
554
|
.fig-input-oscillator-svg-container {
|
|
542
555
|
border-radius: var(--radius-medium);
|
|
543
|
-
|
|
544
|
-
padding: var(--spacer-3) var(--spacer-2);
|
|
556
|
+
padding: var(--spacer-3) var(--spacer-5);
|
|
545
557
|
margin-bottom: var(--spacer-2);
|
|
546
558
|
overflow: hidden;
|
|
559
|
+
position: relative;
|
|
560
|
+
|
|
561
|
+
&::before{
|
|
562
|
+
position: absolute;
|
|
563
|
+
inset: 0 var(--spacer-3);
|
|
564
|
+
content: "";
|
|
565
|
+
background: var(--figma-color-bg-secondary);
|
|
566
|
+
border-radius: var(--radius-medium);
|
|
567
|
+
}
|
|
547
568
|
|
|
548
569
|
&:is(:hover, :active, :focus, :focus-visible, :focus-within) {
|
|
549
570
|
overflow: visible;
|
|
@@ -558,6 +579,8 @@ fig-input-oscillator {
|
|
|
558
579
|
width: 100%;
|
|
559
580
|
aspect-ratio: var(--aspect-ratio);
|
|
560
581
|
overflow: visible;
|
|
582
|
+
position: relative;
|
|
583
|
+
z-index: 1;
|
|
561
584
|
|
|
562
585
|
.fig-input-oscillator-handle{
|
|
563
586
|
opacity: 0;
|
|
@@ -616,56 +639,31 @@ fig-input-oscillator {
|
|
|
616
639
|
.fig-input-oscillator-waves {
|
|
617
640
|
display: flex;
|
|
618
641
|
flex-direction: column;
|
|
619
|
-
gap:
|
|
642
|
+
gap: 0;
|
|
620
643
|
}
|
|
621
644
|
|
|
622
645
|
.fig-input-oscillator-wave {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
> .fig-input-oscillator-wave-summary {
|
|
626
|
-
min-height: var(--control-height);
|
|
627
|
-
padding: 0;
|
|
628
|
-
|
|
629
|
-
> label {
|
|
630
|
-
display: inline-flex;
|
|
631
|
-
align-items: center;
|
|
632
|
-
gap: var(--spacer-1);
|
|
633
|
-
min-width: 0;
|
|
646
|
+
margin-bottom: 0;
|
|
634
647
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
> .fig-input-oscillator-remove-button {
|
|
641
|
-
margin-left: auto;
|
|
648
|
+
> fig-header {
|
|
649
|
+
.fig-input-oscillator-remove-button,
|
|
650
|
+
.fig-input-oscillator-add-type-button {
|
|
651
|
+
flex-shrink: 0;
|
|
642
652
|
}
|
|
643
653
|
}
|
|
644
654
|
}
|
|
645
655
|
|
|
646
656
|
.fig-input-oscillator-field {
|
|
647
|
-
--fig-field-left-padding: 0;
|
|
648
|
-
--fig-field-right-padding: 0;
|
|
649
|
-
|
|
650
|
-
> fig-slider {
|
|
651
|
-
min-width: 0;
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
.fig-input-oscillator-add-wave {
|
|
656
|
-
display: grid;
|
|
657
|
-
grid-template-columns: auto;
|
|
658
|
-
justify-content: end;
|
|
659
657
|
width: 100%;
|
|
658
|
+
}
|
|
660
659
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
660
|
+
.fig-input-oscillator-add-type-button {
|
|
661
|
+
> fig-dropdown,
|
|
662
|
+
> fig-dropdown > select {
|
|
663
|
+
width: 100%;
|
|
664
|
+
height: 100%;
|
|
665
|
+
min-width: 100%;
|
|
666
|
+
padding: 0;
|
|
669
667
|
}
|
|
670
668
|
}
|
|
671
669
|
|
package/fig-lab.js
CHANGED
|
@@ -25,6 +25,8 @@ class FigFieldSlider extends HTMLElement {
|
|
|
25
25
|
#isElasticTracking = false;
|
|
26
26
|
#elasticMaxPx = 0;
|
|
27
27
|
#elasticRangeRect = null;
|
|
28
|
+
#elasticHostWidth = 0;
|
|
29
|
+
#elasticPointerId = null;
|
|
28
30
|
#boundHandleSliderInput = null;
|
|
29
31
|
#boundHandleSliderChange = null;
|
|
30
32
|
#boundHandleElasticPointerDown = this.#handleElasticPointerDown.bind(this);
|
|
@@ -38,6 +40,12 @@ class FigFieldSlider extends HTMLElement {
|
|
|
38
40
|
"color",
|
|
39
41
|
"text",
|
|
40
42
|
"full",
|
|
43
|
+
"elastic",
|
|
44
|
+
"size",
|
|
45
|
+
"name",
|
|
46
|
+
"class",
|
|
47
|
+
"data-wave-index",
|
|
48
|
+
"data-active",
|
|
41
49
|
"data-elastic-dragging",
|
|
42
50
|
"style",
|
|
43
51
|
]);
|
|
@@ -111,6 +119,7 @@ class FigFieldSlider extends HTMLElement {
|
|
|
111
119
|
this.#focusSyncFrame = 0;
|
|
112
120
|
}
|
|
113
121
|
this.#clearPendingClick();
|
|
122
|
+
this.#stopElasticTracking();
|
|
114
123
|
this.#resetElasticPull();
|
|
115
124
|
this.#unbindRangeInput();
|
|
116
125
|
this.#unbindSliderEvents();
|
|
@@ -323,19 +332,25 @@ class FigFieldSlider extends HTMLElement {
|
|
|
323
332
|
|
|
324
333
|
#handleElasticPointerDown(event) {
|
|
325
334
|
if (event.button !== 0 || this.hasAttribute("disabled")) return;
|
|
335
|
+
if (this.getAttribute("elastic") === "false") return;
|
|
326
336
|
if (event.target?.closest?.("fig-input-number")) return;
|
|
327
337
|
const rangeInput =
|
|
328
338
|
this.#slider?.querySelector('input[type="range"]') ?? this.#rangeInput;
|
|
329
339
|
if (!rangeInput) return;
|
|
340
|
+
this.#stopElasticTracking();
|
|
341
|
+
this.#resetElasticPull();
|
|
330
342
|
this.#rangeInput = rangeInput;
|
|
331
343
|
this.#isElasticTracking = true;
|
|
344
|
+
this.#elasticPointerId = event.pointerId;
|
|
332
345
|
this.#elasticMaxPx = this.#readElasticDistance();
|
|
333
346
|
const rect = rangeInput.getBoundingClientRect();
|
|
347
|
+
const hostRect = this.getBoundingClientRect();
|
|
334
348
|
this.#elasticRangeRect = {
|
|
335
349
|
left: rect.left,
|
|
336
350
|
right: rect.right,
|
|
337
351
|
width: rect.width,
|
|
338
352
|
};
|
|
353
|
+
this.#elasticHostWidth = hostRect.width;
|
|
339
354
|
window.addEventListener("pointermove", this.#boundHandleElasticPointerMove, {
|
|
340
355
|
passive: true,
|
|
341
356
|
});
|
|
@@ -345,19 +360,40 @@ class FigFieldSlider extends HTMLElement {
|
|
|
345
360
|
window.addEventListener("pointercancel", this.#boundHandleElasticPointerEnd, {
|
|
346
361
|
once: true,
|
|
347
362
|
});
|
|
363
|
+
window.addEventListener("blur", this.#boundHandleElasticPointerEnd, {
|
|
364
|
+
once: true,
|
|
365
|
+
});
|
|
348
366
|
}
|
|
349
367
|
|
|
350
368
|
#handleElasticPointerMove(event) {
|
|
351
369
|
if (!this.#isElasticTracking) return;
|
|
370
|
+
if (event.pointerId !== this.#elasticPointerId) return;
|
|
371
|
+
if (event.buttons === 0) {
|
|
372
|
+
this.#handleElasticPointerEnd(event);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
352
375
|
this.#updateElasticPull(event.clientX);
|
|
353
376
|
}
|
|
354
377
|
|
|
355
|
-
#handleElasticPointerEnd() {
|
|
378
|
+
#handleElasticPointerEnd(event) {
|
|
379
|
+
if (
|
|
380
|
+
event?.pointerId !== undefined &&
|
|
381
|
+
this.#elasticPointerId !== null &&
|
|
382
|
+
event.pointerId !== this.#elasticPointerId
|
|
383
|
+
) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.#stopElasticTracking();
|
|
387
|
+
this.#resetElasticPull();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
#stopElasticTracking() {
|
|
356
391
|
window.removeEventListener("pointermove", this.#boundHandleElasticPointerMove);
|
|
357
392
|
window.removeEventListener("pointerup", this.#boundHandleElasticPointerEnd);
|
|
358
393
|
window.removeEventListener("pointercancel", this.#boundHandleElasticPointerEnd);
|
|
394
|
+
window.removeEventListener("blur", this.#boundHandleElasticPointerEnd);
|
|
359
395
|
this.#isElasticTracking = false;
|
|
360
|
-
this.#
|
|
396
|
+
this.#elasticPointerId = null;
|
|
361
397
|
}
|
|
362
398
|
|
|
363
399
|
#handleContextMenu(event) {
|
|
@@ -445,11 +481,15 @@ class FigFieldSlider extends HTMLElement {
|
|
|
445
481
|
Math.min(this.#elasticMaxPx, overshoot * 0.5),
|
|
446
482
|
);
|
|
447
483
|
const stretch = Math.abs(offset);
|
|
484
|
+
const scale = this.#elasticHostWidth
|
|
485
|
+
? (this.#elasticHostWidth + stretch) / this.#elasticHostWidth
|
|
486
|
+
: 1;
|
|
448
487
|
this.dataset.elasticDragging = "true";
|
|
449
488
|
this.style.setProperty("--fig-field-slider-elastic-size", `${stretch}px`);
|
|
489
|
+
this.style.setProperty("--fig-field-slider-elastic-scale", `${scale}`);
|
|
450
490
|
this.style.setProperty(
|
|
451
|
-
"--fig-field-slider-elastic-
|
|
452
|
-
offset < 0 ?
|
|
491
|
+
"--fig-field-slider-elastic-origin",
|
|
492
|
+
offset < 0 ? "right center" : "left center",
|
|
453
493
|
);
|
|
454
494
|
}
|
|
455
495
|
|
|
@@ -457,12 +497,14 @@ class FigFieldSlider extends HTMLElement {
|
|
|
457
497
|
this.#clearElasticPull();
|
|
458
498
|
this.#elasticMaxPx = 0;
|
|
459
499
|
this.#elasticRangeRect = null;
|
|
500
|
+
this.#elasticHostWidth = 0;
|
|
501
|
+
this.#elasticPointerId = null;
|
|
460
502
|
}
|
|
461
503
|
|
|
462
504
|
#clearElasticPull() {
|
|
463
505
|
this.removeAttribute("data-elastic-dragging");
|
|
464
506
|
this.style.removeProperty("--fig-field-slider-elastic-size");
|
|
465
|
-
this.style.removeProperty("--fig-field-slider-elastic-
|
|
507
|
+
this.style.removeProperty("--fig-field-slider-elastic-scale");
|
|
466
508
|
}
|
|
467
509
|
|
|
468
510
|
#valueFromPointer(event) {
|
|
@@ -558,7 +600,7 @@ class FigFieldSlider extends HTMLElement {
|
|
|
558
600
|
}
|
|
559
601
|
|
|
560
602
|
#forwardSliderEvent(type, event) {
|
|
561
|
-
event.
|
|
603
|
+
event.stopImmediatePropagation();
|
|
562
604
|
if (type === "change") {
|
|
563
605
|
this.#resetElasticPull();
|
|
564
606
|
}
|
|
@@ -1797,11 +1839,13 @@ class FigInputOscillator extends HTMLElement {
|
|
|
1797
1839
|
#bounds = null;
|
|
1798
1840
|
#handleAmplitude = null;
|
|
1799
1841
|
#handleFrequency = null;
|
|
1800
|
-
#addTypeControl = null;
|
|
1801
1842
|
#fields = [];
|
|
1802
1843
|
#typeControls = [];
|
|
1803
1844
|
#waveRows = [];
|
|
1845
|
+
#waveGroups = [];
|
|
1846
|
+
#expandedWaveIndices = new Set();
|
|
1804
1847
|
#resizeObserver = null;
|
|
1848
|
+
#activeFieldInput = null;
|
|
1805
1849
|
|
|
1806
1850
|
static TYPES = [
|
|
1807
1851
|
{ name: "Wave", value: "sine" },
|
|
@@ -2064,12 +2108,6 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2064
2108
|
#getWaveControlsHTML(disabled) {
|
|
2065
2109
|
return `<div class="fig-input-oscillator-waves">
|
|
2066
2110
|
${this.#waves.map((wave, index) => this.#getWaveRowHTML(wave, index, disabled)).join("")}
|
|
2067
|
-
<hstack class="fig-input-oscillator-add-wave">
|
|
2068
|
-
<fig-button class="fig-input-oscillator-add-type-button" type="select" variant="ghost" icon aria-label="Choose waveform type"${disabled}>
|
|
2069
|
-
<fig-icon name="settings"></fig-icon>
|
|
2070
|
-
${this.#getWaveTypeDropdownHTML("fig-input-oscillator-add-type", "sine", disabled)}
|
|
2071
|
-
</fig-button>
|
|
2072
|
-
</hstack>
|
|
2073
2111
|
</div>`;
|
|
2074
2112
|
}
|
|
2075
2113
|
|
|
@@ -2077,18 +2115,27 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2077
2115
|
const removeDisabled = disabled || this.#waves.length <= 1 ? " disabled" : "";
|
|
2078
2116
|
const active = index === this.#activeWaveIndex ? " data-active" : "";
|
|
2079
2117
|
const label = FigInputOscillator.#labelForType(wave.type);
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
<
|
|
2084
|
-
|
|
2118
|
+
const open = this.#expandedWaveIndices.has(index) ? ' open="true"' : ' open="false"';
|
|
2119
|
+
return `<fig-group class="fig-input-oscillator-wave" collapsible borderless compact="true"${open} data-wave-index="${index}">
|
|
2120
|
+
<fig-header borderless>
|
|
2121
|
+
<h3>${label}</h3>
|
|
2122
|
+
<fig-tooltip text="Remove form">
|
|
2123
|
+
<fig-button class="fig-input-oscillator-remove-button" variant="ghost" icon data-wave-index="${index}" aria-label="Remove form"${removeDisabled}><fig-icon name="minus"></fig-icon></fig-button>
|
|
2124
|
+
</fig-tooltip>
|
|
2125
|
+
<fig-tooltip text="Add form">
|
|
2126
|
+
<fig-button class="fig-input-oscillator-add-type-button" type="select" variant="ghost" icon data-wave-index="${index}" aria-label="Add form"${disabled}>
|
|
2127
|
+
<fig-icon name="add"></fig-icon>
|
|
2128
|
+
${this.#getWaveTypeDropdownHTML("fig-input-oscillator-add-type", "sine", disabled, index)}
|
|
2129
|
+
</fig-button>
|
|
2130
|
+
</fig-tooltip>
|
|
2131
|
+
</fig-header>
|
|
2085
2132
|
<div class="fig-input-oscillator-fields" data-wave-index="${index}"${active}>
|
|
2086
2133
|
${this.#getNumberFieldHTML(index, "frequency", "Frequency", 0.1, 16, 0.1, "")}
|
|
2087
2134
|
${this.#getNumberFieldHTML(index, "amplitude", "Amplitude", -4, 4, 0.1, "")}
|
|
2088
2135
|
${this.#getNumberFieldHTML(index, "phase", "Phase", -360, 360, 1, "°")}
|
|
2089
2136
|
${this.#getNumberFieldHTML(index, "offset", "Offset", -4, 4, 0.1, "")}
|
|
2090
2137
|
</div>
|
|
2091
|
-
</
|
|
2138
|
+
</fig-group>`;
|
|
2092
2139
|
}
|
|
2093
2140
|
|
|
2094
2141
|
#getWaveTypeDropdownHTML(className, value, disabled, index = null) {
|
|
@@ -2099,9 +2146,9 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2099
2146
|
<label>${type.name}</label>
|
|
2100
2147
|
</option>`;
|
|
2101
2148
|
}).join("");
|
|
2102
|
-
const indexAttr =
|
|
2103
|
-
|
|
2104
|
-
return `<fig-dropdown class="${className}" value="${value}" experimental="modern"${
|
|
2149
|
+
const indexAttr =
|
|
2150
|
+
index === null ? "" : ` data-wave-index="${FigInputOscillator.#escapeAttribute(String(index))}"`;
|
|
2151
|
+
return `<fig-dropdown class="${className}" value="${value}" experimental="modern" type="dropdown" label="Add form"${indexAttr}${disabled}>${options}</fig-dropdown>`;
|
|
2105
2152
|
}
|
|
2106
2153
|
|
|
2107
2154
|
#getNumberFieldHTML(index, name, label, min, max, step, units) {
|
|
@@ -2110,11 +2157,7 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2110
2157
|
? ` units="${FigInputOscillator.#escapeAttribute(units)}"`
|
|
2111
2158
|
: "";
|
|
2112
2159
|
const wave = this.#waves[index] || FigInputOscillator.#defaultWave();
|
|
2113
|
-
return `<fig-field class="fig-input-oscillator-field" direction="horizontal" data-wave-index="${index}"
|
|
2114
|
-
<label>${label}</label>
|
|
2115
|
-
<fig-slider name="${name}" data-wave-index="${index}" value="${this.#round(wave[name])}" min="${min}" max="${max}" step="${step}" precision="${this.#precision}" text="true"${unitsAttr}${disabled}></fig-slider>
|
|
2116
|
-
</fig-field>
|
|
2117
|
-
`;
|
|
2160
|
+
return `<fig-field-slider class="fig-input-oscillator-field" label="${label}" direction="horizontal" name="${name}" data-wave-index="${index}" value="${this.#round(wave[name])}" min="${min}" max="${max}" step="${step}" precision="${this.#precision}" elastic="false"${unitsAttr}${disabled}></fig-field-slider>`;
|
|
2118
2161
|
}
|
|
2119
2162
|
|
|
2120
2163
|
#cacheRefs() {
|
|
@@ -2125,14 +2168,34 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2125
2168
|
this.#bounds = this.querySelector(".fig-input-oscillator-bounds");
|
|
2126
2169
|
this.#handleAmplitude = this.querySelector('[data-handle="amplitude"]');
|
|
2127
2170
|
this.#handleFrequency = this.querySelector('[data-handle="frequency"]');
|
|
2128
|
-
this.#addTypeControl = this.querySelector(".fig-input-oscillator-add-type");
|
|
2129
2171
|
this.#typeControls = Array.from(
|
|
2130
2172
|
this.querySelectorAll(".fig-input-oscillator-wave-type"),
|
|
2131
2173
|
);
|
|
2132
|
-
this.#fields = Array.from(this.querySelectorAll("fig-slider[name]"));
|
|
2133
|
-
this.#
|
|
2134
|
-
|
|
2174
|
+
this.#fields = Array.from(this.querySelectorAll("fig-field-slider[name]"));
|
|
2175
|
+
this.#waveGroups = Array.from(
|
|
2176
|
+
this.querySelectorAll("fig-group.fig-input-oscillator-wave"),
|
|
2135
2177
|
);
|
|
2178
|
+
this.#waveRows = Array.from(
|
|
2179
|
+
this.querySelectorAll(".fig-input-oscillator-fields"),
|
|
2180
|
+
);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
#reindexExpandedWaves(removedIndex) {
|
|
2184
|
+
const nextExpanded = new Set();
|
|
2185
|
+
for (const index of this.#expandedWaveIndices) {
|
|
2186
|
+
if (index < removedIndex) nextExpanded.add(index);
|
|
2187
|
+
else if (index > removedIndex) nextExpanded.add(index - 1);
|
|
2188
|
+
}
|
|
2189
|
+
this.#expandedWaveIndices = nextExpanded;
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
#reindexExpandedWavesAfterInsert(insertIndex) {
|
|
2193
|
+
const nextExpanded = new Set();
|
|
2194
|
+
for (const index of this.#expandedWaveIndices) {
|
|
2195
|
+
nextExpanded.add(index >= insertIndex ? index + 1 : index);
|
|
2196
|
+
}
|
|
2197
|
+
nextExpanded.add(insertIndex);
|
|
2198
|
+
this.#expandedWaveIndices = nextExpanded;
|
|
2136
2199
|
}
|
|
2137
2200
|
|
|
2138
2201
|
#setupResizeObserver() {
|
|
@@ -2308,12 +2371,17 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2308
2371
|
for (const field of this.#fields) {
|
|
2309
2372
|
field.addEventListener("input", (event) => {
|
|
2310
2373
|
event.stopPropagation();
|
|
2311
|
-
this.#
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2374
|
+
this.#activeFieldInput = field;
|
|
2375
|
+
try {
|
|
2376
|
+
this.#applyFieldValue(
|
|
2377
|
+
this.#indexFromElement(field),
|
|
2378
|
+
field.getAttribute("name"),
|
|
2379
|
+
event.detail ?? event.currentTarget?.value ?? event.target?.value,
|
|
2380
|
+
"input",
|
|
2381
|
+
);
|
|
2382
|
+
} finally {
|
|
2383
|
+
this.#activeFieldInput = null;
|
|
2384
|
+
}
|
|
2317
2385
|
});
|
|
2318
2386
|
field.addEventListener("change", (event) => {
|
|
2319
2387
|
event.stopPropagation();
|
|
@@ -2326,31 +2394,64 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2326
2394
|
});
|
|
2327
2395
|
}
|
|
2328
2396
|
|
|
2329
|
-
for (const
|
|
2330
|
-
|
|
2331
|
-
this.#setActiveWave(this.#indexFromElement(
|
|
2397
|
+
for (const group of this.#waveGroups) {
|
|
2398
|
+
group.addEventListener("pointerdown", () => {
|
|
2399
|
+
this.#setActiveWave(this.#indexFromElement(group));
|
|
2400
|
+
});
|
|
2401
|
+
group.addEventListener("focusin", () => {
|
|
2402
|
+
this.#setActiveWave(this.#indexFromElement(group));
|
|
2332
2403
|
});
|
|
2333
|
-
|
|
2334
|
-
this.#
|
|
2404
|
+
group.addEventListener("openchange", (event) => {
|
|
2405
|
+
const index = this.#indexFromElement(group);
|
|
2406
|
+
if (event.detail?.open) {
|
|
2407
|
+
this.#expandedWaveIndices.add(index);
|
|
2408
|
+
} else {
|
|
2409
|
+
this.#expandedWaveIndices.delete(index);
|
|
2410
|
+
}
|
|
2335
2411
|
});
|
|
2336
2412
|
}
|
|
2337
2413
|
|
|
2338
|
-
this
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2414
|
+
for (const control of this.querySelectorAll(".fig-input-oscillator-add-type")) {
|
|
2415
|
+
const stopHeaderToggle = (event) => {
|
|
2416
|
+
event.stopPropagation();
|
|
2417
|
+
};
|
|
2418
|
+
control.addEventListener("pointerdown", stopHeaderToggle);
|
|
2419
|
+
control.addEventListener("click", stopHeaderToggle);
|
|
2420
|
+
control.addEventListener("change", (event) => {
|
|
2421
|
+
if (event.target !== control) return;
|
|
2422
|
+
if (this.#isDisabled()) return;
|
|
2423
|
+
const insertAfter = this.#indexFromElement(control);
|
|
2424
|
+
const insertIndex = insertAfter + 1;
|
|
2425
|
+
const type = this.#normalizeType(event.detail ?? control.value);
|
|
2426
|
+
this.#waves.splice(insertIndex, 0, FigInputOscillator.#defaultWave(type));
|
|
2427
|
+
this.#reindexExpandedWavesAfterInsert(insertIndex);
|
|
2428
|
+
this.#activeWaveIndex = insertIndex;
|
|
2429
|
+
this.#render();
|
|
2430
|
+
this.#emit("input");
|
|
2431
|
+
this.#emit("change");
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
for (const button of this.querySelectorAll(".fig-input-oscillator-add-type-button")) {
|
|
2436
|
+
const stopHeaderToggle = (event) => {
|
|
2437
|
+
event.stopPropagation();
|
|
2438
|
+
};
|
|
2439
|
+
button.addEventListener("pointerdown", stopHeaderToggle);
|
|
2440
|
+
button.addEventListener("click", stopHeaderToggle);
|
|
2441
|
+
button.closest("fig-tooltip")?.addEventListener("pointerdown", stopHeaderToggle);
|
|
2442
|
+
button.closest("fig-tooltip")?.addEventListener("click", stopHeaderToggle);
|
|
2443
|
+
}
|
|
2348
2444
|
|
|
2349
2445
|
for (const button of this.querySelectorAll(".fig-input-oscillator-remove-button")) {
|
|
2350
|
-
button.addEventListener("
|
|
2446
|
+
button.addEventListener("pointerdown", (event) => {
|
|
2447
|
+
event.stopPropagation();
|
|
2448
|
+
});
|
|
2449
|
+
button.addEventListener("click", (event) => {
|
|
2450
|
+
event.stopPropagation();
|
|
2351
2451
|
if (this.#isDisabled() || this.#waves.length <= 1) return;
|
|
2352
2452
|
const index = this.#indexFromElement(button);
|
|
2353
2453
|
this.#waves.splice(index, 1);
|
|
2454
|
+
this.#reindexExpandedWaves(index);
|
|
2354
2455
|
this.#activeWaveIndex = Math.min(this.#activeWaveIndex, this.#waves.length - 1);
|
|
2355
2456
|
this.#render();
|
|
2356
2457
|
this.#emit("input");
|
|
@@ -2436,7 +2537,7 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2436
2537
|
...this.#waves[index],
|
|
2437
2538
|
[name]: next,
|
|
2438
2539
|
});
|
|
2439
|
-
this.#syncUI();
|
|
2540
|
+
this.#syncUI({ skipFieldSync: eventType == "input" });
|
|
2440
2541
|
this.#emit(eventType);
|
|
2441
2542
|
}
|
|
2442
2543
|
|
|
@@ -2548,9 +2649,9 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2548
2649
|
);
|
|
2549
2650
|
}
|
|
2550
2651
|
|
|
2551
|
-
#syncUI() {
|
|
2652
|
+
#syncUI({ skipFieldSync = false } = {}) {
|
|
2552
2653
|
this.#syncTypeControls();
|
|
2553
|
-
this.#syncFields();
|
|
2654
|
+
if (!skipFieldSync) this.#syncFields();
|
|
2554
2655
|
this.#syncActiveWave();
|
|
2555
2656
|
this.#updateWaveform();
|
|
2556
2657
|
}
|
|
@@ -2564,9 +2665,16 @@ class FigInputOscillator extends HTMLElement {
|
|
|
2564
2665
|
|
|
2565
2666
|
#syncFields() {
|
|
2566
2667
|
for (const field of this.#fields) {
|
|
2668
|
+
if (field === this.#activeFieldInput) continue;
|
|
2567
2669
|
const index = this.#indexFromElement(field);
|
|
2568
2670
|
const name = field.getAttribute("name");
|
|
2569
|
-
|
|
2671
|
+
const next = this.#round(this.#waves[index]?.[name] ?? 0);
|
|
2672
|
+
const slider = field.querySelector("fig-slider");
|
|
2673
|
+
if (slider) {
|
|
2674
|
+
slider.value = next;
|
|
2675
|
+
} else {
|
|
2676
|
+
field.setAttribute("value", String(next));
|
|
2677
|
+
}
|
|
2570
2678
|
}
|
|
2571
2679
|
}
|
|
2572
2680
|
|
package/package.json
CHANGED