@rogieking/figui3 11.3.0 → 11.3.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/.cursor/skills/figui3/components.md +1 -0
- package/.cursor/skills/figui3/reference.md +1 -0
- package/CHANGELOG.md +25 -0
- package/README.md +3 -3
- package/components.css +34 -8
- package/dist/components.css +1 -1
- package/dist/fig.css +1 -1
- package/dist/fig.js +5 -5
- package/fig.js +119 -4
- package/package.json +1 -1
package/fig.js
CHANGED
|
@@ -6342,6 +6342,7 @@ figDefineElement("fig-options", FigOptions);
|
|
|
6342
6342
|
* @attr {number} min - The minimum value
|
|
6343
6343
|
* @attr {number} max - The maximum value
|
|
6344
6344
|
* @attr {number} step - The step increment
|
|
6345
|
+
* @attr {number} default - Explicit tick and native snap target
|
|
6345
6346
|
* @attr {boolean} text - Whether to show a text input alongside the slider (default true)
|
|
6346
6347
|
* @attr {string} placeholder - Placeholder for the number input when text is enabled
|
|
6347
6348
|
* @attr {string} units - The units to display after the value
|
|
@@ -6634,6 +6635,8 @@ class FigSlider extends HTMLElement {
|
|
|
6634
6635
|
this.datalist.append(option);
|
|
6635
6636
|
this.inputContainer.append(this.datalist);
|
|
6636
6637
|
this.input.setAttribute("list", this.datalist.getAttribute("id"));
|
|
6638
|
+
} else if (this.#hasExplicitValidDefault()) {
|
|
6639
|
+
this.#createDefaultDatalist();
|
|
6637
6640
|
}
|
|
6638
6641
|
this.#syncDefaultDatalist();
|
|
6639
6642
|
this.#syncValue();
|
|
@@ -6754,6 +6757,25 @@ class FigSlider extends HTMLElement {
|
|
|
6754
6757
|
const tolerance = Number.EPSILON * Math.max(1, Math.abs(steps)) * 16;
|
|
6755
6758
|
return Math.abs(steps - nearest) <= tolerance;
|
|
6756
6759
|
}
|
|
6760
|
+
#supportsGeneratedDefaultDatalist() {
|
|
6761
|
+
return ["range", "hue", "opacity"].includes(this.type);
|
|
6762
|
+
}
|
|
6763
|
+
#hasExplicitValidDefault() {
|
|
6764
|
+
if (
|
|
6765
|
+
!this.hasAttribute("default") ||
|
|
6766
|
+
!this.#supportsGeneratedDefaultDatalist()
|
|
6767
|
+
) {
|
|
6768
|
+
return false;
|
|
6769
|
+
}
|
|
6770
|
+
const { min, max } = this.#getBounds();
|
|
6771
|
+
const parsed = this.#toFiniteNumber(this.getAttribute("default"));
|
|
6772
|
+
return (
|
|
6773
|
+
parsed !== null &&
|
|
6774
|
+
parsed >= min &&
|
|
6775
|
+
parsed <= max &&
|
|
6776
|
+
this.#isStepAligned(parsed)
|
|
6777
|
+
);
|
|
6778
|
+
}
|
|
6757
6779
|
#resolveDefaultValue(rawDefault = this.getAttribute("default")) {
|
|
6758
6780
|
const { min, max } = this.#getBounds();
|
|
6759
6781
|
const parsed = this.#toFiniteNumber(rawDefault);
|
|
@@ -6959,8 +6981,24 @@ class FigSlider extends HTMLElement {
|
|
|
6959
6981
|
}
|
|
6960
6982
|
|
|
6961
6983
|
#syncDefaultDatalist() {
|
|
6984
|
+
const generatedDefault =
|
|
6985
|
+
this.datalist?.getAttribute("data-generated") === "slider-default";
|
|
6986
|
+
const shouldGenerateDefault = this.#hasExplicitValidDefault();
|
|
6987
|
+
if (generatedDefault && !shouldGenerateDefault) {
|
|
6988
|
+
this.datalist.remove();
|
|
6989
|
+
this.datalist = null;
|
|
6990
|
+
this.input?.removeAttribute("list");
|
|
6991
|
+
} else if (!this.datalist && shouldGenerateDefault) {
|
|
6992
|
+
this.#createDefaultDatalist();
|
|
6993
|
+
}
|
|
6962
6994
|
if (!this.datalist) return;
|
|
6963
6995
|
const defaultValue = String(this.default);
|
|
6996
|
+
if (generatedDefault) {
|
|
6997
|
+
const option =
|
|
6998
|
+
this.datalist.querySelector("option") ?? document.createElement("option");
|
|
6999
|
+
option.value = defaultValue;
|
|
7000
|
+
this.datalist.replaceChildren(option);
|
|
7001
|
+
}
|
|
6964
7002
|
const options = [...this.datalist.querySelectorAll("option")];
|
|
6965
7003
|
options.forEach((option) => option.removeAttribute("default"));
|
|
6966
7004
|
let defaultOption = options.find((option) => option.value === defaultValue);
|
|
@@ -6976,6 +7014,17 @@ class FigSlider extends HTMLElement {
|
|
|
6976
7014
|
defaultOption?.setAttribute("default", "true");
|
|
6977
7015
|
}
|
|
6978
7016
|
|
|
7017
|
+
#createDefaultDatalist() {
|
|
7018
|
+
this.datalist = document.createElement("datalist");
|
|
7019
|
+
this.datalist.setAttribute("data-generated", "slider-default");
|
|
7020
|
+
this.datalist.setAttribute("id", figUniqueId());
|
|
7021
|
+
const option = document.createElement("option");
|
|
7022
|
+
option.value = String(this.default);
|
|
7023
|
+
this.datalist.append(option);
|
|
7024
|
+
this.inputContainer.append(this.datalist);
|
|
7025
|
+
this.input.setAttribute("list", this.datalist.id);
|
|
7026
|
+
}
|
|
7027
|
+
|
|
6979
7028
|
#regenerateWhenIdle() {
|
|
6980
7029
|
if (this.#isInteracting) {
|
|
6981
7030
|
this.#pendingRegeneration = true;
|
|
@@ -7779,6 +7828,12 @@ class FigInputNumber extends HTMLElement {
|
|
|
7779
7828
|
#precision;
|
|
7780
7829
|
#isInteracting = false;
|
|
7781
7830
|
#stepperEl = null;
|
|
7831
|
+
#stepperPointerId = null;
|
|
7832
|
+
#stepperRepeatTimeout = 0;
|
|
7833
|
+
#stepperRepeatInterval = 0;
|
|
7834
|
+
#stepperDidChange = false;
|
|
7835
|
+
#boundStepperPointerEnd;
|
|
7836
|
+
#boundStepperWindowBlur;
|
|
7782
7837
|
#mutationObserver = null;
|
|
7783
7838
|
#syncRaf = 0;
|
|
7784
7839
|
#previousUserSelect = "";
|
|
@@ -7791,6 +7846,8 @@ class FigInputNumber extends HTMLElement {
|
|
|
7791
7846
|
"aria-required",
|
|
7792
7847
|
];
|
|
7793
7848
|
static #DEFAULT_UNITS_DISALLOW = "px";
|
|
7849
|
+
static #STEPPER_REPEAT_DELAY = 350;
|
|
7850
|
+
static #STEPPER_REPEAT_INTERVAL = 60;
|
|
7794
7851
|
|
|
7795
7852
|
#parseUnitsDisallowList(value) {
|
|
7796
7853
|
return (value || "")
|
|
@@ -7832,11 +7889,12 @@ class FigInputNumber extends HTMLElement {
|
|
|
7832
7889
|
const btn = e.target.closest("button");
|
|
7833
7890
|
if (!btn || this.disabled || btn.disabled) return;
|
|
7834
7891
|
const dir = btn.classList.contains("fig-stepper-up") ? 1 : -1;
|
|
7835
|
-
this.#
|
|
7892
|
+
this.#startStepperRepeat(e, dir);
|
|
7836
7893
|
this.input.focus();
|
|
7837
7894
|
});
|
|
7838
7895
|
this.append(this.#stepperEl);
|
|
7839
7896
|
} else if (!hasSteppers && this.#stepperEl) {
|
|
7897
|
+
this.#stopStepperRepeat();
|
|
7840
7898
|
this.#stepperEl.remove();
|
|
7841
7899
|
this.#stepperEl = null;
|
|
7842
7900
|
}
|
|
@@ -7867,13 +7925,60 @@ class FigInputNumber extends HTMLElement {
|
|
|
7867
7925
|
down.disabled = disabled || atMin;
|
|
7868
7926
|
}
|
|
7869
7927
|
|
|
7928
|
+
#startStepperRepeat(event, direction) {
|
|
7929
|
+
this.#stopStepperRepeat();
|
|
7930
|
+
this.#stepperPointerId = event.pointerId;
|
|
7931
|
+
this.#stepperDidChange = this.#stepValue(direction);
|
|
7932
|
+
window.addEventListener("pointerup", this.#boundStepperPointerEnd);
|
|
7933
|
+
window.addEventListener("pointercancel", this.#boundStepperPointerEnd);
|
|
7934
|
+
window.addEventListener("blur", this.#boundStepperWindowBlur);
|
|
7935
|
+
if (!this.#stepperDidChange) return;
|
|
7936
|
+
|
|
7937
|
+
this.#stepperRepeatTimeout = window.setTimeout(() => {
|
|
7938
|
+
this.#stepperRepeatTimeout = 0;
|
|
7939
|
+
this.#stepperRepeatInterval = window.setInterval(() => {
|
|
7940
|
+
const changed = this.#stepValue(direction);
|
|
7941
|
+
this.#stepperDidChange ||= changed;
|
|
7942
|
+
if (!changed) this.#clearStepperRepeatTimers();
|
|
7943
|
+
}, FigInputNumber.#STEPPER_REPEAT_INTERVAL);
|
|
7944
|
+
}, FigInputNumber.#STEPPER_REPEAT_DELAY);
|
|
7945
|
+
}
|
|
7946
|
+
|
|
7947
|
+
#clearStepperRepeatTimers() {
|
|
7948
|
+
if (this.#stepperRepeatTimeout) {
|
|
7949
|
+
clearTimeout(this.#stepperRepeatTimeout);
|
|
7950
|
+
this.#stepperRepeatTimeout = 0;
|
|
7951
|
+
}
|
|
7952
|
+
if (this.#stepperRepeatInterval) {
|
|
7953
|
+
clearInterval(this.#stepperRepeatInterval);
|
|
7954
|
+
this.#stepperRepeatInterval = 0;
|
|
7955
|
+
}
|
|
7956
|
+
}
|
|
7957
|
+
|
|
7958
|
+
#stopStepperRepeat(commit = true) {
|
|
7959
|
+
this.#clearStepperRepeatTimers();
|
|
7960
|
+
window.removeEventListener("pointerup", this.#boundStepperPointerEnd);
|
|
7961
|
+
window.removeEventListener("pointercancel", this.#boundStepperPointerEnd);
|
|
7962
|
+
window.removeEventListener("blur", this.#boundStepperWindowBlur);
|
|
7963
|
+
this.#stepperPointerId = null;
|
|
7964
|
+
if (commit && this.#stepperDidChange) {
|
|
7965
|
+
this.dispatchEvent(
|
|
7966
|
+
new CustomEvent("change", { detail: this.value, bubbles: true }),
|
|
7967
|
+
);
|
|
7968
|
+
}
|
|
7969
|
+
this.#stepperDidChange = false;
|
|
7970
|
+
}
|
|
7971
|
+
|
|
7870
7972
|
#stepValue(direction) {
|
|
7973
|
+
if (this.disabled) return false;
|
|
7871
7974
|
const step = this.step || 1;
|
|
7975
|
+
const previousValue = this.value;
|
|
7872
7976
|
let numericValue = this.#getNumericValue(this.input.value);
|
|
7873
7977
|
let value =
|
|
7874
7978
|
(numericValue !== "" ? Number(numericValue) / (this.transform || 1) : 0) +
|
|
7875
7979
|
step * direction;
|
|
7876
7980
|
value = this.#sanitizeInput(value, false);
|
|
7981
|
+
if (value === previousValue) return false;
|
|
7877
7982
|
this.value = value;
|
|
7878
7983
|
this.input.value = this.#formatWithUnit(this.value);
|
|
7879
7984
|
this.#syncStepperState();
|
|
@@ -7881,9 +7986,7 @@ class FigInputNumber extends HTMLElement {
|
|
|
7881
7986
|
this.dispatchEvent(
|
|
7882
7987
|
new CustomEvent("input", { detail: this.value, bubbles: true }),
|
|
7883
7988
|
);
|
|
7884
|
-
|
|
7885
|
-
new CustomEvent("change", { detail: this.value, bubbles: true }),
|
|
7886
|
-
);
|
|
7989
|
+
return true;
|
|
7887
7990
|
}
|
|
7888
7991
|
|
|
7889
7992
|
constructor() {
|
|
@@ -7910,6 +8013,16 @@ class FigInputNumber extends HTMLElement {
|
|
|
7910
8013
|
this.#boundKeyDown = (e) => {
|
|
7911
8014
|
this.#handleKeyDown(e);
|
|
7912
8015
|
};
|
|
8016
|
+
this.#boundStepperPointerEnd = (e) => {
|
|
8017
|
+
if (
|
|
8018
|
+
this.#stepperPointerId !== null &&
|
|
8019
|
+
e.pointerId !== this.#stepperPointerId
|
|
8020
|
+
) {
|
|
8021
|
+
return;
|
|
8022
|
+
}
|
|
8023
|
+
this.#stopStepperRepeat();
|
|
8024
|
+
};
|
|
8025
|
+
this.#boundStepperWindowBlur = () => this.#stopStepperRepeat();
|
|
7913
8026
|
this.#boundFocusControl = this.focus.bind(this);
|
|
7914
8027
|
this.#boundAdornmentClick = this.#handleAdornmentClick.bind(this);
|
|
7915
8028
|
}
|
|
@@ -8001,6 +8114,7 @@ class FigInputNumber extends HTMLElement {
|
|
|
8001
8114
|
window.removeEventListener("pointermove", this.#boundMouseMove);
|
|
8002
8115
|
window.removeEventListener("pointerup", this.#boundMouseUp);
|
|
8003
8116
|
window.removeEventListener("blur", this.#boundWindowBlur);
|
|
8117
|
+
this.#stopStepperRepeat(false);
|
|
8004
8118
|
this.#mutationObserver?.disconnect();
|
|
8005
8119
|
this.#mutationObserver = null;
|
|
8006
8120
|
if (this.#syncRaf) {
|
|
@@ -8375,6 +8489,7 @@ class FigInputNumber extends HTMLElement {
|
|
|
8375
8489
|
case "disabled":
|
|
8376
8490
|
this.disabled = this.input.disabled =
|
|
8377
8491
|
newValue !== null && newValue !== "false";
|
|
8492
|
+
if (this.disabled) this.#stopStepperRepeat();
|
|
8378
8493
|
this.#syncStepperState();
|
|
8379
8494
|
break;
|
|
8380
8495
|
case "units":
|
package/package.json
CHANGED