@rogieking/figui3 11.5.0 → 11.6.1

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.css CHANGED
@@ -1,6 +1,10 @@
1
1
  /* Copyright (c) 2026 Rogie King. PolyForm Shield 1.0.0. See LICENSE. */
2
2
  @import url("fig-layer.css");
3
3
  @import url("fig-property.css");
4
+ @import url("fig-gradient-editor.css");
5
+ @import url("fig-popup-easing.css");
6
+ @import url("fig-popup-gradient.css");
7
+ @import url("fig-popup-palette.css");
4
8
 
5
9
  fig-input-point {
6
10
  display: inline-flex;
@@ -159,12 +163,6 @@ dialog[is="fig-toast"] {
159
163
  }
160
164
 
161
165
  /* Palette Editor */
162
- .fig-palette-editor-popup {
163
- width: 12rem;
164
- padding: 0;
165
- pointer-events: auto;
166
- }
167
-
168
166
  fig-palette-editor {
169
167
  display: flex;
170
168
  flex-direction: column;
@@ -330,168 +328,6 @@ fig-fill-picker {
330
328
  }
331
329
  }
332
330
 
333
- /* Gradient Tab */
334
- .fig-fill-picker-gradient-preview {
335
- aspect-ratio: auto;
336
- width: calc(100% - var(--spacer-3) * 2);
337
- margin: var(--spacer-2) var(--spacer-3);
338
- margin-top: var(--spacer-4);
339
- margin-bottom:0;
340
- background: transparent;
341
- &::after{
342
- display: none;
343
- }
344
- }
345
-
346
- fig-header.fig-fill-picker-gradient-header {
347
- .fig-fill-picker-gradient-type {
348
- display: flex;
349
- flex: 0 1 auto;
350
- min-width: 0;
351
- width: auto;
352
- }
353
-
354
- .fig-fill-picker-gradient-actions {
355
- flex: 0 0 auto;
356
- }
357
- }
358
-
359
- .fig-fill-picker-gradient-stops {
360
- .fig-fill-picker-gradient-stops-header {
361
- > span {
362
- flex: 1;
363
- }
364
- }
365
- }
366
-
367
- fig-field.fig-fill-picker-gradient-interpolation-field {
368
- display: flex;
369
- align-items: center;
370
- grid-template-columns: unset;
371
- grid-template-areas: unset;
372
- padding-left: var(--spacer-3);
373
- padding-right: var(--spacer-2);
374
- gap: var(--spacer-1);
375
-
376
- > *:not([slot="leading"]):not([slot="trailing"]):not(label) {
377
- grid-area: unset;
378
- }
379
- }
380
-
381
- .fig-fill-picker-gradient-interpolation-modes {
382
- flex: 1 1 auto;
383
- min-width: 0;
384
-
385
- fig-interpolation-swatch {
386
- pointer-events: none;
387
- }
388
- }
389
-
390
- /* Transparent select trigger sits on the icon button so its menu anchors here. */
391
- .fig-fill-picker-gradient-interpolation-more {
392
- position: relative;
393
- display: inline-flex;
394
- flex: 0 0 auto;
395
-
396
- > fig-button {
397
- pointer-events: none;
398
- }
399
-
400
- .fig-fill-picker-gradient-space {
401
- position: absolute;
402
- inset: 0;
403
- width: 100%;
404
- opacity: 0;
405
- }
406
-
407
- &:has(.fig-fill-picker-gradient-space:hover) > fig-button,
408
- &:has(.fig-fill-picker-gradient-space[open]) > fig-button {
409
- background-color: var(--figma-color-bg-transparent-hover);
410
- }
411
-
412
- &:has(.fig-fill-picker-gradient-space[data-focus-visible]) > fig-button {
413
- outline: var(--figma-focus-outline);
414
- outline-offset: var(--figma-focus-outline-offset);
415
- }
416
- }
417
-
418
- .fig-fill-picker-gradient-space {
419
- &::part(prepend) {
420
- display: none;
421
- }
422
-
423
- fig-select-option {
424
- min-height: 3rem;
425
-
426
- &:hover::before,
427
- &:focus-visible::before {
428
- background-color: var(--figma-color-bg-tertiary);
429
- }
430
- }
431
-
432
- .fig-fill-picker-gradient-interpolation-label {
433
- display: flex;
434
- flex-direction: column;
435
- justify-content: center;
436
- min-width: 0;
437
- line-height: 1.25;
438
- }
439
-
440
- .fig-fill-picker-gradient-interpolation-title,
441
- .fig-fill-picker-gradient-interpolation-subtitle {
442
- display: block;
443
- overflow: hidden;
444
- text-overflow: ellipsis;
445
- }
446
-
447
- .fig-fill-picker-gradient-interpolation-subtitle {
448
- color: var(--figma-color-text-tertiary);
449
- }
450
-
451
- fig-select-options.fig-fill-picker-gradient-interpolation-collapsed {
452
- overflow: hidden;
453
- }
454
- }
455
-
456
- .fig-fill-picker-gradient-stops-list {
457
- display: flex;
458
- flex-direction: column;
459
-
460
- fig-reorder {
461
- display: contents;
462
- }
463
- }
464
-
465
- .fig-fill-picker-gradient-stop-row {
466
- &.dragging {
467
- background-color: var(--figma-color-bg-selected);
468
- }
469
-
470
- .fig-fill-picker-gradient-stop-inputs {
471
- width: 100%;
472
- min-width: 0;
473
- }
474
-
475
- .fig-fill-picker-stop-position {
476
- flex: 0;
477
- flex-basis: 3rem;
478
- min-width: 0;
479
- width: 3rem;
480
- }
481
-
482
- .fig-fill-picker-stop-color {
483
- flex: 1;
484
- min-width: 0;
485
- fig-input-text {
486
- min-width: 0;
487
- }
488
- }
489
-
490
- .fig-fill-picker-stop-remove {
491
- flex-shrink: 0;
492
- }
493
- }
494
-
495
331
  /* Media Tabs (Image/Video/Webcam) */
496
332
  fig-field.fig-fill-picker-media-header {
497
333
  display: flex;
package/fig-editor.js CHANGED
@@ -1,6 +1,10 @@
1
1
  /* Copyright (c) 2026 Rogie King. PolyForm Shield 1.0.0. See LICENSE. */
2
2
  import "./fig.js";
3
3
  import "./fig-property.js";
4
+ import { figGradientCSS } from "./fig-gradient-editor.js";
5
+ import "./fig-popup-easing.js";
6
+ import "./fig-popup-gradient.js";
7
+ import "./fig-popup-palette.js";
4
8
 
5
9
  function figEditorDefineElement(name, constructor) {
6
10
  if (!customElements.get(name)) {
@@ -4240,6 +4244,29 @@ class FigFillPicker extends HTMLElement {
4240
4244
 
4241
4245
  // ============ GRADIENT TAB ============
4242
4246
  #initGradientTab() {
4247
+ {
4248
+ const container = this.#dialog.querySelector('[data-tab="gradient"]');
4249
+ const editor = document.createElement("fig-gradient-editor");
4250
+ editor.value = gradientToValueShape(this.#gradient);
4251
+ editor.setAttribute("color-space", this.#gamut);
4252
+ editor.toggleAttribute("disabled", this.#isDisabled());
4253
+ editor.pickerAnchor = this.#dialog;
4254
+ const syncFromEditor = (event) => {
4255
+ event.stopPropagation();
4256
+ if (!event.detail?.gradient) return;
4257
+ this.#gradient = lockFillPickerGradientInterpolation(
4258
+ event.detail.gradient,
4259
+ );
4260
+ this.#updateSwatch();
4261
+ if (event.type === "change") this.#emitChange();
4262
+ else this.#emitInput();
4263
+ };
4264
+ editor.addEventListener("input", syncFromEditor);
4265
+ editor.addEventListener("change", syncFromEditor);
4266
+ container.replaceChildren(editor);
4267
+ return;
4268
+ }
4269
+
4243
4270
  const container = this.#dialog.querySelector('[data-tab="gradient"]');
4244
4271
  const gradientType = figEditorCreateElement(
4245
4272
  "fig-select",
@@ -4817,6 +4844,14 @@ class FigFillPicker extends HTMLElement {
4817
4844
  const container = this.#dialog.querySelector('[data-tab="gradient"]');
4818
4845
  if (!container) return;
4819
4846
  this.#gradient = lockFillPickerGradientInterpolation(this.#gradient);
4847
+ const editor = container.querySelector("fig-gradient-editor");
4848
+ if (editor) {
4849
+ editor.value = this.#gradient;
4850
+ editor.setAttribute("color-space", this.#gamut);
4851
+ editor.toggleAttribute("disabled", this.#isDisabled());
4852
+ editor.pickerAnchor = this.#dialog;
4853
+ return;
4854
+ }
4820
4855
 
4821
4856
  const interpolationValue = gradientInterpolationSelectValue(this.#gradient);
4822
4857
  const interpolationSelect = container.querySelector(
@@ -4895,6 +4930,16 @@ class FigFillPicker extends HTMLElement {
4895
4930
  #updateGradientPreview() {
4896
4931
  if (!this.#dialog) return;
4897
4932
 
4933
+ const editor = this.#dialog.querySelector(
4934
+ '[data-tab="gradient"] > fig-gradient-editor',
4935
+ );
4936
+ if (editor) {
4937
+ editor.value = this.#gradient;
4938
+ editor.setAttribute("color-space", this.#gamut);
4939
+ this.#updateSwatch();
4940
+ return;
4941
+ }
4942
+
4898
4943
  const barInput = this.#dialog.querySelector(
4899
4944
  ".fig-fill-picker-gradient-bar-input",
4900
4945
  );
@@ -5093,13 +5138,7 @@ class FigFillPicker extends HTMLElement {
5093
5138
  }
5094
5139
 
5095
5140
  #getGradientCSS() {
5096
- const preferred = this.#buildGradientCSS(undefined, true);
5097
- if (this.#testGradientSupport(preferred)) return preferred;
5098
-
5099
- const oklabFallback = this.#buildGradientCSS("oklab", true);
5100
- if (this.#testGradientSupport(oklabFallback)) return oklabFallback;
5101
-
5102
- return this.#buildGradientCSS("oklab", false);
5141
+ return figGradientCSS(this.#gradient, { colorSpace: this.#gamut });
5103
5142
  }
5104
5143
 
5105
5144
  // ============ IMAGE TAB ============
@@ -0,0 +1,76 @@
1
+ /* Copyright (c) 2026 Rogie King. PolyForm Shield 1.0.0. See LICENSE. */
2
+ fig-gradient-editor {
3
+ display: block;
4
+ width: 100%;
5
+ min-width: 0;
6
+
7
+ .fig-fill-picker-gradient-preview {
8
+ aspect-ratio: auto;
9
+ width: calc(100% - var(--spacer-3) * 2);
10
+ margin: var(--spacer-3) var(--spacer-3) 0;
11
+ background: transparent;
12
+ overflow: visible;
13
+
14
+ &::after {
15
+ display: none;
16
+ }
17
+ }
18
+
19
+ fig-header.fig-fill-picker-gradient-header {
20
+ .fig-fill-picker-gradient-type {
21
+ display: flex;
22
+ flex: 0 1 auto;
23
+ min-width: 0;
24
+ width: auto;
25
+ }
26
+
27
+ .fig-fill-picker-gradient-actions {
28
+ flex: 0 0 auto;
29
+ }
30
+ }
31
+
32
+ .fig-fill-picker-gradient-stops {
33
+ .fig-fill-picker-gradient-stops-header > span {
34
+ flex: 1;
35
+ }
36
+ }
37
+
38
+ .fig-fill-picker-gradient-stops-list {
39
+ display: flex;
40
+ flex-direction: column;
41
+
42
+ fig-reorder {
43
+ display: contents;
44
+ }
45
+ }
46
+
47
+ .fig-fill-picker-gradient-stop-row {
48
+ &.dragging {
49
+ background-color: var(--figma-color-bg-selected);
50
+ }
51
+
52
+ .fig-fill-picker-gradient-stop-inputs {
53
+ width: 100%;
54
+ min-width: 0;
55
+ }
56
+
57
+ .fig-fill-picker-stop-position {
58
+ flex: 0 0 3rem;
59
+ min-width: 0;
60
+ width: 3rem;
61
+ }
62
+
63
+ .fig-fill-picker-stop-color {
64
+ flex: 1;
65
+ min-width: 0;
66
+
67
+ fig-input-text {
68
+ min-width: 0;
69
+ }
70
+ }
71
+
72
+ .fig-fill-picker-stop-remove {
73
+ flex-shrink: 0;
74
+ }
75
+ }
76
+ }