@rogieking/figui3 6.9.2 → 6.9.4

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/fig-editor.js CHANGED
@@ -309,7 +309,7 @@ function gradientInterpolationClause(gradient) {
309
309
  */
310
310
  class FigFillPicker extends HTMLElement {
311
311
  #trigger = null;
312
- #chit = null;
312
+ #swatch = null;
313
313
  #dialog = null;
314
314
  #activeTab = "solid";
315
315
  anchorElement = null;
@@ -377,7 +377,7 @@ class FigFillPicker extends HTMLElement {
377
377
  requestAnimationFrame(() => {
378
378
  this.#setupTrigger();
379
379
  this.#parseValue();
380
- this.#updateChit();
380
+ this.#updateSwatch();
381
381
  });
382
382
  }
383
383
 
@@ -405,7 +405,7 @@ class FigFillPicker extends HTMLElement {
405
405
  if (this.#video.url && this.#video.url.startsWith("blob:")) {
406
406
  URL.revokeObjectURL(this.#video.url);
407
407
  }
408
- if (this.#chit) this.#chit.removeAttribute("selected");
408
+ if (this.#swatch) this.#swatch.removeAttribute("selected");
409
409
  if (this.#trigger) {
410
410
  this.#trigger.removeEventListener("click", this.#boundTriggerClick);
411
411
  this.#trigger.removeEventListener("keydown", this.#boundTriggerKeydown);
@@ -423,19 +423,19 @@ class FigFillPicker extends HTMLElement {
423
423
  );
424
424
 
425
425
  if (!child) {
426
- // Scenario 1: Empty - create fig-chit
427
- this.#chit = document.createElement("fig-chit");
428
- this.#chit.setAttribute("background", "#D9D9D9");
429
- this.appendChild(this.#chit);
430
- this.#trigger = this.#chit;
431
- } else if (child.tagName === "FIG-CHIT") {
432
- // Scenario 2: Has fig-chit - use and populate it
433
- this.#chit = child;
426
+ // Scenario 1: Empty - create fig-swatch
427
+ this.#swatch = document.createElement("fig-swatch");
428
+ this.#swatch.setAttribute("background", "#D9D9D9");
429
+ this.appendChild(this.#swatch);
430
+ this.#trigger = this.#swatch;
431
+ } else if (child.matches("fig-swatch")) {
432
+ // Scenario 2: Has swatch - use and populate it
433
+ this.#swatch = child;
434
434
  this.#trigger = child;
435
435
  } else {
436
436
  // Scenario 3: Other element - trigger only, no populate
437
437
  this.#trigger = child;
438
- this.#chit = null;
438
+ this.#swatch = null;
439
439
  }
440
440
 
441
441
  this.#syncTriggerA11y();
@@ -444,10 +444,10 @@ class FigFillPicker extends HTMLElement {
444
444
  this.#trigger.removeEventListener("keydown", this.#boundTriggerKeydown);
445
445
  this.#trigger.addEventListener("keydown", this.#boundTriggerKeydown);
446
446
 
447
- // Prevent fig-chit's internal color input from opening system picker
448
- if (this.#chit) {
447
+ // Prevent the swatch's internal color input from opening system picker
448
+ if (this.#swatch) {
449
449
  requestAnimationFrame(() => {
450
- const input = this.#chit.querySelector('input[type="color"]');
450
+ const input = this.#swatch.querySelector('input[type="color"]');
451
451
  if (input) {
452
452
  input.remove();
453
453
  }
@@ -549,8 +549,8 @@ class FigFillPicker extends HTMLElement {
549
549
  }
550
550
  }
551
551
 
552
- #updateChit() {
553
- if (!this.#chit) return;
552
+ #updateSwatch() {
553
+ if (!this.#swatch) return;
554
554
 
555
555
  let bg;
556
556
  let bgSize = "cover";
@@ -591,17 +591,17 @@ class FigFillPicker extends HTMLElement {
591
591
  break;
592
592
  default:
593
593
  const slot = this.#customSlots[this.#fillType];
594
- bg = slot?.element?.getAttribute("chit-background") || "#D9D9D9";
594
+ bg = slot?.element?.getAttribute("swatch-background") || "#D9D9D9";
595
595
  }
596
596
 
597
- this.#chit.setAttribute("background", bg);
598
- this.#chit.style.setProperty("--chit-bg-size", bgSize);
599
- this.#chit.style.setProperty("--chit-bg-position", bgPosition);
597
+ this.#swatch.setAttribute("background", bg);
598
+ this.#swatch.style.setProperty("--swatch-bg-size", bgSize);
599
+ this.#swatch.style.setProperty("--swatch-bg-position", bgPosition);
600
600
 
601
601
  if (this.#fillType === "solid") {
602
- this.#chit.setAttribute("alpha", this.#color.a);
602
+ this.#swatch.setAttribute("alpha", this.#color.a);
603
603
  } else {
604
- this.#chit.removeAttribute("alpha");
604
+ this.#swatch.removeAttribute("alpha");
605
605
  }
606
606
  }
607
607
 
@@ -630,7 +630,7 @@ class FigFillPicker extends HTMLElement {
630
630
  const gamutEl = this.#dialog.querySelector(".fig-fill-picker-gamut");
631
631
  if (gamutEl) gamutEl.value = this.#gamut;
632
632
 
633
- if (this.#chit) this.#chit.setAttribute("selected", "true");
633
+ if (this.#swatch) this.#swatch.setAttribute("selected", "true");
634
634
 
635
635
  this.#dialog.open = true;
636
636
 
@@ -796,7 +796,7 @@ class FigFillPicker extends HTMLElement {
796
796
  });
797
797
 
798
798
  const onDialogClose = () => {
799
- if (this.#chit) this.#chit.removeAttribute("selected");
799
+ if (this.#swatch) this.#swatch.removeAttribute("selected");
800
800
  this.#emitChange();
801
801
  this.dispatchEvent(new CustomEvent("close"));
802
802
  };
@@ -890,7 +890,7 @@ class FigFillPicker extends HTMLElement {
890
890
  });
891
891
  }
892
892
 
893
- this.#updateChit();
893
+ this.#updateSwatch();
894
894
  this.#emitInput();
895
895
  }
896
896
 
@@ -1399,7 +1399,7 @@ class FigFillPicker extends HTMLElement {
1399
1399
  this.#opacitySlider.setAttribute("color", hex);
1400
1400
  }
1401
1401
 
1402
- this.#updateChit();
1402
+ this.#updateSwatch();
1403
1403
  }
1404
1404
 
1405
1405
  // ============ GRADIENT TAB ============
@@ -1582,7 +1582,7 @@ class FigFillPicker extends HTMLElement {
1582
1582
  ...this.#gradient,
1583
1583
  ...detail.gradient,
1584
1584
  });
1585
- this.#updateChit();
1585
+ this.#updateSwatch();
1586
1586
  this.#updateGradientStopsList();
1587
1587
  };
1588
1588
  gradientBarInput.addEventListener("input", (e) => {
@@ -1652,7 +1652,7 @@ class FigFillPicker extends HTMLElement {
1652
1652
  );
1653
1653
  }
1654
1654
 
1655
- this.#updateChit();
1655
+ this.#updateSwatch();
1656
1656
  }
1657
1657
 
1658
1658
  #updateGradientStopsList() {
@@ -1851,14 +1851,14 @@ class FigFillPicker extends HTMLElement {
1851
1851
  this.#image.scaleMode = e.target.value;
1852
1852
  scaleInput.style.display = e.target.value === "tile" ? "block" : "none";
1853
1853
  this.#updateImagePreview(preview);
1854
- this.#updateChit();
1854
+ this.#updateSwatch();
1855
1855
  this.#emitInput();
1856
1856
  });
1857
1857
 
1858
1858
  scaleInput.addEventListener("input", (e) => {
1859
1859
  this.#image.scale = parseFloat(e.target.value) || 100;
1860
1860
  this.#updateImagePreview(preview);
1861
- this.#updateChit();
1861
+ this.#updateSwatch();
1862
1862
  this.#emitInput();
1863
1863
  });
1864
1864
 
@@ -1867,7 +1867,7 @@ class FigFillPicker extends HTMLElement {
1867
1867
  if (!src) return;
1868
1868
  this.#image.url = src;
1869
1869
  this.#updateImagePreview(preview);
1870
- this.#updateChit();
1870
+ this.#updateSwatch();
1871
1871
  this.#emitInput();
1872
1872
  });
1873
1873
 
@@ -1875,7 +1875,7 @@ class FigFillPicker extends HTMLElement {
1875
1875
  if (preview.src) return;
1876
1876
  this.#image.url = null;
1877
1877
  this.#updateImagePreview(preview);
1878
- this.#updateChit();
1878
+ this.#updateSwatch();
1879
1879
  this.#emitInput();
1880
1880
  });
1881
1881
 
@@ -2011,7 +2011,7 @@ class FigFillPicker extends HTMLElement {
2011
2011
  scaleModeDropdown.addEventListener("change", (e) => {
2012
2012
  this.#video.scaleMode = e.target.value;
2013
2013
  this.#updateVideoPreviewStyle(preview);
2014
- this.#updateChit();
2014
+ this.#updateSwatch();
2015
2015
  this.#emitInput();
2016
2016
  });
2017
2017
 
@@ -2021,7 +2021,7 @@ class FigFillPicker extends HTMLElement {
2021
2021
  this.#video.url = src;
2022
2022
  this.#updateVideoPreviewStyle(preview);
2023
2023
  preview.play?.();
2024
- this.#updateChit();
2024
+ this.#updateSwatch();
2025
2025
  this.#emitInput();
2026
2026
  });
2027
2027
 
@@ -2029,7 +2029,7 @@ class FigFillPicker extends HTMLElement {
2029
2029
  if (preview.src) return;
2030
2030
  this.#video.url = null;
2031
2031
  this.#updateVideoPreviewStyle(preview);
2032
- this.#updateChit();
2032
+ this.#updateSwatch();
2033
2033
  this.#emitInput();
2034
2034
  });
2035
2035
 
@@ -2453,7 +2453,7 @@ class FigFillPicker extends HTMLElement {
2453
2453
 
2454
2454
  // ============ EVENT EMITTERS ============
2455
2455
  #emitInput() {
2456
- this.#updateChit();
2456
+ this.#updateSwatch();
2457
2457
  this.dispatchEvent(
2458
2458
  new CustomEvent("input", {
2459
2459
  bubbles: true,
@@ -2523,7 +2523,7 @@ class FigFillPicker extends HTMLElement {
2523
2523
  switch (name) {
2524
2524
  case "value":
2525
2525
  this.#parseValue();
2526
- this.#updateChit();
2526
+ this.#updateSwatch();
2527
2527
  if (this.#dialog) {
2528
2528
  // Update dialog UI if open - but don't rebuild if user is dragging
2529
2529
  if (!this.#isDraggingColor) {
package/fig-lab.css CHANGED
@@ -9,19 +9,24 @@
9
9
  */
10
10
 
11
11
  fig-field-slider {
12
+ --fig-field-slider-elastic-distance: var(--spacer-2);
13
+ --fig-field-slider-elastic-size: 0px;
14
+ --fig-field-slider-elastic-position-offset: 0px;
15
+ --fig-field-slider-elastic-transition: 0.1s ease-out;
16
+ --fig-field-slider-height: 2rem;
17
+ --figma-focus-outline-offset: 1px;
18
+ --fig-field-slider-progress-shadow: inset 0px 0.75px 0px 0px light-dark(transparent, rgba(255, 255, 255, 0.1));
19
+ --field-text-shadow: 0 1px 1.5px
20
+ light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
12
21
  display: block;
13
22
  position: relative;
14
23
  width: 100%;
24
+ height: var(--fig-field-slider-height);
15
25
  border-radius: var(--radius-medium);
16
- --field-text-shadow: 0 1px 1.5px
17
- light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
18
-
19
-
20
- &:focus-within {
21
- outline: var(--figma-focus-outline);
22
- outline-offset: var(--figma-focus-outline-offset);
23
- }
24
-
26
+ transition:
27
+ width var(--fig-field-slider-elastic-transition),
28
+ transform var(--fig-field-slider-elastic-transition);
29
+
25
30
  label {
26
31
  pointer-events: none;
27
32
  z-index: 1;
@@ -29,7 +34,6 @@ fig-field-slider {
29
34
 
30
35
  &[disabled]:not([disabled="false"]) {
31
36
  pointer-events: none;
32
-
33
37
  label,
34
38
  input {
35
39
  color: var(--figma-color-text-disabled);
@@ -46,16 +50,32 @@ fig-field-slider {
46
50
  }
47
51
  }
48
52
 
53
+ &[type="opacity"] fig-slider {
54
+ --slider-checkerboard: var(--checkerboard);
55
+ }
56
+
57
+
49
58
  fig-field:not([direction="vertical"]) {
50
59
  position: relative;
51
60
  padding-left: var(--spacer-2-5);
52
61
  display: flex;
62
+ height: 100%;
53
63
 
54
64
  & > label {
55
65
  min-width: 0;
56
66
  max-width: none;
57
67
  width: 100%;
58
68
  flex: 1 1 auto;
69
+ color: var(--figma-color-text);
70
+ padding: 0;
71
+ display: flex;
72
+ align-items: center;
73
+ gap: var(--spacer-1);
74
+ margin:0;
75
+ height: 100%;
76
+ fig-icon:first-child{
77
+ margin-left: calc(var(--spacer-1) * -1);
78
+ }
59
79
  }
60
80
 
61
81
  fig-slider {
@@ -70,21 +90,57 @@ fig-field-slider {
70
90
  var(--figma-color-text-secondary),
71
91
  var(--figma-color-text)
72
92
  );
73
- --slider-thumb-height: calc(
93
+ /*--slider-thumb-height: calc(
74
94
  var(--spacer-2) + (var(--spacer-3) - var(--spacer-2)) *
75
95
  min(var(--slider-complete), calc(1 - var(--slider-complete))) * 2
76
- );
96
+ );*/
97
+ --slider-thumb-height: calc(var(--slider-height) - var(--spacer-3));
77
98
  --slider-border-radius: var(--radius-medium);
78
99
  --slider-tick-width: 0.125rem;
79
100
  --slider-tick-height: var(--spacer-2);
80
101
  --slider-tick-radius: var(--radius-medium);
81
102
  --slider-stepper-padding: 0;
82
- --slider-handle-shadow: inset 0 0 0 var(--slider-thumb-height)
83
- var(--slider-thumb-color) !important;
84
- --slider-thumb-opacity: calc(
85
- min(var(--slider-complete), calc(1 - var(--slider-complete))) * 2
103
+ --slider-thumb-inset-threshold: calc(
104
+ var(--slider-thumb-width) + var(--spacer-2) * 2
105
+ );
106
+ --slider-thumb-inset-distance: var(--slider-percent);
107
+ --slider-thumb-edge-offset: clamp(
108
+ calc(-1 * var(--spacer-2)),
109
+ calc(
110
+ var(--slider-thumb-inset-threshold) -
111
+ var(--slider-thumb-inset-distance) - var(--spacer-2)
112
+ ),
113
+ 0px
86
114
  );
87
- --slider-tick-opacity: 1;
115
+ --slider-thumb-travel-offset: var(--slider-thumb-edge-offset);
116
+ --slider-handle-shadow:
117
+ inset 0 0 0 var(--slider-thumb-height) var(--slider-thumb-color),
118
+ var(--handle-shadow) !important;
119
+ /*--slider-thumb-opacity: calc(
120
+ min(var(--slider-complete), calc(1 - var(--slider-complete))) * 2
121
+ );*/
122
+ --slider-thumb-opacity: 0;
123
+ --slider-tick-opacity: 0.5;
124
+
125
+ &[type="delta"] {
126
+ --slider-thumb-inset-distance: max(
127
+ calc(var(--slider-percent) - var(--start-percent)),
128
+ calc(var(--start-percent) - var(--slider-percent))
129
+ );
130
+ --slider-delta-right-inset: max(var(--slider-delta-direction, 1), 0);
131
+ --slider-thumb-travel-offset: calc(
132
+ var(--slider-thumb-edge-offset) * var(--slider-delta-right-inset)
133
+ );
134
+ }
135
+
136
+ &[type="stepper"] {
137
+ --slider-thumb-travel-offset: 0px;
138
+ }
139
+
140
+ &[type="stepper"] .fig-slider-input-container input[type="range"] {
141
+ width: 100% !important;
142
+ margin-left: 0;
143
+ }
88
144
 
89
145
  &:has(input[type="range"]:focus-within) {
90
146
  --slider-thumb-outline: var(--figma-focus-outline) !important;
@@ -102,16 +158,25 @@ fig-field-slider {
102
158
  inset: 0;
103
159
  pointer-events: none;
104
160
  border-radius: var(--slider-border-radius);
105
- box-shadow: inset 0 0 0 1px var(--figma-color-border) !important;
161
+ box-shadow: inset 0 0 0 1px var(--figma-color-bordertranslucent) !important;
106
162
  }
107
163
  }
108
164
  &::before {
109
- background: var(--figma-color-bg-tertiary) !important;
165
+ box-shadow: var(--fig-field-slider-progress-shadow) !important;
166
+ background: var(--figma-color-bordertranslucent) !important;
110
167
  min-width: 0 !important;
111
168
  box-shadow: none !important;
112
169
  }
113
170
  input[type="range"] {
114
171
  border-radius: 0 !important;
172
+ width: calc(100% - var(--spacer-2)) !important;
173
+ margin-left: var(--spacer-2);
174
+ &::-webkit-slider-thumb {
175
+ margin-left: var(--slider-thumb-travel-offset);
176
+ }
177
+ &::-moz-range-thumb {
178
+ margin-left: var(--slider-thumb-travel-offset);
179
+ }
115
180
  }
116
181
  }
117
182
 
@@ -120,6 +185,7 @@ fig-field-slider {
120
185
  }
121
186
 
122
187
  &[type="delta"] .fig-slider-input-container::before {
188
+ background: var(--figma-color-bordertranslucent) !important;
123
189
  --left-start: calc(
124
190
  var(--start-percent) - var(--slider-thumb-width) / 2
125
191
  ) !important;
@@ -143,6 +209,64 @@ fig-field-slider {
143
209
  ) !important;
144
210
  width: var(--abs-width) !important;
145
211
  }
212
+
213
+ &:is([type="hue"], [type="opacity"]) {
214
+ .fig-slider-input-container {
215
+ &::after {
216
+ content: "";
217
+ position: absolute;
218
+ inset: 0;
219
+ z-index: 0;
220
+ pointer-events: none;
221
+ border-radius: var(--slider-border-radius);
222
+ }
223
+
224
+ input[type="range"] {
225
+ position: relative;
226
+ z-index: 1;
227
+ &::-webkit-slider-runnable-track {
228
+ background: transparent;
229
+ }
230
+ &::-moz-range-track {
231
+ background: transparent;
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ &[type="hue"] .fig-slider-input-container::after {
238
+ --fig-field-slider-hue-fade-size: 30%;
239
+ background: var(--bg-hue);
240
+ mask-image: linear-gradient(
241
+ to right,
242
+ transparent 0%,
243
+ rgba(0, 0, 0, 0.16) calc(var(--slider-percent) - var(--fig-field-slider-hue-fade-size)),
244
+ black var(--slider-percent),
245
+ rgba(0, 0, 0, 0.16) calc(var(--slider-percent) + var(--fig-field-slider-hue-fade-size)),
246
+ transparent 100%
247
+ );
248
+ -webkit-mask-image: linear-gradient(
249
+ to right,
250
+ transparent 0%,
251
+ rgba(0, 0, 0, 0.16) calc(var(--slider-percent) - var(--fig-field-slider-hue-fade-size)),
252
+ black var(--slider-percent),
253
+ rgba(0, 0, 0, 0.16) calc(var(--slider-percent) + var(--fig-field-slider-hue-fade-size)),
254
+ transparent 100%
255
+ );
256
+ }
257
+
258
+ &[type="opacity"] .fig-slider-input-container::after {
259
+ opacity: calc(0.2 + var(--slider-complete) * 0.65);
260
+ background:
261
+ linear-gradient(to right, transparent, var(--color)),
262
+ var(--slider-checkerboard);
263
+ }
264
+ }
265
+ &:hover,
266
+ &:focus-within {
267
+ fig-slider {
268
+ --slider-thumb-opacity: 1;
269
+ }
146
270
  }
147
271
  datalist {
148
272
  mask-image: linear-gradient(
@@ -176,6 +300,7 @@ fig-field-slider {
176
300
  }
177
301
  input {
178
302
  field-sizing: content;
303
+ font-variant-numeric: tabular-nums;
179
304
  border-radius: var(--radius-small);
180
305
  width: auto;
181
306
  flex: 0 0 auto;
@@ -184,6 +309,12 @@ fig-field-slider {
184
309
  }
185
310
  }
186
311
  }
312
+
313
+ &[data-elastic-dragging="true"] {
314
+ width: calc(100% + var(--fig-field-slider-elastic-size));
315
+ transform: translateX(var(--fig-field-slider-elastic-position-offset));
316
+ transition: none;
317
+ }
187
318
  }
188
319
 
189
320
  /* Canvas Control */