@rogieking/figui3 8.9.32 → 8.9.33
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/fig-lab/SKILL.md +10 -7
- package/.cursor/skills/fig-lab/reference.md +18 -4
- package/.cursor/skills/figui3/SKILL.md +3 -3
- package/README.md +35 -5
- package/dist/fig-lab.css +1 -1
- package/dist/fig-lab.js +2 -2
- package/fig-lab.css +147 -105
- package/fig-lab.js +713 -427
- package/package.json +1 -1
package/fig-lab.js
CHANGED
|
@@ -5546,43 +5546,25 @@ class PropskitSlider extends HTMLElement {
|
|
|
5546
5546
|
figLabDefineElement("propskit-slider", PropskitSlider);
|
|
5547
5547
|
|
|
5548
5548
|
/**
|
|
5549
|
-
*
|
|
5549
|
+
* Standalone interactive numeric wheel.
|
|
5550
5550
|
*
|
|
5551
|
-
* @attr {string} label - Field label. Omitted defaults to "Value"; authored values (including blank) are used as-is.
|
|
5552
|
-
* @attr {string} units - Optional unit forwarded to fig-input-number. Time aliases are normalized.
|
|
5553
5551
|
* @attr {number} value - Numeric value. Unbounded unless min/max are set.
|
|
5554
5552
|
* @attr {number} min - Inclusive lower bound. Omitted = unbounded below.
|
|
5555
5553
|
* @attr {number} max - Inclusive upper bound. Omitted = unbounded above.
|
|
5556
|
-
* @attr {
|
|
5557
|
-
* @attr {
|
|
5558
|
-
* @attr {
|
|
5559
|
-
* @
|
|
5560
|
-
* @
|
|
5561
|
-
* @attr {boolean|string} disabled - Disables wheel and number.
|
|
5562
|
-
* @attr {string} variant - Set to "minimal" for compact chrome.
|
|
5563
|
-
* @fires input - Composed event while dragging or typing.
|
|
5564
|
-
* @fires change - Composed event on commit.
|
|
5554
|
+
* @attr {number} step - Increment. Defaults to 1.
|
|
5555
|
+
* @attr {boolean|string} elastic - Enables resisted handle movement. Defaults to true.
|
|
5556
|
+
* @attr {boolean|string} disabled - Disables interaction and focus.
|
|
5557
|
+
* @fires input - Numeric composed event during interaction.
|
|
5558
|
+
* @fires change - Numeric composed event on commit.
|
|
5565
5559
|
*/
|
|
5566
|
-
class
|
|
5560
|
+
class FigInputWheel extends HTMLElement {
|
|
5567
5561
|
static #TICK_COUNT = 33;
|
|
5568
5562
|
static #HALF_FOV_DEG = 60;
|
|
5569
5563
|
static #PERSPECTIVE_K = 0.55;
|
|
5570
|
-
static #DRAGGING_BODY_CLASS = "fig-
|
|
5571
|
-
static #RESERVED_ATTRS = new Set([
|
|
5572
|
-
"label",
|
|
5573
|
-
"size",
|
|
5574
|
-
"disabled",
|
|
5575
|
-
"variant",
|
|
5576
|
-
"elastic",
|
|
5577
|
-
"default",
|
|
5578
|
-
"class",
|
|
5579
|
-
"style",
|
|
5580
|
-
"id",
|
|
5581
|
-
"oninput",
|
|
5582
|
-
"onchange",
|
|
5583
|
-
]);
|
|
5564
|
+
static #DRAGGING_BODY_CLASS = "fig-input-wheel-dragging";
|
|
5584
5565
|
|
|
5585
5566
|
#surface = null;
|
|
5567
|
+
#track = null;
|
|
5586
5568
|
#wheel = null;
|
|
5587
5569
|
#svg = null;
|
|
5588
5570
|
#tickPath = null;
|
|
@@ -5593,13 +5575,7 @@ class PropskitWheel extends HTMLElement {
|
|
|
5593
5575
|
#layoutFrame = 0;
|
|
5594
5576
|
#keyboardAnimationFrame = 0;
|
|
5595
5577
|
#keyboardSettleTimer = 0;
|
|
5596
|
-
#label = null;
|
|
5597
|
-
#input = null;
|
|
5598
|
-
#hasCustomLabel = false;
|
|
5599
|
-
#observer = null;
|
|
5600
5578
|
#resizeObserver = null;
|
|
5601
|
-
#managedInputAttrs = new Set();
|
|
5602
|
-
#initialValue = null;
|
|
5603
5579
|
#isDragging = false;
|
|
5604
5580
|
#dragPointerId = null;
|
|
5605
5581
|
#dragStartX = 0;
|
|
@@ -5609,168 +5585,113 @@ class PropskitWheel extends HTMLElement {
|
|
|
5609
5585
|
#elasticMaxPx = 0;
|
|
5610
5586
|
#elasticRangeRect = null;
|
|
5611
5587
|
#elasticHostWidth = 0;
|
|
5612
|
-
#numberPointerId = null;
|
|
5613
|
-
#numberPointerStartX = 0;
|
|
5614
|
-
#numberPointerStartY = 0;
|
|
5615
|
-
#numberPointerStartValue = 0;
|
|
5616
|
-
#isNumberScrubbing = false;
|
|
5617
|
-
#suppressNumberClick = false;
|
|
5618
|
-
#numberClickResetTimer = 0;
|
|
5619
|
-
#boundHandleInput = null;
|
|
5620
|
-
#boundHandleChange = null;
|
|
5621
5588
|
#boundPointerDown = this.#handlePointerDown.bind(this);
|
|
5622
5589
|
#boundPointerMove = this.#handlePointerMove.bind(this);
|
|
5623
5590
|
#boundPointerUp = this.#handlePointerUp.bind(this);
|
|
5624
|
-
#boundNumberPointerDown = this.#handleNumberPointerDown.bind(this);
|
|
5625
|
-
#boundNumberPointerMove = this.#handleNumberPointerMove.bind(this);
|
|
5626
|
-
#boundNumberPointerEnd = this.#handleNumberPointerEnd.bind(this);
|
|
5627
5591
|
#boundWheel = this.#handleWheel.bind(this);
|
|
5628
5592
|
#boundKeyDown = this.#handleKeyDown.bind(this);
|
|
5629
|
-
#boundClick = this.#handleClick.bind(this);
|
|
5630
5593
|
|
|
5631
5594
|
static get observedAttributes() {
|
|
5632
|
-
return [
|
|
5595
|
+
return [
|
|
5596
|
+
"value",
|
|
5597
|
+
"disabled",
|
|
5598
|
+
"step",
|
|
5599
|
+
"min",
|
|
5600
|
+
"max",
|
|
5601
|
+
"elastic",
|
|
5602
|
+
];
|
|
5633
5603
|
}
|
|
5634
5604
|
|
|
5635
5605
|
connectedCallback() {
|
|
5636
5606
|
if (!this.#surface) this.#initialize();
|
|
5637
|
-
this.#syncLabel();
|
|
5638
5607
|
this.#syncDisabled();
|
|
5639
|
-
this.#syncInputAttributes();
|
|
5640
5608
|
this.#syncValueFromHost();
|
|
5641
5609
|
this.#bindEvents();
|
|
5642
|
-
figLabConnectPropskitResetMenu(this);
|
|
5643
|
-
this.#observer?.disconnect();
|
|
5644
|
-
this.#observer = new MutationObserver((mutations) => {
|
|
5645
|
-
let syncInput = false;
|
|
5646
|
-
for (const mutation of mutations) {
|
|
5647
|
-
if (mutation.type !== "attributes") continue;
|
|
5648
|
-
const name = mutation.attributeName;
|
|
5649
|
-
if (
|
|
5650
|
-
!PropskitWheel.#RESERVED_ATTRS.has(name) &&
|
|
5651
|
-
!PropskitWheel.observedAttributes.includes(name) &&
|
|
5652
|
-
!name?.startsWith("data-")
|
|
5653
|
-
) {
|
|
5654
|
-
syncInput = true;
|
|
5655
|
-
}
|
|
5656
|
-
}
|
|
5657
|
-
if (syncInput) this.#syncInputAttributes();
|
|
5658
|
-
});
|
|
5659
|
-
this.#observer.observe(this, { attributes: true });
|
|
5660
5610
|
this.#resizeObserver?.disconnect();
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5611
|
+
if (globalThis.ResizeObserver) {
|
|
5612
|
+
this.#resizeObserver = new ResizeObserver((entries) => {
|
|
5613
|
+
const rect = entries.at(-1)?.contentRect;
|
|
5614
|
+
if (rect) this.#setWheelSize(rect.width, rect.height);
|
|
5615
|
+
});
|
|
5616
|
+
this.#resizeObserver.observe(this);
|
|
5617
|
+
}
|
|
5666
5618
|
this.#queueWheelLayout();
|
|
5667
5619
|
}
|
|
5668
5620
|
|
|
5669
5621
|
disconnectedCallback() {
|
|
5670
|
-
this.#observer?.disconnect();
|
|
5671
5622
|
this.#resizeObserver?.disconnect();
|
|
5672
5623
|
if (this.#layoutFrame) cancelAnimationFrame(this.#layoutFrame);
|
|
5673
5624
|
this.#layoutFrame = 0;
|
|
5674
5625
|
this.#stopKeyboardAnimation();
|
|
5675
5626
|
this.#unbindEvents();
|
|
5676
5627
|
this.#stopDrag();
|
|
5677
|
-
figLabDisconnectPropskitResetMenu(this);
|
|
5678
5628
|
}
|
|
5679
5629
|
|
|
5680
5630
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
5681
5631
|
if (oldValue === newValue || !this.#surface) return;
|
|
5682
|
-
if (name === "label") this.#syncLabel();
|
|
5683
5632
|
if (name === "disabled") this.#syncDisabled();
|
|
5684
5633
|
if (name === "value" && !this.#isDragging) {
|
|
5685
5634
|
this.#syncValueFromHost();
|
|
5686
5635
|
}
|
|
5687
|
-
if (name === "
|
|
5688
|
-
this.#
|
|
5636
|
+
if (name === "step") {
|
|
5637
|
+
this.#syncWheelAria();
|
|
5689
5638
|
this.#queueWheelLayout();
|
|
5690
5639
|
}
|
|
5691
5640
|
if (name === "min" || name === "max") {
|
|
5692
|
-
this.#syncInputAttributes();
|
|
5693
5641
|
this.#commitValue(this.#numericValue());
|
|
5694
5642
|
}
|
|
5695
5643
|
}
|
|
5696
5644
|
|
|
5697
5645
|
#initialize() {
|
|
5698
|
-
this.#
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
)
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
});
|
|
5710
|
-
const wheel = figLabCreateElement("div", {
|
|
5711
|
-
className: "propskit-wheel-wheel",
|
|
5712
|
-
tabindex: "0",
|
|
5713
|
-
role: "spinbutton",
|
|
5714
|
-
});
|
|
5646
|
+
this.#surface = this;
|
|
5647
|
+
this.#track = this;
|
|
5648
|
+
this.#wheel = this;
|
|
5649
|
+
this.setAttribute("role", "spinbutton");
|
|
5650
|
+
if (
|
|
5651
|
+
!this.hasAttribute("aria-label") &&
|
|
5652
|
+
!this.hasAttribute("aria-labelledby")
|
|
5653
|
+
) {
|
|
5654
|
+
this.setAttribute("aria-label", "Value");
|
|
5655
|
+
}
|
|
5656
|
+
this.setAttribute("tabindex", "0");
|
|
5715
5657
|
const svg = figLabCreateSvgElement("svg", {
|
|
5716
|
-
className: "
|
|
5658
|
+
className: "fig-input-wheel-svg",
|
|
5717
5659
|
"aria-hidden": "true",
|
|
5718
5660
|
});
|
|
5719
|
-
const label = customLabel || document.createElement("label");
|
|
5720
|
-
const input = document.createElement("fig-input-number");
|
|
5721
|
-
const labelId = figLabUniqueId("propskit-wheel-label");
|
|
5722
|
-
label.id = labelId;
|
|
5723
|
-
wheel.setAttribute("aria-labelledby", labelId);
|
|
5724
|
-
|
|
5725
5661
|
const handle = figLabCreateElement("div", {
|
|
5726
|
-
className: "
|
|
5662
|
+
className: "fig-input-wheel-handle",
|
|
5727
5663
|
});
|
|
5728
|
-
wheel.append(svg);
|
|
5729
|
-
surface.append(wheel, handle, label, input);
|
|
5730
|
-
this.#surface = surface;
|
|
5731
|
-
this.#wheel = wheel;
|
|
5732
5664
|
this.#svg = svg;
|
|
5733
|
-
this
|
|
5734
|
-
this.#input = input;
|
|
5735
|
-
this.#hasCustomLabel = Boolean(customLabel);
|
|
5736
|
-
this.replaceChildren(surface);
|
|
5665
|
+
this.replaceChildren(svg, handle);
|
|
5737
5666
|
|
|
5738
5667
|
const metricProbe = document.createElement("div");
|
|
5739
5668
|
metricProbe.setAttribute("aria-hidden", "true");
|
|
5740
5669
|
metricProbe.style.cssText =
|
|
5741
5670
|
"position:absolute;visibility:hidden;pointer-events:none;left:0;top:0";
|
|
5742
5671
|
const maxEl = document.createElement("div");
|
|
5743
|
-
maxEl.style.height = "var(--
|
|
5672
|
+
maxEl.style.height = "var(--fig-input-wheel-tick-height)";
|
|
5744
5673
|
const minEl = document.createElement("div");
|
|
5745
|
-
minEl.style.height = "var(--
|
|
5674
|
+
minEl.style.height = "var(--fig-input-wheel-tick-height-min)";
|
|
5746
5675
|
const maxWidthEl = document.createElement("div");
|
|
5747
|
-
maxWidthEl.style.width = "var(--
|
|
5676
|
+
maxWidthEl.style.width = "var(--fig-input-wheel-tick-width)";
|
|
5748
5677
|
const minWidthEl = document.createElement("div");
|
|
5749
|
-
minWidthEl.style.width = "var(--
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
metricProbe.append(maxEl, minEl, maxWidthEl, minWidthEl, insetEl);
|
|
5753
|
-
surface.append(metricProbe);
|
|
5678
|
+
minWidthEl.style.width = "var(--fig-input-wheel-tick-width-min)";
|
|
5679
|
+
metricProbe.append(maxEl, minEl, maxWidthEl, minWidthEl);
|
|
5680
|
+
this.append(metricProbe);
|
|
5754
5681
|
this.#tickMetricProbe = {
|
|
5755
5682
|
maxEl,
|
|
5756
5683
|
minEl,
|
|
5757
5684
|
maxWidthEl,
|
|
5758
5685
|
minWidthEl,
|
|
5759
|
-
insetEl,
|
|
5760
5686
|
};
|
|
5761
5687
|
|
|
5762
|
-
for (const node of initialChildren) {
|
|
5763
|
-
if (node === customLabel) continue;
|
|
5764
|
-
input.appendChild(node);
|
|
5765
|
-
}
|
|
5766
|
-
|
|
5767
5688
|
this.#ensureTickPath();
|
|
5768
5689
|
}
|
|
5769
5690
|
|
|
5770
5691
|
#ensureTickPath() {
|
|
5771
5692
|
if (!this.#svg || this.#tickPath) return;
|
|
5772
5693
|
this.#tickPath = figLabCreateSvgElement("path", {
|
|
5773
|
-
className: "
|
|
5694
|
+
className: "fig-input-wheel-tick",
|
|
5774
5695
|
});
|
|
5775
5696
|
this.#svg.append(this.#tickPath);
|
|
5776
5697
|
}
|
|
@@ -5784,60 +5705,20 @@ class PropskitWheel extends HTMLElement {
|
|
|
5784
5705
|
this.#tickMetricProbe?.maxWidthEl.getBoundingClientRect().width || 2,
|
|
5785
5706
|
minW:
|
|
5786
5707
|
this.#tickMetricProbe?.minWidthEl.getBoundingClientRect().width || 1,
|
|
5787
|
-
inset: this.#tickMetricProbe?.insetEl.getBoundingClientRect().width || 0,
|
|
5788
5708
|
};
|
|
5789
5709
|
return this.#tickMetrics;
|
|
5790
5710
|
}
|
|
5791
5711
|
|
|
5792
|
-
#units() {
|
|
5793
|
-
const raw = (this.getAttribute("units") || "").trim();
|
|
5794
|
-
const normalized = raw.toLowerCase();
|
|
5795
|
-
if (
|
|
5796
|
-
normalized === "ms" ||
|
|
5797
|
-
normalized === "millisecond" ||
|
|
5798
|
-
normalized === "milliseconds"
|
|
5799
|
-
) {
|
|
5800
|
-
return "ms";
|
|
5801
|
-
}
|
|
5802
|
-
if (
|
|
5803
|
-
normalized === "s" ||
|
|
5804
|
-
normalized === "second" ||
|
|
5805
|
-
normalized === "seconds"
|
|
5806
|
-
) {
|
|
5807
|
-
return "s";
|
|
5808
|
-
}
|
|
5809
|
-
return raw;
|
|
5810
|
-
}
|
|
5811
|
-
|
|
5812
|
-
#defaultStep() {
|
|
5813
|
-
const units = this.#units();
|
|
5814
|
-
if (units === "s") return 0.1;
|
|
5815
|
-
if (units === "ms") return 100;
|
|
5816
|
-
return 1;
|
|
5817
|
-
}
|
|
5818
|
-
|
|
5819
|
-
#defaultPrecision() {
|
|
5820
|
-
return this.#units() === "s" ? 2 : 0;
|
|
5821
|
-
}
|
|
5822
|
-
|
|
5823
5712
|
#step() {
|
|
5824
5713
|
if (this.hasAttribute("step")) {
|
|
5825
5714
|
const parsed = Number(this.getAttribute("step"));
|
|
5826
5715
|
if (parsed > 0) return parsed;
|
|
5827
5716
|
}
|
|
5828
|
-
return
|
|
5829
|
-
}
|
|
5830
|
-
|
|
5831
|
-
#precision() {
|
|
5832
|
-
if (this.hasAttribute("precision")) {
|
|
5833
|
-
const parsed = Number(this.getAttribute("precision"));
|
|
5834
|
-
if (Number.isInteger(parsed) && parsed >= 0) return parsed;
|
|
5835
|
-
}
|
|
5836
|
-
return this.#defaultPrecision();
|
|
5717
|
+
return 1;
|
|
5837
5718
|
}
|
|
5838
5719
|
|
|
5839
5720
|
#numericValue() {
|
|
5840
|
-
const parsed = Number(this.getAttribute("value") ??
|
|
5721
|
+
const parsed = Number(this.getAttribute("value") ?? 0);
|
|
5841
5722
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
5842
5723
|
}
|
|
5843
5724
|
|
|
@@ -5894,9 +5775,6 @@ class PropskitWheel extends HTMLElement {
|
|
|
5894
5775
|
if (this.getAttribute("value") !== asString) {
|
|
5895
5776
|
this.setAttribute("value", asString);
|
|
5896
5777
|
}
|
|
5897
|
-
if (this.#input?.getAttribute("value") !== asString) {
|
|
5898
|
-
this.#input?.setAttribute("value", asString);
|
|
5899
|
-
}
|
|
5900
5778
|
this.#syncWheelAria(next);
|
|
5901
5779
|
this.#queueWheelLayout();
|
|
5902
5780
|
if (emit) {
|
|
@@ -5914,53 +5792,35 @@ class PropskitWheel extends HTMLElement {
|
|
|
5914
5792
|
#syncValueFromHost() {
|
|
5915
5793
|
const value = this.#numericValue();
|
|
5916
5794
|
const clamped = this.#clamp(value);
|
|
5917
|
-
if (
|
|
5795
|
+
if (
|
|
5796
|
+
clamped !== value ||
|
|
5797
|
+
this.getAttribute("value") !== String(clamped)
|
|
5798
|
+
) {
|
|
5918
5799
|
this.#commitValue(clamped);
|
|
5919
5800
|
return;
|
|
5920
5801
|
}
|
|
5921
|
-
const asString = String(value);
|
|
5922
|
-
if (this.#input?.getAttribute("value") !== asString) {
|
|
5923
|
-
this.#input?.setAttribute("value", asString);
|
|
5924
|
-
}
|
|
5925
5802
|
this.#syncWheelAria(value);
|
|
5926
5803
|
this.#queueWheelLayout();
|
|
5927
5804
|
}
|
|
5928
5805
|
|
|
5929
5806
|
#syncWheelAria(value = this.#numericValue()) {
|
|
5930
5807
|
if (!this.#wheel) return;
|
|
5931
|
-
const units = this.#units();
|
|
5932
5808
|
const min = this.#boundMin();
|
|
5933
5809
|
const max = this.#boundMax();
|
|
5934
5810
|
this.#wheel.setAttribute("aria-valuenow", String(value));
|
|
5935
|
-
this.#wheel.setAttribute(
|
|
5936
|
-
"aria-valuetext",
|
|
5937
|
-
units
|
|
5938
|
-
? `${value} ${
|
|
5939
|
-
units === "s" ? "seconds" : units === "ms" ? "milliseconds" : units
|
|
5940
|
-
}`
|
|
5941
|
-
: String(value),
|
|
5942
|
-
);
|
|
5811
|
+
this.#wheel.setAttribute("aria-valuetext", String(value));
|
|
5943
5812
|
if (min === null) this.#wheel.removeAttribute("aria-valuemin");
|
|
5944
5813
|
else this.#wheel.setAttribute("aria-valuemin", String(min));
|
|
5945
5814
|
if (max === null) this.#wheel.removeAttribute("aria-valuemax");
|
|
5946
5815
|
else this.#wheel.setAttribute("aria-valuemax", String(max));
|
|
5947
5816
|
}
|
|
5948
5817
|
|
|
5949
|
-
#syncLabel() {
|
|
5950
|
-
if (!this.#label) return;
|
|
5951
|
-
if (this.#hasCustomLabel) return;
|
|
5952
|
-
if (!this.hasAttribute("label")) {
|
|
5953
|
-
this.#label.textContent = "Value";
|
|
5954
|
-
return;
|
|
5955
|
-
}
|
|
5956
|
-
this.#label.textContent = this.getAttribute("label") ?? "";
|
|
5957
|
-
}
|
|
5958
|
-
|
|
5959
5818
|
#syncDisabled() {
|
|
5960
5819
|
const disabled = figLabBooleanAttribute(this, "disabled");
|
|
5961
|
-
this.#input?.toggleAttribute("disabled", disabled);
|
|
5962
5820
|
if (!this.#wheel) return;
|
|
5963
5821
|
if (disabled) {
|
|
5822
|
+
if (this.#isDragging) this.#stopDrag();
|
|
5823
|
+
this.#stopKeyboardAnimation();
|
|
5964
5824
|
this.setAttribute("aria-disabled", "true");
|
|
5965
5825
|
this.#wheel.setAttribute("tabindex", "-1");
|
|
5966
5826
|
this.#wheel.setAttribute("aria-disabled", "true");
|
|
@@ -5971,39 +5831,6 @@ class PropskitWheel extends HTMLElement {
|
|
|
5971
5831
|
}
|
|
5972
5832
|
}
|
|
5973
5833
|
|
|
5974
|
-
#getForwardedInputAttrNames() {
|
|
5975
|
-
return this.getAttributeNames().filter(
|
|
5976
|
-
(name) =>
|
|
5977
|
-
!PropskitWheel.#RESERVED_ATTRS.has(name) && !name.startsWith("data-"),
|
|
5978
|
-
);
|
|
5979
|
-
}
|
|
5980
|
-
|
|
5981
|
-
#syncInputAttributes() {
|
|
5982
|
-
if (!this.#input) return;
|
|
5983
|
-
const inputAttrs = this.#getForwardedInputAttrNames();
|
|
5984
|
-
const nextManaged = new Set(inputAttrs);
|
|
5985
|
-
for (const attrName of this.#managedInputAttrs) {
|
|
5986
|
-
if (!nextManaged.has(attrName)) this.#input.removeAttribute(attrName);
|
|
5987
|
-
}
|
|
5988
|
-
for (const attrName of inputAttrs) {
|
|
5989
|
-
this.#input.setAttribute(attrName, this.getAttribute(attrName) ?? "");
|
|
5990
|
-
}
|
|
5991
|
-
const units = this.#units();
|
|
5992
|
-
if (units) this.#input.setAttribute("units", units);
|
|
5993
|
-
else this.#input.removeAttribute("units");
|
|
5994
|
-
nextManaged.add("units");
|
|
5995
|
-
if (!this.hasAttribute("step")) {
|
|
5996
|
-
this.#input.setAttribute("step", String(this.#defaultStep()));
|
|
5997
|
-
nextManaged.add("step");
|
|
5998
|
-
}
|
|
5999
|
-
if (!this.hasAttribute("precision")) {
|
|
6000
|
-
this.#input.setAttribute("precision", String(this.#defaultPrecision()));
|
|
6001
|
-
nextManaged.add("precision");
|
|
6002
|
-
}
|
|
6003
|
-
this.#managedInputAttrs = nextManaged;
|
|
6004
|
-
this.#syncWheelAria();
|
|
6005
|
-
}
|
|
6006
|
-
|
|
6007
5834
|
#setWheelSize(width, height) {
|
|
6008
5835
|
if (!this.#svg || width < 1 || height < 1) return;
|
|
6009
5836
|
if (width === this.#wheelWidth && height === this.#wheelHeight) return;
|
|
@@ -6039,22 +5866,21 @@ class PropskitWheel extends HTMLElement {
|
|
|
6039
5866
|
if (width < 1 || height < 1) return;
|
|
6040
5867
|
|
|
6041
5868
|
const value = this.#visualValue ?? this.#numericValue();
|
|
6042
|
-
const tickStep = 360 /
|
|
5869
|
+
const tickStep = 360 / FigInputWheel.#TICK_COUNT;
|
|
6043
5870
|
const step = this.#step();
|
|
6044
5871
|
const base = this.#boundMin() ?? 0;
|
|
6045
5872
|
const offsetDeg = ((value - base) / step) * tickStep;
|
|
6046
|
-
const k =
|
|
5873
|
+
const k = FigInputWheel.#PERSPECTIVE_K;
|
|
6047
5874
|
const cx = width / 2;
|
|
6048
5875
|
const cy = height / 2;
|
|
6049
5876
|
|
|
6050
|
-
const { maxH, minH, maxW, minW
|
|
6051
|
-
const
|
|
6052
|
-
const
|
|
6053
|
-
const
|
|
6054
|
-
const visibleHalf = Math.max(drawableWidth / 2, 1);
|
|
5877
|
+
const { maxH, minH, maxW, minW } = this.#readTickMetrics();
|
|
5878
|
+
const fov = FigInputWheel.#HALF_FOV_DEG;
|
|
5879
|
+
const visibleHalf = Math.max(width / 2, 1);
|
|
5880
|
+
const radius = visibleHalf * 0.84;
|
|
6055
5881
|
const commands = [];
|
|
6056
5882
|
|
|
6057
|
-
for (let index = 0; index <
|
|
5883
|
+
for (let index = 0; index < FigInputWheel.#TICK_COUNT; index += 1) {
|
|
6058
5884
|
let theta = offsetDeg + index * tickStep;
|
|
6059
5885
|
theta = ((((theta + 180) % 360) + 360) % 360) - 180;
|
|
6060
5886
|
if (theta < -fov || theta >= fov) continue;
|
|
@@ -6084,106 +5910,93 @@ class PropskitWheel extends HTMLElement {
|
|
|
6084
5910
|
}
|
|
6085
5911
|
|
|
6086
5912
|
#bindEvents() {
|
|
6087
|
-
this.#boundHandleInput ??= this.#forwardInputEvent.bind(this, "input");
|
|
6088
|
-
this.#boundHandleChange ??= this.#forwardInputEvent.bind(this, "change");
|
|
6089
|
-
this.#input?.addEventListener("input", this.#boundHandleInput);
|
|
6090
|
-
this.#input?.addEventListener("change", this.#boundHandleChange);
|
|
6091
5913
|
this.#surface?.addEventListener("pointerdown", this.#boundPointerDown);
|
|
6092
|
-
this.addEventListener("pointerdown", this.#boundNumberPointerDown, {
|
|
6093
|
-
capture: true,
|
|
6094
|
-
});
|
|
6095
5914
|
this.#wheel?.addEventListener("wheel", this.#boundWheel, { passive: false });
|
|
6096
5915
|
this.#wheel?.addEventListener("keydown", this.#boundKeyDown);
|
|
6097
|
-
this.addEventListener("click", this.#boundClick, true);
|
|
6098
5916
|
}
|
|
6099
5917
|
|
|
6100
5918
|
#unbindEvents() {
|
|
6101
|
-
this.#input?.removeEventListener("input", this.#boundHandleInput);
|
|
6102
|
-
this.#input?.removeEventListener("change", this.#boundHandleChange);
|
|
6103
5919
|
this.#surface?.removeEventListener("pointerdown", this.#boundPointerDown);
|
|
6104
|
-
this.removeEventListener("pointerdown", this.#boundNumberPointerDown, {
|
|
6105
|
-
capture: true,
|
|
6106
|
-
});
|
|
6107
5920
|
this.#wheel?.removeEventListener("wheel", this.#boundWheel);
|
|
6108
5921
|
this.#wheel?.removeEventListener("keydown", this.#boundKeyDown);
|
|
6109
|
-
this.removeEventListener("click", this.#boundClick, true);
|
|
6110
|
-
this.#stopNumberTracking();
|
|
6111
|
-
clearTimeout(this.#numberClickResetTimer);
|
|
6112
|
-
this.#numberClickResetTimer = 0;
|
|
6113
5922
|
window.removeEventListener("pointermove", this.#boundPointerMove);
|
|
6114
5923
|
window.removeEventListener("pointerup", this.#boundPointerUp);
|
|
6115
5924
|
window.removeEventListener("pointercancel", this.#boundPointerUp);
|
|
6116
5925
|
}
|
|
6117
5926
|
|
|
6118
|
-
#forwardInputEvent(type, event) {
|
|
6119
|
-
event.stopImmediatePropagation();
|
|
6120
|
-
if (figLabBooleanAttribute(this, "disabled")) return;
|
|
6121
|
-
const raw =
|
|
6122
|
-
event instanceof CustomEvent && event.detail !== undefined
|
|
6123
|
-
? event.detail
|
|
6124
|
-
: this.#input?.value;
|
|
6125
|
-
const parsed = Number(raw);
|
|
6126
|
-
const next = Number.isFinite(parsed) ? parsed : this.#numericValue();
|
|
6127
|
-
this.#commitValue(next, { emit: type });
|
|
6128
|
-
}
|
|
6129
|
-
|
|
6130
|
-
#handleClick(event) {
|
|
6131
|
-
if (figLabBooleanAttribute(this, "disabled")) return;
|
|
6132
|
-
if (
|
|
6133
|
-
event.target instanceof Element &&
|
|
6134
|
-
event.target.closest("fig-input-number, fig-menu")
|
|
6135
|
-
) {
|
|
6136
|
-
if (
|
|
6137
|
-
this.#suppressNumberClick &&
|
|
6138
|
-
event.target.closest("fig-input-number")
|
|
6139
|
-
) {
|
|
6140
|
-
event.preventDefault();
|
|
6141
|
-
event.stopImmediatePropagation();
|
|
6142
|
-
this.#suppressNumberClick = false;
|
|
6143
|
-
}
|
|
6144
|
-
return;
|
|
6145
|
-
}
|
|
6146
|
-
this.#wheel?.focus();
|
|
6147
|
-
}
|
|
6148
|
-
|
|
6149
5927
|
#handlePointerDown(event) {
|
|
6150
5928
|
if (figLabBooleanAttribute(this, "disabled")) return;
|
|
6151
5929
|
if (event.button !== 0) return;
|
|
6152
|
-
if (
|
|
6153
|
-
event.target instanceof Element &&
|
|
6154
|
-
event.target.closest("fig-input-number, fig-menu")
|
|
6155
|
-
) {
|
|
6156
|
-
return;
|
|
6157
|
-
}
|
|
6158
5930
|
event.preventDefault();
|
|
6159
|
-
this
|
|
6160
|
-
this.#isDragging = true;
|
|
6161
|
-
this.#dragPointerId = event.pointerId;
|
|
6162
|
-
this.#dragStartX = event.clientX;
|
|
6163
|
-
this.#dragStartValue = this.#numericValue();
|
|
6164
|
-
this.#startElasticPull();
|
|
6165
|
-
this.setAttribute("data-active", "");
|
|
6166
|
-
document.body.classList.add(PropskitWheel.#DRAGGING_BODY_CLASS);
|
|
6167
|
-
this.#wheel?.focus();
|
|
5931
|
+
if (!this.beginScrub(event)) return;
|
|
6168
5932
|
this.#surface?.setPointerCapture?.(event.pointerId);
|
|
6169
5933
|
window.addEventListener("pointermove", this.#boundPointerMove);
|
|
6170
5934
|
window.addEventListener("pointerup", this.#boundPointerUp);
|
|
6171
5935
|
window.addEventListener("pointercancel", this.#boundPointerUp);
|
|
6172
5936
|
}
|
|
6173
5937
|
|
|
5938
|
+
beginScrub(start = {}) {
|
|
5939
|
+
if (figLabBooleanAttribute(this, "disabled")) return false;
|
|
5940
|
+
const clientX =
|
|
5941
|
+
typeof start === "number" ? start : Number(start?.clientX ?? start?.x);
|
|
5942
|
+
if (!Number.isFinite(clientX)) return false;
|
|
5943
|
+
this.#stopKeyboardAnimation();
|
|
5944
|
+
this.#isDragging = true;
|
|
5945
|
+
this.#dragPointerId =
|
|
5946
|
+
start && typeof start === "object" && start.pointerId !== undefined
|
|
5947
|
+
? start.pointerId
|
|
5948
|
+
: null;
|
|
5949
|
+
this.#dragStartX = clientX;
|
|
5950
|
+
const requestedStart =
|
|
5951
|
+
start && typeof start === "object"
|
|
5952
|
+
? Number(start.startValue)
|
|
5953
|
+
: Number.NaN;
|
|
5954
|
+
this.#dragStartValue = Number.isFinite(requestedStart)
|
|
5955
|
+
? this.#clamp(requestedStart)
|
|
5956
|
+
: this.#numericValue();
|
|
5957
|
+
this.#startElasticPull();
|
|
5958
|
+
this.setAttribute("data-fig-input-wheel-active", "");
|
|
5959
|
+
document.body.classList.add(FigInputWheel.#DRAGGING_BODY_CLASS);
|
|
5960
|
+
this.focus();
|
|
5961
|
+
return true;
|
|
5962
|
+
}
|
|
5963
|
+
|
|
5964
|
+
updateScrub(position, speed) {
|
|
5965
|
+
if (!this.#isDragging) return this.#numericValue();
|
|
5966
|
+
const clientX =
|
|
5967
|
+
typeof position === "number"
|
|
5968
|
+
? position
|
|
5969
|
+
: Number(position?.clientX ?? position?.x);
|
|
5970
|
+
if (!Number.isFinite(clientX)) return this.#numericValue();
|
|
5971
|
+
const multiplier =
|
|
5972
|
+
speed ??
|
|
5973
|
+
(typeof position === "object" && position?.shiftKey ? 10 : 1);
|
|
5974
|
+
this.#updateDrag(clientX, multiplier);
|
|
5975
|
+
return this.#numericValue();
|
|
5976
|
+
}
|
|
5977
|
+
|
|
5978
|
+
endScrub(commit = true) {
|
|
5979
|
+
if (!this.#isDragging) return this.#numericValue();
|
|
5980
|
+
if (commit && this.#numericValue() !== this.#dragStartValue) {
|
|
5981
|
+
this.#commitValue(this.#numericValue(), { snap: true, emit: "change" });
|
|
5982
|
+
}
|
|
5983
|
+
this.#stopDrag();
|
|
5984
|
+
return this.#numericValue();
|
|
5985
|
+
}
|
|
5986
|
+
|
|
6174
5987
|
#handlePointerMove(event) {
|
|
6175
5988
|
if (!this.#isDragging) return;
|
|
6176
5989
|
if (this.#dragPointerId !== null && event.pointerId !== this.#dragPointerId) {
|
|
6177
5990
|
return;
|
|
6178
5991
|
}
|
|
6179
|
-
this
|
|
5992
|
+
this.updateScrub(event);
|
|
6180
5993
|
}
|
|
6181
5994
|
|
|
6182
5995
|
#updateDrag(clientX, speed = 1) {
|
|
6183
5996
|
const width = this.#wheel?.clientWidth || 1;
|
|
6184
5997
|
const visibleSteps =
|
|
6185
|
-
|
|
6186
|
-
((
|
|
5998
|
+
FigInputWheel.#TICK_COUNT *
|
|
5999
|
+
((FigInputWheel.#HALF_FOV_DEG * 2) / 360);
|
|
6187
6000
|
const visibleUnits = this.#step() * visibleSteps;
|
|
6188
6001
|
const delta =
|
|
6189
6002
|
(clientX - this.#dragStartX) * (visibleUnits / width) * speed;
|
|
@@ -6201,18 +6014,15 @@ class PropskitWheel extends HTMLElement {
|
|
|
6201
6014
|
if (this.#dragPointerId !== null && event.pointerId !== this.#dragPointerId) {
|
|
6202
6015
|
return;
|
|
6203
6016
|
}
|
|
6204
|
-
|
|
6205
|
-
this.#commitValue(this.#numericValue(), { snap: true, emit: "change" });
|
|
6206
|
-
}
|
|
6207
|
-
this.#stopDrag();
|
|
6017
|
+
this.endScrub();
|
|
6208
6018
|
}
|
|
6209
6019
|
|
|
6210
6020
|
#stopDrag() {
|
|
6211
6021
|
this.#isDragging = false;
|
|
6212
6022
|
this.#dragPointerId = null;
|
|
6213
6023
|
this.#visualValue = null;
|
|
6214
|
-
this.removeAttribute("data-active");
|
|
6215
|
-
document.body.classList.remove(
|
|
6024
|
+
this.removeAttribute("data-fig-input-wheel-active");
|
|
6025
|
+
document.body.classList.remove(FigInputWheel.#DRAGGING_BODY_CLASS);
|
|
6216
6026
|
this.#resetElasticPull();
|
|
6217
6027
|
window.removeEventListener("pointermove", this.#boundPointerMove);
|
|
6218
6028
|
window.removeEventListener("pointerup", this.#boundPointerUp);
|
|
@@ -6220,107 +6030,14 @@ class PropskitWheel extends HTMLElement {
|
|
|
6220
6030
|
this.#queueWheelLayout();
|
|
6221
6031
|
}
|
|
6222
6032
|
|
|
6223
|
-
#handleNumberPointerDown(event) {
|
|
6224
|
-
if (
|
|
6225
|
-
event.button !== 0 ||
|
|
6226
|
-
event.altKey ||
|
|
6227
|
-
figLabBooleanAttribute(this, "disabled") ||
|
|
6228
|
-
!(event.target instanceof Element)
|
|
6229
|
-
) {
|
|
6230
|
-
return;
|
|
6231
|
-
}
|
|
6232
|
-
const input = event.target.closest("fig-input-number input");
|
|
6233
|
-
if (!input || input === document.activeElement) return;
|
|
6234
|
-
|
|
6235
|
-
event.preventDefault();
|
|
6236
|
-
event.stopImmediatePropagation();
|
|
6237
|
-
this.#stopNumberTracking();
|
|
6238
|
-
this.#numberPointerId = event.pointerId;
|
|
6239
|
-
this.#numberPointerStartX = event.clientX;
|
|
6240
|
-
this.#numberPointerStartY = event.clientY;
|
|
6241
|
-
this.#numberPointerStartValue = this.#numericValue();
|
|
6242
|
-
window.addEventListener("pointermove", this.#boundNumberPointerMove);
|
|
6243
|
-
window.addEventListener("pointerup", this.#boundNumberPointerEnd, {
|
|
6244
|
-
once: true,
|
|
6245
|
-
});
|
|
6246
|
-
window.addEventListener("pointercancel", this.#boundNumberPointerEnd, {
|
|
6247
|
-
once: true,
|
|
6248
|
-
});
|
|
6249
|
-
window.addEventListener("blur", this.#boundNumberPointerEnd, {
|
|
6250
|
-
once: true,
|
|
6251
|
-
});
|
|
6252
|
-
}
|
|
6253
|
-
|
|
6254
|
-
#handleNumberPointerMove(event) {
|
|
6255
|
-
if (event.pointerId !== this.#numberPointerId) return;
|
|
6256
|
-
if (event.buttons === 0) {
|
|
6257
|
-
this.#handleNumberPointerEnd(event);
|
|
6258
|
-
return;
|
|
6259
|
-
}
|
|
6260
|
-
if (!this.#isNumberScrubbing) {
|
|
6261
|
-
const distance = Math.hypot(
|
|
6262
|
-
event.clientX - this.#numberPointerStartX,
|
|
6263
|
-
event.clientY - this.#numberPointerStartY,
|
|
6264
|
-
);
|
|
6265
|
-
if (distance < 4) return;
|
|
6266
|
-
this.#stopKeyboardAnimation();
|
|
6267
|
-
this.#isNumberScrubbing = true;
|
|
6268
|
-
this.setAttribute("data-number-scrubbing", "");
|
|
6269
|
-
this.#isDragging = true;
|
|
6270
|
-
this.#dragPointerId = event.pointerId;
|
|
6271
|
-
this.#dragStartX = this.#numberPointerStartX;
|
|
6272
|
-
this.#dragStartValue = this.#numberPointerStartValue;
|
|
6273
|
-
this.#startElasticPull();
|
|
6274
|
-
this.setAttribute("data-active", "");
|
|
6275
|
-
document.body.classList.add(PropskitWheel.#DRAGGING_BODY_CLASS);
|
|
6276
|
-
this.#wheel?.focus();
|
|
6277
|
-
}
|
|
6278
|
-
this.#updateDrag(event.clientX, event.shiftKey ? 10 : 1);
|
|
6279
|
-
}
|
|
6280
|
-
|
|
6281
|
-
#handleNumberPointerEnd(event) {
|
|
6282
|
-
if (
|
|
6283
|
-
event?.pointerId !== undefined &&
|
|
6284
|
-
this.#numberPointerId !== null &&
|
|
6285
|
-
event.pointerId !== this.#numberPointerId
|
|
6286
|
-
) {
|
|
6287
|
-
return;
|
|
6288
|
-
}
|
|
6289
|
-
const wasScrubbing = this.#isNumberScrubbing;
|
|
6290
|
-
this.#stopNumberTracking();
|
|
6291
|
-
if (wasScrubbing) {
|
|
6292
|
-
this.#commitValue(this.#numericValue(), { snap: true, emit: "change" });
|
|
6293
|
-
this.#stopDrag();
|
|
6294
|
-
this.#suppressNumberClick = true;
|
|
6295
|
-
clearTimeout(this.#numberClickResetTimer);
|
|
6296
|
-
this.#numberClickResetTimer = window.setTimeout(() => {
|
|
6297
|
-
this.#suppressNumberClick = false;
|
|
6298
|
-
this.#numberClickResetTimer = 0;
|
|
6299
|
-
}, 0);
|
|
6300
|
-
requestAnimationFrame(() => this.#wheel?.focus());
|
|
6301
|
-
return;
|
|
6302
|
-
}
|
|
6303
|
-
this.#input?.querySelector("input")?.focus();
|
|
6304
|
-
}
|
|
6305
|
-
|
|
6306
|
-
#stopNumberTracking() {
|
|
6307
|
-
window.removeEventListener("pointermove", this.#boundNumberPointerMove);
|
|
6308
|
-
window.removeEventListener("pointerup", this.#boundNumberPointerEnd);
|
|
6309
|
-
window.removeEventListener("pointercancel", this.#boundNumberPointerEnd);
|
|
6310
|
-
window.removeEventListener("blur", this.#boundNumberPointerEnd);
|
|
6311
|
-
this.#numberPointerId = null;
|
|
6312
|
-
this.#isNumberScrubbing = false;
|
|
6313
|
-
this.removeAttribute("data-number-scrubbing");
|
|
6314
|
-
}
|
|
6315
|
-
|
|
6316
6033
|
#startElasticPull() {
|
|
6317
6034
|
this.#resetElasticPull();
|
|
6318
6035
|
if (this.getAttribute("elastic") === "false") return;
|
|
6319
6036
|
this.#handleDragMaxPx = this.#readCssLength(
|
|
6320
|
-
"--
|
|
6037
|
+
"--fig-input-wheel-handle-drag-max",
|
|
6321
6038
|
);
|
|
6322
6039
|
this.#elasticMaxPx = this.#readCssLength(
|
|
6323
|
-
"--
|
|
6040
|
+
"--fig-input-wheel-elastic-distance",
|
|
6324
6041
|
);
|
|
6325
6042
|
const rect = this.#wheel?.getBoundingClientRect();
|
|
6326
6043
|
if (rect) {
|
|
@@ -6367,9 +6084,9 @@ class PropskitWheel extends HTMLElement {
|
|
|
6367
6084
|
Math.tanh(
|
|
6368
6085
|
dragDelta / Math.max(1, this.#handleDragMaxPx * 3),
|
|
6369
6086
|
);
|
|
6370
|
-
this.
|
|
6087
|
+
this.setAttribute("data-fig-input-wheel-elastic-dragging", "");
|
|
6371
6088
|
this.style.setProperty(
|
|
6372
|
-
"--
|
|
6089
|
+
"--fig-input-wheel-handle-drag-offset",
|
|
6373
6090
|
`${offset}px`,
|
|
6374
6091
|
);
|
|
6375
6092
|
|
|
@@ -6382,17 +6099,17 @@ class PropskitWheel extends HTMLElement {
|
|
|
6382
6099
|
: 0
|
|
6383
6100
|
: 0;
|
|
6384
6101
|
if (!overshoot || !this.#elasticMaxPx) {
|
|
6385
|
-
this.style.removeProperty("--
|
|
6386
|
-
this.style.removeProperty("--
|
|
6102
|
+
this.style.removeProperty("--fig-input-wheel-elastic-scale");
|
|
6103
|
+
this.style.removeProperty("--fig-input-wheel-elastic-origin");
|
|
6387
6104
|
return;
|
|
6388
6105
|
}
|
|
6389
6106
|
const stretch = Math.min(this.#elasticMaxPx, Math.abs(overshoot) * 0.5);
|
|
6390
6107
|
const scale = this.#elasticHostWidth
|
|
6391
6108
|
? (this.#elasticHostWidth + stretch) / this.#elasticHostWidth
|
|
6392
6109
|
: 1;
|
|
6393
|
-
this.style.setProperty("--
|
|
6110
|
+
this.style.setProperty("--fig-input-wheel-elastic-scale", `${scale}`);
|
|
6394
6111
|
this.style.setProperty(
|
|
6395
|
-
"--
|
|
6112
|
+
"--fig-input-wheel-elastic-origin",
|
|
6396
6113
|
overshoot < 0 ? "right center" : "left center",
|
|
6397
6114
|
);
|
|
6398
6115
|
}
|
|
@@ -6406,10 +6123,10 @@ class PropskitWheel extends HTMLElement {
|
|
|
6406
6123
|
}
|
|
6407
6124
|
|
|
6408
6125
|
#clearElasticPull() {
|
|
6409
|
-
this.removeAttribute("data-elastic-dragging");
|
|
6410
|
-
this.style.removeProperty("--
|
|
6411
|
-
this.style.removeProperty("--
|
|
6412
|
-
this.style.removeProperty("--
|
|
6126
|
+
this.removeAttribute("data-fig-input-wheel-elastic-dragging");
|
|
6127
|
+
this.style.removeProperty("--fig-input-wheel-handle-drag-offset");
|
|
6128
|
+
this.style.removeProperty("--fig-input-wheel-elastic-scale");
|
|
6129
|
+
this.style.removeProperty("--fig-input-wheel-elastic-origin");
|
|
6413
6130
|
}
|
|
6414
6131
|
|
|
6415
6132
|
#handleWheel(event) {
|
|
@@ -6484,16 +6201,16 @@ class PropskitWheel extends HTMLElement {
|
|
|
6484
6201
|
}
|
|
6485
6202
|
clearTimeout(this.#keyboardSettleTimer);
|
|
6486
6203
|
this.#keyboardSettleTimer = 0;
|
|
6487
|
-
this.removeAttribute("data-keyboard-settling");
|
|
6204
|
+
this.removeAttribute("data-fig-input-wheel-keyboard-settling");
|
|
6488
6205
|
const visualFrom = this.#visualValue ?? from;
|
|
6489
6206
|
const handleFrom =
|
|
6490
6207
|
Number.parseFloat(
|
|
6491
|
-
this.style.getPropertyValue("--
|
|
6208
|
+
this.style.getPropertyValue("--fig-input-wheel-handle-drag-offset"),
|
|
6492
6209
|
) || 0;
|
|
6493
6210
|
const duration = multiplier > 1 ? 120 : 90;
|
|
6494
6211
|
const startedAt = performance.now();
|
|
6495
6212
|
const animateHandle = this.getAttribute("elastic") !== "false";
|
|
6496
|
-
this.setAttribute("data-keyboard-moving", "");
|
|
6213
|
+
this.setAttribute("data-fig-input-wheel-keyboard-moving", "");
|
|
6497
6214
|
|
|
6498
6215
|
const frame = (now) => {
|
|
6499
6216
|
const progress = Math.min(1, (now - startedAt) / duration);
|
|
@@ -6502,7 +6219,7 @@ class PropskitWheel extends HTMLElement {
|
|
|
6502
6219
|
const eased = Math.sin((progress * Math.PI) / 2);
|
|
6503
6220
|
const offset = handleFrom + (direction * 4 - handleFrom) * eased;
|
|
6504
6221
|
this.style.setProperty(
|
|
6505
|
-
"--
|
|
6222
|
+
"--fig-input-wheel-handle-drag-offset",
|
|
6506
6223
|
`${offset}px`,
|
|
6507
6224
|
);
|
|
6508
6225
|
}
|
|
@@ -6515,11 +6232,11 @@ class PropskitWheel extends HTMLElement {
|
|
|
6515
6232
|
|
|
6516
6233
|
this.#keyboardAnimationFrame = 0;
|
|
6517
6234
|
this.#visualValue = null;
|
|
6518
|
-
this.removeAttribute("data-keyboard-moving");
|
|
6519
|
-
this.setAttribute("data-keyboard-settling", "");
|
|
6520
|
-
this.style.removeProperty("--
|
|
6235
|
+
this.removeAttribute("data-fig-input-wheel-keyboard-moving");
|
|
6236
|
+
this.setAttribute("data-fig-input-wheel-keyboard-settling", "");
|
|
6237
|
+
this.style.removeProperty("--fig-input-wheel-handle-drag-offset");
|
|
6521
6238
|
this.#keyboardSettleTimer = window.setTimeout(() => {
|
|
6522
|
-
this.removeAttribute("data-keyboard-settling");
|
|
6239
|
+
this.removeAttribute("data-fig-input-wheel-keyboard-settling");
|
|
6523
6240
|
this.#keyboardSettleTimer = 0;
|
|
6524
6241
|
}, 140);
|
|
6525
6242
|
this.#queueWheelLayout();
|
|
@@ -6536,9 +6253,9 @@ class PropskitWheel extends HTMLElement {
|
|
|
6536
6253
|
clearTimeout(this.#keyboardSettleTimer);
|
|
6537
6254
|
this.#keyboardSettleTimer = 0;
|
|
6538
6255
|
this.#visualValue = null;
|
|
6539
|
-
this.removeAttribute("data-keyboard-moving");
|
|
6540
|
-
this.removeAttribute("data-keyboard-settling");
|
|
6541
|
-
this.style.removeProperty("--
|
|
6256
|
+
this.removeAttribute("data-fig-input-wheel-keyboard-moving");
|
|
6257
|
+
this.removeAttribute("data-fig-input-wheel-keyboard-settling");
|
|
6258
|
+
this.style.removeProperty("--fig-input-wheel-handle-drag-offset");
|
|
6542
6259
|
if (this.isConnected) this.#queueWheelLayout();
|
|
6543
6260
|
}
|
|
6544
6261
|
|
|
@@ -6571,6 +6288,573 @@ class PropskitWheel extends HTMLElement {
|
|
|
6571
6288
|
this.#writeBound("max", nextValue);
|
|
6572
6289
|
}
|
|
6573
6290
|
|
|
6291
|
+
get step() {
|
|
6292
|
+
return this.#step();
|
|
6293
|
+
}
|
|
6294
|
+
|
|
6295
|
+
focus(options) {
|
|
6296
|
+
HTMLElement.prototype.focus.call(this, options);
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
figLabDefineElement("fig-input-wheel", FigInputWheel);
|
|
6300
|
+
|
|
6301
|
+
/**
|
|
6302
|
+
* Labeled numeric wheel with an optional editable number field.
|
|
6303
|
+
*
|
|
6304
|
+
* @attr {string} label - Field label. Defaults to "Value".
|
|
6305
|
+
* @attr {string} default - Reset target.
|
|
6306
|
+
* @attr {number} precision - Number field display decimals.
|
|
6307
|
+
* @attr {boolean|string} text - Shows the number field. Defaults to true.
|
|
6308
|
+
* @attr {string} size - Set to "small" for compact sizing.
|
|
6309
|
+
* @attr {string} variant - Set to "minimal" for compact chrome.
|
|
6310
|
+
* @fires input - Retargeted numeric composed event.
|
|
6311
|
+
* @fires change - Retargeted numeric composed event.
|
|
6312
|
+
*/
|
|
6313
|
+
class PropskitWheel extends HTMLElement {
|
|
6314
|
+
static #RESERVED_ATTRS = new Set([
|
|
6315
|
+
"label",
|
|
6316
|
+
"size",
|
|
6317
|
+
"disabled",
|
|
6318
|
+
"variant",
|
|
6319
|
+
"elastic",
|
|
6320
|
+
"text",
|
|
6321
|
+
"default",
|
|
6322
|
+
"class",
|
|
6323
|
+
"style",
|
|
6324
|
+
"id",
|
|
6325
|
+
"oninput",
|
|
6326
|
+
"onchange",
|
|
6327
|
+
]);
|
|
6328
|
+
|
|
6329
|
+
static get observedAttributes() {
|
|
6330
|
+
return [
|
|
6331
|
+
"label",
|
|
6332
|
+
"units",
|
|
6333
|
+
"value",
|
|
6334
|
+
"disabled",
|
|
6335
|
+
"step",
|
|
6336
|
+
"precision",
|
|
6337
|
+
"min",
|
|
6338
|
+
"max",
|
|
6339
|
+
"elastic",
|
|
6340
|
+
"text",
|
|
6341
|
+
];
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
#surface = null;
|
|
6345
|
+
#wheel = null;
|
|
6346
|
+
#label = null;
|
|
6347
|
+
#input = null;
|
|
6348
|
+
#hasCustomLabel = false;
|
|
6349
|
+
#observer = null;
|
|
6350
|
+
#elasticObserver = null;
|
|
6351
|
+
#managedInputAttrs = new Set();
|
|
6352
|
+
#initialValue = null;
|
|
6353
|
+
#numberPointerId = null;
|
|
6354
|
+
#numberPointerStartX = 0;
|
|
6355
|
+
#numberPointerStartY = 0;
|
|
6356
|
+
#numberPointerStartValue = 0;
|
|
6357
|
+
#isNumberScrubbing = false;
|
|
6358
|
+
#suppressNumberClick = false;
|
|
6359
|
+
#numberClickResetTimer = 0;
|
|
6360
|
+
#boundPrimitiveInput = this.#handlePrimitiveEvent.bind(this, "input");
|
|
6361
|
+
#boundPrimitiveChange = this.#handlePrimitiveEvent.bind(this, "change");
|
|
6362
|
+
#boundNumberInput = this.#handleNumberEvent.bind(this, "input");
|
|
6363
|
+
#boundNumberChange = this.#handleNumberEvent.bind(this, "change");
|
|
6364
|
+
#boundNumberPointerDown = this.#handleNumberPointerDown.bind(this);
|
|
6365
|
+
#boundNumberPointerMove = this.#handleNumberPointerMove.bind(this);
|
|
6366
|
+
#boundNumberPointerEnd = this.#handleNumberPointerEnd.bind(this);
|
|
6367
|
+
#boundClick = this.#handleClick.bind(this);
|
|
6368
|
+
|
|
6369
|
+
connectedCallback() {
|
|
6370
|
+
if (!this.#surface) this.#initialize();
|
|
6371
|
+
this.#syncLabel();
|
|
6372
|
+
this.#syncText();
|
|
6373
|
+
this.#syncPrimitive();
|
|
6374
|
+
this.#syncInputAttributes();
|
|
6375
|
+
this.#bindEvents();
|
|
6376
|
+
figLabConnectPropskitResetMenu(this);
|
|
6377
|
+
this.#observer?.disconnect();
|
|
6378
|
+
this.#observer = new MutationObserver((mutations) => {
|
|
6379
|
+
if (
|
|
6380
|
+
mutations.some(
|
|
6381
|
+
({ type, attributeName }) =>
|
|
6382
|
+
type === "attributes" &&
|
|
6383
|
+
attributeName &&
|
|
6384
|
+
!PropskitWheel.#RESERVED_ATTRS.has(attributeName) &&
|
|
6385
|
+
!PropskitWheel.observedAttributes.includes(attributeName) &&
|
|
6386
|
+
!attributeName.startsWith("data-"),
|
|
6387
|
+
)
|
|
6388
|
+
) {
|
|
6389
|
+
this.#syncInputAttributes();
|
|
6390
|
+
}
|
|
6391
|
+
});
|
|
6392
|
+
this.#observer.observe(this, { attributes: true });
|
|
6393
|
+
this.#elasticObserver?.disconnect();
|
|
6394
|
+
this.#elasticObserver = new MutationObserver(() => {
|
|
6395
|
+
this.#syncElasticComposition();
|
|
6396
|
+
});
|
|
6397
|
+
if (this.#wheel) {
|
|
6398
|
+
this.#elasticObserver.observe(this.#wheel, {
|
|
6399
|
+
attributes: true,
|
|
6400
|
+
attributeFilter: ["style", "data-fig-input-wheel-elastic-dragging"],
|
|
6401
|
+
});
|
|
6402
|
+
}
|
|
6403
|
+
this.#syncElasticComposition();
|
|
6404
|
+
}
|
|
6405
|
+
|
|
6406
|
+
disconnectedCallback() {
|
|
6407
|
+
this.#observer?.disconnect();
|
|
6408
|
+
this.#elasticObserver?.disconnect();
|
|
6409
|
+
this.#elasticObserver = null;
|
|
6410
|
+
this.#clearElasticComposition();
|
|
6411
|
+
this.#unbindEvents();
|
|
6412
|
+
this.#stopNumberTracking();
|
|
6413
|
+
clearTimeout(this.#numberClickResetTimer);
|
|
6414
|
+
this.#numberClickResetTimer = 0;
|
|
6415
|
+
this.#wheel?.endScrub(false);
|
|
6416
|
+
figLabDisconnectPropskitResetMenu(this);
|
|
6417
|
+
}
|
|
6418
|
+
|
|
6419
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
6420
|
+
if (oldValue === newValue || !this.#surface) return;
|
|
6421
|
+
if (name === "label") this.#syncLabel();
|
|
6422
|
+
if (name === "text") this.#syncText();
|
|
6423
|
+
if (
|
|
6424
|
+
["units", "value", "disabled", "step", "min", "max", "elastic"].includes(
|
|
6425
|
+
name,
|
|
6426
|
+
)
|
|
6427
|
+
) {
|
|
6428
|
+
this.#syncPrimitive();
|
|
6429
|
+
}
|
|
6430
|
+
if (
|
|
6431
|
+
["units", "value", "disabled", "step", "precision", "min", "max"].includes(
|
|
6432
|
+
name,
|
|
6433
|
+
)
|
|
6434
|
+
) {
|
|
6435
|
+
this.#syncInputAttributes();
|
|
6436
|
+
}
|
|
6437
|
+
}
|
|
6438
|
+
|
|
6439
|
+
#initialize() {
|
|
6440
|
+
this.#initialValue = this.getAttribute("value") ?? "0";
|
|
6441
|
+
const initialChildren = Array.from(this.childNodes).filter(
|
|
6442
|
+
(node) =>
|
|
6443
|
+
node.nodeType !== Node.TEXT_NODE || Boolean(node.textContent?.trim()),
|
|
6444
|
+
);
|
|
6445
|
+
const customLabel = initialChildren.find(
|
|
6446
|
+
(node) => node.nodeType === Node.ELEMENT_NODE && node.matches("label"),
|
|
6447
|
+
);
|
|
6448
|
+
const surface = figLabCreateElement("div", {
|
|
6449
|
+
className: "propskit-wheel-surface",
|
|
6450
|
+
});
|
|
6451
|
+
const label = customLabel || document.createElement("label");
|
|
6452
|
+
const wheel = document.createElement("fig-input-wheel");
|
|
6453
|
+
const input = document.createElement("fig-input-number");
|
|
6454
|
+
const labelId = figLabUniqueId("propskit-wheel-label");
|
|
6455
|
+
label.id = labelId;
|
|
6456
|
+
wheel.setAttribute("aria-labelledby", labelId);
|
|
6457
|
+
input.setAttribute("aria-labelledby", labelId);
|
|
6458
|
+
surface.append(label, wheel, input);
|
|
6459
|
+
this.#surface = surface;
|
|
6460
|
+
this.#wheel = wheel;
|
|
6461
|
+
this.#label = label;
|
|
6462
|
+
this.#input = input;
|
|
6463
|
+
this.#hasCustomLabel = Boolean(customLabel);
|
|
6464
|
+
this.replaceChildren(surface);
|
|
6465
|
+
for (const node of initialChildren) {
|
|
6466
|
+
if (node !== customLabel) input.appendChild(node);
|
|
6467
|
+
}
|
|
6468
|
+
}
|
|
6469
|
+
|
|
6470
|
+
#syncLabel() {
|
|
6471
|
+
if (!this.#label) return;
|
|
6472
|
+
if (!this.#hasCustomLabel) {
|
|
6473
|
+
this.#label.textContent = this.hasAttribute("label")
|
|
6474
|
+
? (this.getAttribute("label") ?? "")
|
|
6475
|
+
: "Value";
|
|
6476
|
+
}
|
|
6477
|
+
this.toggleAttribute(
|
|
6478
|
+
"data-label-empty",
|
|
6479
|
+
!(this.#label.textContent ?? "").trim(),
|
|
6480
|
+
);
|
|
6481
|
+
}
|
|
6482
|
+
|
|
6483
|
+
#syncText() {
|
|
6484
|
+
if (!this.#surface || !this.#input) return;
|
|
6485
|
+
const enabled = this.getAttribute("text") !== "false";
|
|
6486
|
+
const isInserted = this.#input.parentElement === this.#surface;
|
|
6487
|
+
if (enabled && !isInserted) this.#surface.append(this.#input);
|
|
6488
|
+
else if (!enabled && isInserted) this.#input.remove();
|
|
6489
|
+
}
|
|
6490
|
+
|
|
6491
|
+
#mirrorAttribute(name) {
|
|
6492
|
+
if (!this.#wheel) return;
|
|
6493
|
+
if (this.hasAttribute(name)) {
|
|
6494
|
+
this.#wheel.setAttribute(name, this.getAttribute(name) ?? "");
|
|
6495
|
+
} else {
|
|
6496
|
+
this.#wheel.removeAttribute(name);
|
|
6497
|
+
}
|
|
6498
|
+
}
|
|
6499
|
+
|
|
6500
|
+
#syncPrimitive() {
|
|
6501
|
+
if (!this.#wheel) return;
|
|
6502
|
+
this.#wheel.removeAttribute("units");
|
|
6503
|
+
for (const name of ["min", "max", "elastic"]) {
|
|
6504
|
+
this.#mirrorAttribute(name);
|
|
6505
|
+
}
|
|
6506
|
+
if (this.hasAttribute("step")) this.#mirrorAttribute("step");
|
|
6507
|
+
else this.#wheel.setAttribute("step", String(this.#defaultStep()));
|
|
6508
|
+
this.#wheel.toggleAttribute(
|
|
6509
|
+
"disabled",
|
|
6510
|
+
figLabBooleanAttribute(this, "disabled"),
|
|
6511
|
+
);
|
|
6512
|
+
this.#wheel.value = this.getAttribute("value") ?? "0";
|
|
6513
|
+
const normalized = this.#wheel.value;
|
|
6514
|
+
if (this.getAttribute("value") !== normalized) {
|
|
6515
|
+
this.setAttribute("value", normalized);
|
|
6516
|
+
}
|
|
6517
|
+
if (this.#input?.getAttribute("value") !== normalized) {
|
|
6518
|
+
this.#input?.setAttribute("value", normalized);
|
|
6519
|
+
}
|
|
6520
|
+
this.#syncPrimitiveAria();
|
|
6521
|
+
}
|
|
6522
|
+
|
|
6523
|
+
#syncElasticComposition() {
|
|
6524
|
+
if (!this.#wheel) return;
|
|
6525
|
+
const active = this.#wheel.hasAttribute(
|
|
6526
|
+
"data-fig-input-wheel-elastic-dragging",
|
|
6527
|
+
);
|
|
6528
|
+
if (!active) {
|
|
6529
|
+
this.#clearElasticComposition();
|
|
6530
|
+
return;
|
|
6531
|
+
}
|
|
6532
|
+
this.toggleAttribute("data-propskit-wheel-elastic-dragging", true);
|
|
6533
|
+
this.style.setProperty(
|
|
6534
|
+
"--propskit-wheel-elastic-scale",
|
|
6535
|
+
this.#wheel.style.getPropertyValue("--fig-input-wheel-elastic-scale") ||
|
|
6536
|
+
"1",
|
|
6537
|
+
);
|
|
6538
|
+
this.style.setProperty(
|
|
6539
|
+
"--propskit-wheel-elastic-origin",
|
|
6540
|
+
this.#wheel.style.getPropertyValue("--fig-input-wheel-elastic-origin") ||
|
|
6541
|
+
"left center",
|
|
6542
|
+
);
|
|
6543
|
+
}
|
|
6544
|
+
|
|
6545
|
+
#clearElasticComposition() {
|
|
6546
|
+
this.removeAttribute("data-propskit-wheel-elastic-dragging");
|
|
6547
|
+
this.style.removeProperty("--propskit-wheel-elastic-scale");
|
|
6548
|
+
this.style.removeProperty("--propskit-wheel-elastic-origin");
|
|
6549
|
+
}
|
|
6550
|
+
|
|
6551
|
+
#getForwardedInputAttrNames() {
|
|
6552
|
+
return this.getAttributeNames().filter(
|
|
6553
|
+
(name) =>
|
|
6554
|
+
!PropskitWheel.#RESERVED_ATTRS.has(name) &&
|
|
6555
|
+
!PropskitWheel.observedAttributes.includes(name) &&
|
|
6556
|
+
!name.startsWith("data-"),
|
|
6557
|
+
);
|
|
6558
|
+
}
|
|
6559
|
+
|
|
6560
|
+
#units() {
|
|
6561
|
+
const raw = (this.getAttribute("units") || "").trim();
|
|
6562
|
+
const normalized = raw.toLowerCase();
|
|
6563
|
+
if (
|
|
6564
|
+
normalized === "ms" ||
|
|
6565
|
+
normalized === "millisecond" ||
|
|
6566
|
+
normalized === "milliseconds"
|
|
6567
|
+
) {
|
|
6568
|
+
return "ms";
|
|
6569
|
+
}
|
|
6570
|
+
if (
|
|
6571
|
+
normalized === "s" ||
|
|
6572
|
+
normalized === "second" ||
|
|
6573
|
+
normalized === "seconds"
|
|
6574
|
+
) {
|
|
6575
|
+
return "s";
|
|
6576
|
+
}
|
|
6577
|
+
return raw;
|
|
6578
|
+
}
|
|
6579
|
+
|
|
6580
|
+
#defaultStep() {
|
|
6581
|
+
const units = this.#units();
|
|
6582
|
+
if (units === "s") return 0.1;
|
|
6583
|
+
if (units === "ms") return 100;
|
|
6584
|
+
return 1;
|
|
6585
|
+
}
|
|
6586
|
+
|
|
6587
|
+
#defaultPrecision() {
|
|
6588
|
+
return this.#units() === "s" ? 2 : 0;
|
|
6589
|
+
}
|
|
6590
|
+
|
|
6591
|
+
#syncPrimitiveAria() {
|
|
6592
|
+
if (!this.#wheel) return;
|
|
6593
|
+
const value = Number(this.#wheel.value);
|
|
6594
|
+
const units = this.#units();
|
|
6595
|
+
this.#wheel.setAttribute(
|
|
6596
|
+
"aria-valuetext",
|
|
6597
|
+
units
|
|
6598
|
+
? `${value} ${
|
|
6599
|
+
units === "s" ? "seconds" : units === "ms" ? "milliseconds" : units
|
|
6600
|
+
}`
|
|
6601
|
+
: String(value),
|
|
6602
|
+
);
|
|
6603
|
+
}
|
|
6604
|
+
|
|
6605
|
+
#syncInputAttributes() {
|
|
6606
|
+
if (!this.#input || !this.#wheel) return;
|
|
6607
|
+
const forwarded = this.#getForwardedInputAttrNames();
|
|
6608
|
+
const nextManaged = new Set(forwarded);
|
|
6609
|
+
for (const name of this.#managedInputAttrs) {
|
|
6610
|
+
if (!nextManaged.has(name)) this.#input.removeAttribute(name);
|
|
6611
|
+
}
|
|
6612
|
+
for (const name of forwarded) {
|
|
6613
|
+
this.#input.setAttribute(name, this.getAttribute(name) ?? "");
|
|
6614
|
+
}
|
|
6615
|
+
const units = this.#units();
|
|
6616
|
+
if (units) this.#input.setAttribute("units", units);
|
|
6617
|
+
else this.#input.removeAttribute("units");
|
|
6618
|
+
this.#input.setAttribute("step", String(this.#wheel.step));
|
|
6619
|
+
if (this.hasAttribute("precision")) {
|
|
6620
|
+
this.#input.setAttribute(
|
|
6621
|
+
"precision",
|
|
6622
|
+
this.getAttribute("precision") ?? "",
|
|
6623
|
+
);
|
|
6624
|
+
} else {
|
|
6625
|
+
this.#input.setAttribute("precision", String(this.#defaultPrecision()));
|
|
6626
|
+
}
|
|
6627
|
+
for (const name of ["min", "max"]) {
|
|
6628
|
+
const value = this.#wheel[name];
|
|
6629
|
+
if (value === null) this.#input.removeAttribute(name);
|
|
6630
|
+
else this.#input.setAttribute(name, String(value));
|
|
6631
|
+
}
|
|
6632
|
+
this.#input.toggleAttribute(
|
|
6633
|
+
"disabled",
|
|
6634
|
+
figLabBooleanAttribute(this, "disabled"),
|
|
6635
|
+
);
|
|
6636
|
+
this.#input.setAttribute("value", this.#wheel.value);
|
|
6637
|
+
this.#managedInputAttrs = nextManaged;
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
#bindEvents() {
|
|
6641
|
+
this.#unbindEvents();
|
|
6642
|
+
this.#wheel?.addEventListener("input", this.#boundPrimitiveInput);
|
|
6643
|
+
this.#wheel?.addEventListener("change", this.#boundPrimitiveChange);
|
|
6644
|
+
this.#input?.addEventListener("input", this.#boundNumberInput);
|
|
6645
|
+
this.#input?.addEventListener("change", this.#boundNumberChange);
|
|
6646
|
+
this.addEventListener("pointerdown", this.#boundNumberPointerDown, {
|
|
6647
|
+
capture: true,
|
|
6648
|
+
});
|
|
6649
|
+
this.addEventListener("click", this.#boundClick, true);
|
|
6650
|
+
}
|
|
6651
|
+
|
|
6652
|
+
#unbindEvents() {
|
|
6653
|
+
this.#wheel?.removeEventListener("input", this.#boundPrimitiveInput);
|
|
6654
|
+
this.#wheel?.removeEventListener("change", this.#boundPrimitiveChange);
|
|
6655
|
+
this.#input?.removeEventListener("input", this.#boundNumberInput);
|
|
6656
|
+
this.#input?.removeEventListener("change", this.#boundNumberChange);
|
|
6657
|
+
this.removeEventListener("pointerdown", this.#boundNumberPointerDown, {
|
|
6658
|
+
capture: true,
|
|
6659
|
+
});
|
|
6660
|
+
this.removeEventListener("click", this.#boundClick, true);
|
|
6661
|
+
}
|
|
6662
|
+
|
|
6663
|
+
#setSynchronizedValue(value) {
|
|
6664
|
+
const parsed = Number(value);
|
|
6665
|
+
if (!this.#wheel) {
|
|
6666
|
+
const normalized = Number.isFinite(parsed) ? parsed : 0;
|
|
6667
|
+
this.setAttribute("value", String(normalized));
|
|
6668
|
+
return normalized;
|
|
6669
|
+
}
|
|
6670
|
+
this.#wheel.value = Number.isFinite(parsed) ? parsed : 0;
|
|
6671
|
+
const normalized = this.#wheel.value;
|
|
6672
|
+
if (this.getAttribute("value") !== normalized) {
|
|
6673
|
+
this.setAttribute("value", normalized);
|
|
6674
|
+
}
|
|
6675
|
+
if (this.#input?.getAttribute("value") !== normalized) {
|
|
6676
|
+
this.#input?.setAttribute("value", normalized);
|
|
6677
|
+
}
|
|
6678
|
+
this.#syncPrimitiveAria();
|
|
6679
|
+
return Number(normalized);
|
|
6680
|
+
}
|
|
6681
|
+
|
|
6682
|
+
#emit(type, value) {
|
|
6683
|
+
this.dispatchEvent(
|
|
6684
|
+
new CustomEvent(type, {
|
|
6685
|
+
detail: value,
|
|
6686
|
+
bubbles: true,
|
|
6687
|
+
cancelable: true,
|
|
6688
|
+
composed: true,
|
|
6689
|
+
}),
|
|
6690
|
+
);
|
|
6691
|
+
}
|
|
6692
|
+
|
|
6693
|
+
#handlePrimitiveEvent(type, event) {
|
|
6694
|
+
event.stopImmediatePropagation();
|
|
6695
|
+
const value = this.#setSynchronizedValue(event.detail);
|
|
6696
|
+
this.#emit(type, value);
|
|
6697
|
+
}
|
|
6698
|
+
|
|
6699
|
+
#handleNumberEvent(type, event) {
|
|
6700
|
+
event.stopImmediatePropagation();
|
|
6701
|
+
if (figLabBooleanAttribute(this, "disabled")) return;
|
|
6702
|
+
const raw =
|
|
6703
|
+
event instanceof CustomEvent && event.detail !== undefined
|
|
6704
|
+
? event.detail
|
|
6705
|
+
: this.#input?.value;
|
|
6706
|
+
const value = this.#setSynchronizedValue(raw);
|
|
6707
|
+
this.#emit(type, value);
|
|
6708
|
+
}
|
|
6709
|
+
|
|
6710
|
+
#handleNumberPointerDown(event) {
|
|
6711
|
+
if (
|
|
6712
|
+
event.button !== 0 ||
|
|
6713
|
+
event.altKey ||
|
|
6714
|
+
figLabBooleanAttribute(this, "disabled") ||
|
|
6715
|
+
!(event.target instanceof Element)
|
|
6716
|
+
) {
|
|
6717
|
+
return;
|
|
6718
|
+
}
|
|
6719
|
+
const input = event.target.closest("fig-input-number input");
|
|
6720
|
+
if (!input || input === document.activeElement) return;
|
|
6721
|
+
event.preventDefault();
|
|
6722
|
+
event.stopImmediatePropagation();
|
|
6723
|
+
this.#stopNumberTracking();
|
|
6724
|
+
this.#numberPointerId = event.pointerId;
|
|
6725
|
+
this.#numberPointerStartX = event.clientX;
|
|
6726
|
+
this.#numberPointerStartY = event.clientY;
|
|
6727
|
+
this.#numberPointerStartValue = Number(this.#wheel?.value ?? 0);
|
|
6728
|
+
window.addEventListener("pointermove", this.#boundNumberPointerMove);
|
|
6729
|
+
window.addEventListener("pointerup", this.#boundNumberPointerEnd, {
|
|
6730
|
+
once: true,
|
|
6731
|
+
});
|
|
6732
|
+
window.addEventListener("pointercancel", this.#boundNumberPointerEnd, {
|
|
6733
|
+
once: true,
|
|
6734
|
+
});
|
|
6735
|
+
window.addEventListener("blur", this.#boundNumberPointerEnd, {
|
|
6736
|
+
once: true,
|
|
6737
|
+
});
|
|
6738
|
+
}
|
|
6739
|
+
|
|
6740
|
+
#handleNumberPointerMove(event) {
|
|
6741
|
+
if (event.pointerId !== this.#numberPointerId) return;
|
|
6742
|
+
if (event.buttons === 0) {
|
|
6743
|
+
this.#handleNumberPointerEnd(event);
|
|
6744
|
+
return;
|
|
6745
|
+
}
|
|
6746
|
+
if (!this.#isNumberScrubbing) {
|
|
6747
|
+
const distance = Math.hypot(
|
|
6748
|
+
event.clientX - this.#numberPointerStartX,
|
|
6749
|
+
event.clientY - this.#numberPointerStartY,
|
|
6750
|
+
);
|
|
6751
|
+
if (distance < 4) return;
|
|
6752
|
+
this.#isNumberScrubbing = true;
|
|
6753
|
+
this.setAttribute("data-number-scrubbing", "");
|
|
6754
|
+
this.#wheel?.beginScrub({
|
|
6755
|
+
clientX: this.#numberPointerStartX,
|
|
6756
|
+
pointerId: event.pointerId,
|
|
6757
|
+
startValue: this.#numberPointerStartValue,
|
|
6758
|
+
});
|
|
6759
|
+
}
|
|
6760
|
+
this.#wheel?.updateScrub(event);
|
|
6761
|
+
}
|
|
6762
|
+
|
|
6763
|
+
#handleNumberPointerEnd(event) {
|
|
6764
|
+
if (
|
|
6765
|
+
event?.pointerId !== undefined &&
|
|
6766
|
+
this.#numberPointerId !== null &&
|
|
6767
|
+
event.pointerId !== this.#numberPointerId
|
|
6768
|
+
) {
|
|
6769
|
+
return;
|
|
6770
|
+
}
|
|
6771
|
+
const wasScrubbing = this.#isNumberScrubbing;
|
|
6772
|
+
this.#stopNumberTracking();
|
|
6773
|
+
if (wasScrubbing) {
|
|
6774
|
+
this.#wheel?.endScrub();
|
|
6775
|
+
this.#suppressNumberClick = true;
|
|
6776
|
+
clearTimeout(this.#numberClickResetTimer);
|
|
6777
|
+
this.#numberClickResetTimer = window.setTimeout(() => {
|
|
6778
|
+
this.#suppressNumberClick = false;
|
|
6779
|
+
this.#numberClickResetTimer = 0;
|
|
6780
|
+
}, 0);
|
|
6781
|
+
requestAnimationFrame(() => this.#wheel?.focus());
|
|
6782
|
+
return;
|
|
6783
|
+
}
|
|
6784
|
+
this.#input?.querySelector("input")?.focus();
|
|
6785
|
+
}
|
|
6786
|
+
|
|
6787
|
+
#stopNumberTracking() {
|
|
6788
|
+
window.removeEventListener("pointermove", this.#boundNumberPointerMove);
|
|
6789
|
+
window.removeEventListener("pointerup", this.#boundNumberPointerEnd);
|
|
6790
|
+
window.removeEventListener("pointercancel", this.#boundNumberPointerEnd);
|
|
6791
|
+
window.removeEventListener("blur", this.#boundNumberPointerEnd);
|
|
6792
|
+
this.#numberPointerId = null;
|
|
6793
|
+
this.#isNumberScrubbing = false;
|
|
6794
|
+
this.removeAttribute("data-number-scrubbing");
|
|
6795
|
+
}
|
|
6796
|
+
|
|
6797
|
+
#handleClick(event) {
|
|
6798
|
+
if (figLabBooleanAttribute(this, "disabled")) return;
|
|
6799
|
+
if (
|
|
6800
|
+
event.target instanceof Element &&
|
|
6801
|
+
event.target.closest("fig-input-number, fig-menu")
|
|
6802
|
+
) {
|
|
6803
|
+
if (
|
|
6804
|
+
this.#suppressNumberClick &&
|
|
6805
|
+
event.target.closest("fig-input-number")
|
|
6806
|
+
) {
|
|
6807
|
+
event.preventDefault();
|
|
6808
|
+
event.stopImmediatePropagation();
|
|
6809
|
+
this.#suppressNumberClick = false;
|
|
6810
|
+
}
|
|
6811
|
+
return;
|
|
6812
|
+
}
|
|
6813
|
+
if (
|
|
6814
|
+
!(event.target instanceof Element) ||
|
|
6815
|
+
!event.target.closest("fig-input-wheel")
|
|
6816
|
+
) {
|
|
6817
|
+
this.#wheel?.focus();
|
|
6818
|
+
}
|
|
6819
|
+
}
|
|
6820
|
+
|
|
6821
|
+
get value() {
|
|
6822
|
+
return this.getAttribute("value") ?? this.#wheel?.value ?? "0";
|
|
6823
|
+
}
|
|
6824
|
+
|
|
6825
|
+
set value(nextValue) {
|
|
6826
|
+
const parsed = Number(nextValue);
|
|
6827
|
+
this.#setSynchronizedValue(Number.isFinite(parsed) ? parsed : 0);
|
|
6828
|
+
}
|
|
6829
|
+
|
|
6830
|
+
get min() {
|
|
6831
|
+
return this.#wheel?.min ?? null;
|
|
6832
|
+
}
|
|
6833
|
+
|
|
6834
|
+
set min(nextValue) {
|
|
6835
|
+
if (nextValue === null || nextValue === undefined || nextValue === "") {
|
|
6836
|
+
this.removeAttribute("min");
|
|
6837
|
+
} else {
|
|
6838
|
+
const parsed = Number(nextValue);
|
|
6839
|
+
if (Number.isFinite(parsed)) this.setAttribute("min", String(parsed));
|
|
6840
|
+
else this.removeAttribute("min");
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
|
|
6844
|
+
get max() {
|
|
6845
|
+
return this.#wheel?.max ?? null;
|
|
6846
|
+
}
|
|
6847
|
+
|
|
6848
|
+
set max(nextValue) {
|
|
6849
|
+
if (nextValue === null || nextValue === undefined || nextValue === "") {
|
|
6850
|
+
this.removeAttribute("max");
|
|
6851
|
+
} else {
|
|
6852
|
+
const parsed = Number(nextValue);
|
|
6853
|
+
if (Number.isFinite(parsed)) this.setAttribute("max", String(parsed));
|
|
6854
|
+
else this.removeAttribute("max");
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
|
|
6574
6858
|
get defaultValue() {
|
|
6575
6859
|
return this.getAttribute("default") ?? this.#initialValue ?? "0";
|
|
6576
6860
|
}
|
|
@@ -6581,8 +6865,9 @@ class PropskitWheel extends HTMLElement {
|
|
|
6581
6865
|
|
|
6582
6866
|
resetToDefault() {
|
|
6583
6867
|
const parsed = Number(this.defaultValue);
|
|
6584
|
-
const value =
|
|
6585
|
-
|
|
6868
|
+
const value = this.#setSynchronizedValue(
|
|
6869
|
+
Number.isFinite(parsed) ? parsed : 0,
|
|
6870
|
+
);
|
|
6586
6871
|
figLabEmitPropskitReset(this, value);
|
|
6587
6872
|
}
|
|
6588
6873
|
|
|
@@ -9756,6 +10041,7 @@ class FigReorder extends HTMLElement {
|
|
|
9756
10041
|
"fig-input-gradient",
|
|
9757
10042
|
"fig-easing-curve",
|
|
9758
10043
|
"fig-input-angle",
|
|
10044
|
+
"fig-input-wheel",
|
|
9759
10045
|
"fig-input-joystick",
|
|
9760
10046
|
"fig-canvas-control",
|
|
9761
10047
|
"propskit-color-point",
|