@rogieking/figui3 6.20.0 → 6.20.2

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-lab.css CHANGED
@@ -137,6 +137,27 @@ fig-content:has(> propskit-group[name]:last-child) {
137
137
  padding-bottom: 0;
138
138
  }
139
139
 
140
+ /* Large size: more left field padding; nudge trailing controls in from the right.
141
+ propskit-select applies left inset on label + trigger button instead (below). */
142
+ :is(
143
+ propskit-switch,
144
+ propskit-color,
145
+ propskit-text,
146
+ propskit-number,
147
+ propskit-slider
148
+ )[size="large"] {
149
+ fig-field:not([direction="vertical"]) {
150
+ padding-left: var(--spacer-2-5);
151
+ }
152
+ }
153
+
154
+ /* Flex-positioned numbers — margin works. Absolute numbers use right: calc(...) below. */
155
+ :is(propskit-color, propskit-number)[size="large"] {
156
+ fig-field fig-input-number {
157
+ margin-right: var(--spacer-1);
158
+ }
159
+ }
160
+
140
161
  propskit-switch {
141
162
  --propskit-switch-height: 2rem;
142
163
  --propskit-switch-vertical-padding: var(--spacer-1);
@@ -349,6 +370,27 @@ propskit-select {
349
370
 
350
371
  &[size="large"] {
351
372
  --propskit-select-vertical-padding: 0px;
373
+
374
+ fig-field:not([direction="vertical"]) {
375
+ padding-left: 0;
376
+
377
+ & > label {
378
+ inset: 0 auto 0 var(--spacer-2-5);
379
+ width: calc(50% - var(--spacer-2-5));
380
+ }
381
+
382
+ fig-select {
383
+ padding-right: var(--spacer-1);
384
+
385
+ &::after {
386
+ right: calc(0.25rem + var(--spacer-1));
387
+ }
388
+ }
389
+
390
+ fig-select::part(trigger) {
391
+ padding-left: var(--spacer-2-5);
392
+ }
393
+ }
352
394
  }
353
395
 
354
396
  &[disabled]:not([disabled="false"]) {
@@ -546,6 +588,10 @@ propskit-number {
546
588
 
547
589
  &[size="large"] {
548
590
  --propskit-number-vertical-padding: 0px;
591
+
592
+ fig-field:not([direction="vertical"]) > label {
593
+ inset: 0 auto 0 var(--spacer-2-5);
594
+ }
549
595
  }
550
596
 
551
597
  &[disabled]:not([disabled="false"]) {
@@ -567,6 +613,12 @@ propskit-number {
567
613
  height: 100%;
568
614
  border-radius: var(--radius-medium);
569
615
  background-color: var(--figma-color-bg-secondary);
616
+ outline: none;
617
+
618
+ &:focus-within {
619
+ outline: var(--figma-focus-outline);
620
+ outline-offset: var(--figma-focus-outline-offset);
621
+ }
570
622
 
571
623
  &::after {
572
624
  content: "";
@@ -602,8 +654,6 @@ propskit-number {
602
654
  }
603
655
 
604
656
  fig-input-number {
605
- --figma-focus-outline-offset: 1px;
606
-
607
657
  position: relative;
608
658
  align-self: center;
609
659
  flex: 0 0 auto;
@@ -617,10 +667,10 @@ propskit-number {
617
667
  border-radius: var(--radius-medium);
618
668
  background-color: transparent;
619
669
  box-shadow: none;
670
+ outline: none !important;
620
671
 
621
672
  &:has(input:focus) {
622
- outline: var(--figma-focus-outline) !important;
623
- outline-offset: var(--figma-focus-outline-offset) !important;
673
+ outline: none !important;
624
674
  }
625
675
 
626
676
  input {
@@ -650,6 +700,7 @@ propskit-slider {
650
700
  light-dark(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
651
701
  --propskit-slider-fig-slider-height: calc(var(--propskit-slider-height) - var(--propskit-slider-vertical-padding) * 2);
652
702
  --propskit-slider-fig-slider-thumb-height: calc(var(--propskit-slider-fig-slider-height) - var(--spacer-2-5));
703
+ --propskit-slider-number-right: 2px;
653
704
 
654
705
  display: block;
655
706
  position: relative;
@@ -663,9 +714,12 @@ propskit-slider {
663
714
  padding-left: var(--propskit-slider-horizontal-padding);
664
715
  padding-right: var(--propskit-slider-horizontal-padding);
665
716
 
666
- &[size="large"]{
717
+ &[size="large"] {
667
718
  --propskit-slider-vertical-padding: 0px;
668
- --propskit-slider-fig-slider-thumb-height: calc(var(--propskit-slider-fig-slider-height) - var(--spacer-3));
719
+ --propskit-slider-fig-slider-thumb-height: calc(
720
+ var(--propskit-slider-fig-slider-height) - var(--spacer-3)
721
+ );
722
+ --propskit-slider-number-right: calc(2px + var(--spacer-1));
669
723
  }
670
724
 
671
725
  label {
@@ -725,6 +779,11 @@ propskit-slider {
725
779
  padding: 0;
726
780
  background-color: transparent;
727
781
  --slider-height: var(--propskit-slider-fig-slider-height);
782
+
783
+ &:focus-within {
784
+ outline: var(--figma-focus-outline);
785
+ outline-offset: var(--figma-focus-outline-offset);
786
+ }
728
787
  --slider-field-height: calc(var(--propskit-slider-height) - var(--propskit-slider-vertical-padding) * 2);
729
788
  --slider-thumb-width: var(--spacer-1);
730
789
  --slider-thumb-color: light-dark(
@@ -741,25 +800,17 @@ propskit-slider {
741
800
  --slider-tick-height: var(--spacer-2);
742
801
  --slider-tick-radius: var(--radius-medium);
743
802
  --slider-stepper-padding: 0;
744
- --slider-thumb-inset-threshold: calc(
745
- var(--slider-thumb-width) + var(--spacer-2) * 2
746
- );
747
- --slider-thumb-inset-distance: var(--slider-percent);
748
- --slider-thumb-edge-offset: clamp(
749
- calc(-1 * var(--spacer-2)),
750
- calc(
751
- var(--slider-thumb-inset-threshold) -
752
- var(--slider-thumb-inset-distance) - var(--spacer-2)
753
- ),
754
- 0px
755
- );
756
- --slider-thumb-travel-offset: var(--slider-thumb-edge-offset);
757
- --propskit-slider-progress-offset: calc(
758
- min(var(--slider-complete), calc(1 - var(--slider-complete))) *
759
- var(--spacer-2)
760
- );
761
- --propskit-slider-progress-percent: calc(
762
- var(--slider-percent) + var(--propskit-slider-progress-offset)
803
+ /*
804
+ Progress = --slider-percent (0 100%).
805
+ Native range: thumbRight = complete * (100% - thumbWidth) + thumbWidth.
806
+ Wanted: thumbRight = progress - inset = complete * 100% - inset.
807
+ Compensate with a constant-gap margin on the thumb.
808
+ */
809
+ --propskit-slider-thumb-inset: var(--spacer-2);
810
+ --propskit-slider-progress-percent: var(--slider-percent);
811
+ --propskit-slider-thumb-travel-offset: calc(
812
+ (var(--slider-complete) - 1) * var(--slider-thumb-width) -
813
+ var(--propskit-slider-thumb-inset)
763
814
  );
764
815
  --slider-handle-shadow:
765
816
  inset 0 0 0 var(--slider-thumb-height) var(--slider-thumb-color),
@@ -773,18 +824,13 @@ propskit-slider {
773
824
  );
774
825
  --slider-tick-opacity: 0.5;
775
826
 
776
- &[type="delta"] {
777
- --slider-thumb-inset-distance: max(
778
- calc(var(--slider-percent) - var(--start-percent)),
779
- calc(var(--start-percent) - var(--slider-percent))
780
- );
781
- --slider-thumb-travel-offset: calc(
782
- (var(--slider-complete) - 1) * var(--spacer-2)
783
- );
827
+ &[type="delta"],
828
+ &[type="stepper"],
829
+ &[type="hue"] {
830
+ --propskit-slider-thumb-inset: 0;
784
831
  }
785
832
 
786
833
  &[type="stepper"] {
787
- --slider-thumb-travel-offset: 0px;
788
834
  datalist{
789
835
  opacity: 0;
790
836
  }
@@ -800,14 +846,10 @@ propskit-slider {
800
846
  margin-left: 0;
801
847
  }
802
848
 
803
- &:has(input[type="range"]:focus-within) {
804
- --slider-thumb-outline: var(--figma-focus-outline) !important;
805
- --slider-thumb-outline-offset: var(--figma-focus-outline-offset) !important;
806
- }
807
-
808
849
  .fig-slider-input-container {
809
850
  box-shadow: none !important;
810
851
  background-color: var(--figma-color-bg-secondary) !important;
852
+ overflow: hidden;
811
853
  &:hover,
812
854
  &:focus-within {
813
855
  &::after {
@@ -827,19 +869,20 @@ propskit-slider {
827
869
  }
828
870
  input[type="range"] {
829
871
  border-radius: 0 !important;
830
- width: calc(100% - var(--spacer-2)) !important;
831
- margin-left: var(--spacer-2);
872
+ width: 100% !important;
873
+ margin-left: 0;
832
874
  &::-webkit-slider-thumb {
833
- margin-left: var(--slider-thumb-travel-offset);
875
+ margin-left: var(--propskit-slider-thumb-travel-offset);
834
876
  }
835
877
  &::-moz-range-thumb {
836
- margin-left: var(--slider-thumb-travel-offset);
878
+ margin-left: var(--propskit-slider-thumb-travel-offset);
837
879
  }
838
880
  }
839
881
  }
840
882
 
841
883
  &:not([type="delta"]) .fig-slider-input-container::before {
842
884
  width: var(--propskit-slider-progress-percent) !important;
885
+ max-width: 100%;
843
886
  }
844
887
 
845
888
  &[type="delta"] .fig-slider-input-container::before {
@@ -934,23 +977,21 @@ propskit-slider {
934
977
  background-color: transparent;
935
978
  box-shadow: none !important;
936
979
  position: absolute;
937
- right: 2px;
938
- top:2px;
939
- bottom:2px;
980
+ right: var(--propskit-slider-number-right);
981
+ top: 2px;
982
+ bottom: 2px;
940
983
  width: fit-content;
941
984
  min-width: fit-content;
942
985
  max-width: max-content;
943
986
  flex: 0 0 auto;
944
987
  border-left: 0;
945
988
  border-radius: var(--radius-medium);
989
+ outline: none !important;
946
990
 
947
991
  &:hover,
948
992
  &:has(input:focus) {
949
993
  box-shadow: none !important;
950
- }
951
- &:has(input:focus) {
952
- outline: var(--figma-focus-outline) !important;
953
- outline-offset: var(--figma-focus-outline-offset) !important;
994
+ outline: none !important;
954
995
  }
955
996
  input {
956
997
  field-sizing: content;
package/fig.js CHANGED
@@ -834,6 +834,9 @@ customElements.define("fig-dropdown", FigDropdown);
834
834
  * @attr {string} theme - Optional theme passed to the underlying popup (e.g. "brand").
835
835
  * @attr {string} pointer - "false" to hide the beak.
836
836
  * @attr {boolean} show - When set, force-show the tooltip (ignores hide).
837
+ *
838
+ * Call {@link FigTooltip.dismissHoverTooltips} when opening menus/dialogs so
839
+ * hover tips do not stay visible over interactive overlays.
837
840
  */
838
841
  class FigTooltip extends HTMLElement {
839
842
  static #lastShownAt = 0;
@@ -1331,7 +1334,7 @@ class FigTooltip extends HTMLElement {
1331
1334
  FigTooltip.#documentExitListenersReady = true;
1332
1335
 
1333
1336
  const handlePointerLeftDocument = () => {
1334
- FigTooltip.#dismissHoverTooltipsOnDocumentExit();
1337
+ FigTooltip.dismissHoverTooltips();
1335
1338
  };
1336
1339
  const handleViewportChange = () => {
1337
1340
  FigTooltip.#dismissTooltipsOnViewportChange();
@@ -1372,13 +1375,20 @@ class FigTooltip extends HTMLElement {
1372
1375
  });
1373
1376
  }
1374
1377
 
1375
- static #dismissHoverTooltipsOnDocumentExit() {
1378
+ /**
1379
+ * Dismiss open/pending hover tooltips and programmatic {@link FigTooltip.show} tips.
1380
+ * Skips `show`-persisted and `action="click"` tooltips. Call when opening menus/dialogs.
1381
+ */
1382
+ static dismissHoverTooltips() {
1376
1383
  for (const node of document.querySelectorAll("fig-tooltip")) {
1377
1384
  if (!(node instanceof FigTooltip)) continue;
1378
1385
  if (node.action !== "hover") continue;
1379
1386
  if (node.#showPersisted) continue;
1380
1387
  if (node.isOpen || node.timeout) node.hidePopup();
1381
1388
  }
1389
+ for (const anchor of Array.from(FigTooltip.#programmaticAnchors)) {
1390
+ FigTooltip.hide(anchor);
1391
+ }
1382
1392
  }
1383
1393
 
1384
1394
  static #programmatic = new WeakMap();
@@ -1660,6 +1670,7 @@ class FigDialog extends HTMLDialogElement {
1660
1670
  // other FigUI overlays (same helper as fig-popup).
1661
1671
  this._assignStackingOrder();
1662
1672
  this.addEventListener("close", this._boundRestoreFocus, { once: true });
1673
+ FigTooltip.dismissHoverTooltips();
1663
1674
  return super.show();
1664
1675
  }
1665
1676
 
@@ -1668,6 +1679,7 @@ class FigDialog extends HTMLDialogElement {
1668
1679
  // Top layer owns stacking; clear any prior non-modal inline z-index.
1669
1680
  this._clearStackingOrder();
1670
1681
  this.addEventListener("close", this._boundRestoreFocus, { once: true });
1682
+ FigTooltip.dismissHoverTooltips();
1671
1683
  return super.showModal();
1672
1684
  }
1673
1685
 
@@ -2651,6 +2663,11 @@ class FigPopup extends HTMLDialogElement {
2651
2663
 
2652
2664
  const anchor = this.resolveAnchor();
2653
2665
  if (anchor?.classList) anchor.classList.add("has-popup-open");
2666
+
2667
+ // Tooltips lose to interactive overlays (menus, selects, popovers).
2668
+ if (this.getAttribute("variant") !== "tooltip") {
2669
+ FigTooltip.dismissHoverTooltips();
2670
+ }
2654
2671
  }
2655
2672
 
2656
2673
  hidePopup() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "6.20.0",
3
+ "version": "6.20.2",
4
4
  "description": "A lightweight web components library for building Figma plugin and widget UIs with native look and feel",
5
5
  "author": "Rogie King",
6
6
  "license": "MIT",