@rogieking/figui3 1.3.2 → 1.3.3
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/example.html +10 -1
- package/fig.css +54 -16
- package/fig.js +316 -25
- package/package.json +1 -1
package/example.html
CHANGED
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
<h2>UI3 Components</h2>
|
|
24
24
|
</fig-header>
|
|
25
25
|
<fig-content>
|
|
26
|
+
<fig-input-angle text="true"
|
|
27
|
+
value="0"
|
|
28
|
+
onInput="console.log(event.target.value)"></fig-input-angle>
|
|
29
|
+
<br /><br />
|
|
30
|
+
<fig-input-joystick></fig-input-joystick>
|
|
31
|
+
<br /><br />
|
|
26
32
|
<fig-input-joystick text="true"
|
|
27
33
|
value="0,0"
|
|
28
34
|
onInput="console.log(event.target.value)"></fig-input-joystick>
|
|
@@ -445,8 +451,11 @@
|
|
|
445
451
|
</fig-header>
|
|
446
452
|
<fig-field>
|
|
447
453
|
<label>Switches</label>
|
|
448
|
-
<fig-switch
|
|
454
|
+
<fig-switch checked="true"
|
|
455
|
+
onInput="console.log(event.target.checked)"
|
|
449
456
|
label="On"></fig-switch>
|
|
457
|
+
<fig-switch checked="false"
|
|
458
|
+
label="Off"></fig-switch>
|
|
450
459
|
<fig-switch indeterminate="true"
|
|
451
460
|
label="Indeterminate"></fig-switch>
|
|
452
461
|
<fig-switch disabled
|
package/fig.css
CHANGED
|
@@ -2263,18 +2263,6 @@ fig-segmented-control {
|
|
|
2263
2263
|
}
|
|
2264
2264
|
}
|
|
2265
2265
|
|
|
2266
|
-
/* Utilities */
|
|
2267
|
-
|
|
2268
|
-
@keyframes fig-spinner-spin {
|
|
2269
|
-
from {
|
|
2270
|
-
transform: rotate(0deg);
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
to {
|
|
2274
|
-
transform: rotate(360deg);
|
|
2275
|
-
}
|
|
2276
|
-
}
|
|
2277
|
-
|
|
2278
2266
|
fig-input-joystick {
|
|
2279
2267
|
--size: 1.5rem;
|
|
2280
2268
|
display: inline-flex;
|
|
@@ -2296,10 +2284,10 @@ fig-input-joystick {
|
|
|
2296
2284
|
width: var(--size);
|
|
2297
2285
|
height: var(--size);
|
|
2298
2286
|
flex-shrink: 0;
|
|
2299
|
-
&.dragging
|
|
2300
|
-
&:hover {
|
|
2287
|
+
&.dragging {
|
|
2301
2288
|
cursor: grab;
|
|
2302
2289
|
--size: 3rem;
|
|
2290
|
+
z-index: 2;
|
|
2303
2291
|
}
|
|
2304
2292
|
}
|
|
2305
2293
|
.fig-input-joystick-plane > * {
|
|
@@ -2335,8 +2323,7 @@ fig-input-joystick {
|
|
|
2335
2323
|
pointer-events: none;
|
|
2336
2324
|
}
|
|
2337
2325
|
}
|
|
2338
|
-
.fig-input-joystick-plane.dragging .fig-input-joystick-guides
|
|
2339
|
-
.fig-input-joystick-plane:hover .fig-input-joystick-guides {
|
|
2326
|
+
.fig-input-joystick-plane.dragging .fig-input-joystick-guides {
|
|
2340
2327
|
background: linear-gradient(
|
|
2341
2328
|
45deg,
|
|
2342
2329
|
transparent calc(50% - 0.5px),
|
|
@@ -2364,3 +2351,54 @@ fig-input-joystick {
|
|
|
2364
2351
|
transform: translate(-50%, -50%);
|
|
2365
2352
|
}
|
|
2366
2353
|
}
|
|
2354
|
+
|
|
2355
|
+
fig-input-angle {
|
|
2356
|
+
--size: 1.5rem;
|
|
2357
|
+
display: inline-flex;
|
|
2358
|
+
gap: var(--spacer-2);
|
|
2359
|
+
|
|
2360
|
+
.fig-input-angle-plane {
|
|
2361
|
+
display: inline-grid;
|
|
2362
|
+
place-items: center;
|
|
2363
|
+
width: var(--size);
|
|
2364
|
+
height: var(--size);
|
|
2365
|
+
aspect-ratio: 1/1;
|
|
2366
|
+
flex-shrink: 0;
|
|
2367
|
+
background-color: var(--figma-color-bg-secondary);
|
|
2368
|
+
border-radius: 100%;
|
|
2369
|
+
box-shadow: inset 0 0 0 1px var(--figma-color-border);
|
|
2370
|
+
&.dragging {
|
|
2371
|
+
cursor: grab;
|
|
2372
|
+
--size: 3rem;
|
|
2373
|
+
z-index: 2;
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
.fig-input-angle-handle {
|
|
2377
|
+
display: inline-grid;
|
|
2378
|
+
place-items: center;
|
|
2379
|
+
grid-area: 1/1;
|
|
2380
|
+
width: calc(0.5rem + 2px);
|
|
2381
|
+
height: calc(0.5rem + 2px);
|
|
2382
|
+
&:before {
|
|
2383
|
+
content: "";
|
|
2384
|
+
display: block;
|
|
2385
|
+
width: 0.5rem;
|
|
2386
|
+
height: 0.5rem;
|
|
2387
|
+
background: var(--figma-color-icon-onbrand);
|
|
2388
|
+
box-shadow: var(--handle-shadow);
|
|
2389
|
+
border-radius: 50%;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
/* Utilities */
|
|
2395
|
+
|
|
2396
|
+
@keyframes fig-spinner-spin {
|
|
2397
|
+
from {
|
|
2398
|
+
transform: rotate(0deg);
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
to {
|
|
2402
|
+
transform: rotate(360deg);
|
|
2403
|
+
}
|
|
2404
|
+
}
|
package/fig.js
CHANGED
|
@@ -1671,6 +1671,7 @@ class FigImage extends HTMLElement {
|
|
|
1671
1671
|
this.innerHTML = this.#getInnerHTML();
|
|
1672
1672
|
this.#updateRefs();
|
|
1673
1673
|
}
|
|
1674
|
+
|
|
1674
1675
|
#updateRefs() {
|
|
1675
1676
|
requestAnimationFrame(() => {
|
|
1676
1677
|
this.chit = this.querySelector("fig-chit");
|
|
@@ -1712,6 +1713,13 @@ class FigImage extends HTMLElement {
|
|
|
1712
1713
|
}
|
|
1713
1714
|
window.customElements.define("fig-image", FigImage);
|
|
1714
1715
|
|
|
1716
|
+
/**
|
|
1717
|
+
* A custom joystick input element.
|
|
1718
|
+
* @attr {string} value - The current position of the joystick (e.g., "0.5,0.5").
|
|
1719
|
+
* @attr {number} precision - The number of decimal places for the output.
|
|
1720
|
+
* @attr {number} transform - A scaling factor for the output.
|
|
1721
|
+
* @attr {boolean} text - Whether to display text inputs for X and Y values.
|
|
1722
|
+
*/
|
|
1715
1723
|
class FigInputJoystick extends HTMLElement {
|
|
1716
1724
|
constructor() {
|
|
1717
1725
|
super();
|
|
@@ -1720,6 +1728,10 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1720
1728
|
this.value = [0.5, 0.5];
|
|
1721
1729
|
this.isDragging = false;
|
|
1722
1730
|
this.isShiftHeld = false;
|
|
1731
|
+
this.plane = null;
|
|
1732
|
+
this.cursor = null;
|
|
1733
|
+
this.xInput = null;
|
|
1734
|
+
this.yInput = null;
|
|
1723
1735
|
|
|
1724
1736
|
// Initialize position
|
|
1725
1737
|
requestAnimationFrame(() => {
|
|
@@ -1734,12 +1746,21 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1734
1746
|
this.#setupListeners();
|
|
1735
1747
|
|
|
1736
1748
|
this.#syncHandlePosition();
|
|
1737
|
-
if (this.text) {
|
|
1738
|
-
this.xInput.
|
|
1739
|
-
|
|
1749
|
+
if (this.text && this.xInput && this.yInput) {
|
|
1750
|
+
this.xInput.setAttribute(
|
|
1751
|
+
"value",
|
|
1752
|
+
this.position.x.toFixed(this.precision)
|
|
1753
|
+
);
|
|
1754
|
+
this.yInput.setAttribute(
|
|
1755
|
+
"value",
|
|
1756
|
+
this.position.y.toFixed(this.precision)
|
|
1757
|
+
);
|
|
1740
1758
|
}
|
|
1741
1759
|
});
|
|
1742
1760
|
}
|
|
1761
|
+
disconnectedCallback() {
|
|
1762
|
+
this.#cleanupListeners();
|
|
1763
|
+
}
|
|
1743
1764
|
|
|
1744
1765
|
#render() {
|
|
1745
1766
|
this.innerHTML = this.#getInnerHTML();
|
|
@@ -1780,23 +1801,32 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1780
1801
|
#setupListeners() {
|
|
1781
1802
|
this.plane = this.querySelector(".fig-input-joystick-plane");
|
|
1782
1803
|
this.cursor = this.querySelector(".fig-input-joystick-handle");
|
|
1783
|
-
if (this.text) {
|
|
1784
|
-
this.xInput = this.querySelector("fig-input-text[name='x']");
|
|
1785
|
-
this.yInput = this.querySelector("fig-input-text[name='y']");
|
|
1786
|
-
}
|
|
1787
|
-
|
|
1788
1804
|
this.plane.addEventListener("mousedown", this.#handleMouseDown.bind(this));
|
|
1805
|
+
this.plane.addEventListener(
|
|
1806
|
+
"touchstart",
|
|
1807
|
+
this.#handleTouchStart.bind(this)
|
|
1808
|
+
);
|
|
1789
1809
|
window.addEventListener("keydown", this.#handleKeyDown.bind(this));
|
|
1790
1810
|
window.addEventListener("keyup", this.#handleKeyUp.bind(this));
|
|
1811
|
+
if (this.text && this.xInput && this.yInput) {
|
|
1812
|
+
this.xInput.addEventListener("input", this.#handleXInput.bind(this));
|
|
1813
|
+
this.yInput.addEventListener("input", this.#handleYInput.bind(this));
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1791
1816
|
|
|
1792
|
-
|
|
1793
|
-
this.
|
|
1817
|
+
#cleanupListeners() {
|
|
1818
|
+
this.plane.removeEventListener("mousedown", this.#handleMouseDown);
|
|
1819
|
+
window.removeEventListener("keydown", this.#handleKeyDown);
|
|
1820
|
+
window.removeEventListener("keyup", this.#handleKeyUp);
|
|
1821
|
+
if (this.text && this.xInput && this.yInput) {
|
|
1822
|
+
this.xInput.removeEventListener("input", this.#handleXInput);
|
|
1823
|
+
this.yInput.removeEventListener("input", this.#handleYInput);
|
|
1824
|
+
}
|
|
1794
1825
|
}
|
|
1795
1826
|
|
|
1796
1827
|
#handleXInput(e) {
|
|
1797
1828
|
e.stopPropagation();
|
|
1798
1829
|
this.position.x = Number(e.target.value);
|
|
1799
|
-
this.value = [this.position.x, this.position.y];
|
|
1800
1830
|
this.#syncHandlePosition();
|
|
1801
1831
|
this.#emitInputEvent();
|
|
1802
1832
|
this.#emitChangeEvent();
|
|
@@ -1805,7 +1835,6 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1805
1835
|
#handleYInput(e) {
|
|
1806
1836
|
e.stopPropagation();
|
|
1807
1837
|
this.position.y = Number(e.target.value);
|
|
1808
|
-
this.value = [this.position.x, this.position.y];
|
|
1809
1838
|
this.#syncHandlePosition();
|
|
1810
1839
|
this.#emitInputEvent();
|
|
1811
1840
|
this.#emitChangeEvent();
|
|
@@ -1837,17 +1866,17 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1837
1866
|
|
|
1838
1867
|
const snapped = this.#snapToDiagonal(x, y);
|
|
1839
1868
|
this.position = snapped;
|
|
1840
|
-
this.value = [snapped.x, snapped.y];
|
|
1841
1869
|
|
|
1842
1870
|
this.cursor.style.left = `${snapped.x * 100}%`;
|
|
1843
|
-
this.cursor.style.top = `${
|
|
1844
|
-
if (this.text) {
|
|
1871
|
+
this.cursor.style.top = `${snapped.y * 100}%`; // Invert Y for display
|
|
1872
|
+
if (this.text && this.xInput && this.yInput) {
|
|
1845
1873
|
this.xInput.setAttribute("value", snapped.x.toFixed(3));
|
|
1846
1874
|
this.yInput.setAttribute("value", snapped.y.toFixed(3));
|
|
1847
1875
|
}
|
|
1848
1876
|
|
|
1849
1877
|
this.#emitInputEvent();
|
|
1850
1878
|
}
|
|
1879
|
+
|
|
1851
1880
|
#emitInputEvent() {
|
|
1852
1881
|
this.dispatchEvent(
|
|
1853
1882
|
new CustomEvent("input", {
|
|
@@ -1875,12 +1904,13 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1875
1904
|
|
|
1876
1905
|
#handleMouseDown(e) {
|
|
1877
1906
|
this.isDragging = true;
|
|
1878
|
-
|
|
1907
|
+
|
|
1879
1908
|
this.#updatePosition(e);
|
|
1880
1909
|
|
|
1881
1910
|
this.plane.style.cursor = "grabbing";
|
|
1882
1911
|
|
|
1883
1912
|
const handleMouseMove = (e) => {
|
|
1913
|
+
this.plane.classList.add("dragging");
|
|
1884
1914
|
if (this.isDragging) this.#updatePosition(e);
|
|
1885
1915
|
};
|
|
1886
1916
|
|
|
@@ -1897,6 +1927,26 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1897
1927
|
window.addEventListener("mouseup", handleMouseUp);
|
|
1898
1928
|
}
|
|
1899
1929
|
|
|
1930
|
+
#handleTouchStart(e) {
|
|
1931
|
+
e.preventDefault();
|
|
1932
|
+
this.isDragging = true;
|
|
1933
|
+
this.#updatePosition(e.touches[0]);
|
|
1934
|
+
|
|
1935
|
+
const handleTouchMove = (e) => {
|
|
1936
|
+
if (this.isDragging) this.#updatePosition(e.touches[0]);
|
|
1937
|
+
};
|
|
1938
|
+
|
|
1939
|
+
const handleTouchEnd = () => {
|
|
1940
|
+
this.isDragging = false;
|
|
1941
|
+
window.removeEventListener("touchmove", handleTouchMove);
|
|
1942
|
+
window.removeEventListener("touchend", handleTouchEnd);
|
|
1943
|
+
this.#emitChangeEvent();
|
|
1944
|
+
};
|
|
1945
|
+
|
|
1946
|
+
window.addEventListener("touchmove", handleTouchMove);
|
|
1947
|
+
window.addEventListener("touchend", handleTouchEnd);
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1900
1950
|
#handleKeyDown(e) {
|
|
1901
1951
|
if (e.key === "Shift") this.isShiftHeld = true;
|
|
1902
1952
|
}
|
|
@@ -1907,25 +1957,266 @@ class FigInputJoystick extends HTMLElement {
|
|
|
1907
1957
|
static get observedAttributes() {
|
|
1908
1958
|
return ["value", "precision", "transform", "text"];
|
|
1909
1959
|
}
|
|
1960
|
+
get value() {
|
|
1961
|
+
return [this.position.x, this.position.y];
|
|
1962
|
+
}
|
|
1963
|
+
set value(value) {
|
|
1964
|
+
let v = value.toString().split(",").map(Number);
|
|
1965
|
+
this.position = { x: v[0], y: v[1] };
|
|
1966
|
+
this.#syncHandlePosition();
|
|
1967
|
+
}
|
|
1910
1968
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
1911
1969
|
if (name === "value") {
|
|
1912
|
-
this.value = newValue
|
|
1913
|
-
this.position = { x: this.value[0], y: this.value[1] };
|
|
1914
|
-
this.#syncHandlePosition();
|
|
1970
|
+
this.value = newValue;
|
|
1915
1971
|
}
|
|
1916
1972
|
if (name === "precision") {
|
|
1917
|
-
this.precision = newValue;
|
|
1918
|
-
this.precision = parseInt(this.precision);
|
|
1973
|
+
this.precision = parseInt(newValue);
|
|
1919
1974
|
}
|
|
1920
1975
|
if (name === "transform") {
|
|
1921
|
-
this.transform = newValue;
|
|
1922
|
-
this.transform = Number(this.transform);
|
|
1976
|
+
this.transform = Number(newValue);
|
|
1923
1977
|
}
|
|
1924
|
-
if (name === "text") {
|
|
1978
|
+
if (name === "text" && newValue !== oldValue) {
|
|
1925
1979
|
this.text = newValue.toLowerCase() === "true";
|
|
1926
|
-
this
|
|
1980
|
+
this.#render();
|
|
1927
1981
|
}
|
|
1928
1982
|
}
|
|
1929
1983
|
}
|
|
1930
1984
|
|
|
1931
1985
|
customElements.define("fig-input-joystick", FigInputJoystick);
|
|
1986
|
+
|
|
1987
|
+
/**
|
|
1988
|
+
* A custom angle chooser input element.
|
|
1989
|
+
* @attr {number} value - The current angle of the handle in degrees.
|
|
1990
|
+
* @attr {number} precision - The number of decimal places for the output.
|
|
1991
|
+
* @attr {boolean} text - Whether to display a text input for the angle value.
|
|
1992
|
+
*/
|
|
1993
|
+
class FigInputAngle extends HTMLElement {
|
|
1994
|
+
constructor() {
|
|
1995
|
+
super();
|
|
1996
|
+
|
|
1997
|
+
this.angle = 0; // Angle in degrees
|
|
1998
|
+
this.isDragging = false;
|
|
1999
|
+
this.isShiftHeld = false;
|
|
2000
|
+
this.handle = null;
|
|
2001
|
+
this.angleInput = null;
|
|
2002
|
+
this.plane = null;
|
|
2003
|
+
|
|
2004
|
+
// Initialize position
|
|
2005
|
+
requestAnimationFrame(() => {
|
|
2006
|
+
this.precision = this.getAttribute("precision") || 1;
|
|
2007
|
+
this.precision = parseInt(this.precision);
|
|
2008
|
+
this.text = this.getAttribute("text") === "true";
|
|
2009
|
+
|
|
2010
|
+
this.#render();
|
|
2011
|
+
|
|
2012
|
+
this.#setupListeners();
|
|
2013
|
+
|
|
2014
|
+
this.#syncHandlePosition();
|
|
2015
|
+
if (this.text && this.angleInput) {
|
|
2016
|
+
this.angleInput.setAttribute(
|
|
2017
|
+
"value",
|
|
2018
|
+
this.angle.toFixed(this.precision)
|
|
2019
|
+
);
|
|
2020
|
+
}
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
disconnectedCallback() {
|
|
2025
|
+
this.#cleanupListeners();
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
#render() {
|
|
2029
|
+
this.innerHTML = this.#getInnerHTML();
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
#getInnerHTML() {
|
|
2033
|
+
return `
|
|
2034
|
+
<div class="fig-input-angle-plane">
|
|
2035
|
+
<div class="fig-input-angle-handle"></div>
|
|
2036
|
+
</div>
|
|
2037
|
+
${
|
|
2038
|
+
this.text
|
|
2039
|
+
? `<fig-input-text
|
|
2040
|
+
type="number"
|
|
2041
|
+
name="angle"
|
|
2042
|
+
step="0.1"
|
|
2043
|
+
value="${this.angle}"
|
|
2044
|
+
min="0"
|
|
2045
|
+
max="360">
|
|
2046
|
+
<span slot="append">°</span>
|
|
2047
|
+
</fig-input-text>`
|
|
2048
|
+
: ""
|
|
2049
|
+
}
|
|
2050
|
+
`;
|
|
2051
|
+
}
|
|
2052
|
+
|
|
2053
|
+
#setupListeners() {
|
|
2054
|
+
this.handle = this.querySelector(".fig-input-angle-handle");
|
|
2055
|
+
this.plane = this.querySelector(".fig-input-angle-plane");
|
|
2056
|
+
this.angleInput = this.querySelector("fig-input-text[name='angle']");
|
|
2057
|
+
this.plane.addEventListener("mousedown", this.#handleMouseDown.bind(this));
|
|
2058
|
+
this.plane.addEventListener(
|
|
2059
|
+
"touchstart",
|
|
2060
|
+
this.#handleTouchStart.bind(this)
|
|
2061
|
+
);
|
|
2062
|
+
window.addEventListener("keydown", this.#handleKeyDown.bind(this));
|
|
2063
|
+
window.addEventListener("keyup", this.#handleKeyUp.bind(this));
|
|
2064
|
+
if (this.text && this.angleInput) {
|
|
2065
|
+
this.angleInput = this.querySelector("fig-input-text");
|
|
2066
|
+
this.angleInput.addEventListener(
|
|
2067
|
+
"input",
|
|
2068
|
+
this.#handleAngleInput.bind(this)
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
#cleanupListeners() {
|
|
2074
|
+
this.plane.removeEventListener("mousedown", this.#handleMouseDown);
|
|
2075
|
+
this.plane.removeEventListener("touchstart", this.#handleTouchStart);
|
|
2076
|
+
window.removeEventListener("keydown", this.#handleKeyDown);
|
|
2077
|
+
window.removeEventListener("keyup", this.#handleKeyUp);
|
|
2078
|
+
if (this.text && this.angleInput) {
|
|
2079
|
+
this.angleInput.removeEventListener("input", this.#handleAngleInput);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
#handleAngleInput(e) {
|
|
2084
|
+
e.stopPropagation();
|
|
2085
|
+
this.angle = Number(e.target.value);
|
|
2086
|
+
this.#syncHandlePosition();
|
|
2087
|
+
this.#emitInputEvent();
|
|
2088
|
+
this.#emitChangeEvent();
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
#snapToIncrement(angle) {
|
|
2092
|
+
if (!this.isShiftHeld) return angle;
|
|
2093
|
+
const increment = 45;
|
|
2094
|
+
return Math.round(angle / increment) * increment;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
#updateAngle(e) {
|
|
2098
|
+
const rect = this.plane.getBoundingClientRect();
|
|
2099
|
+
const centerX = rect.left + rect.width / 2;
|
|
2100
|
+
const centerY = rect.top + rect.height / 2;
|
|
2101
|
+
const deltaX = e.clientX - centerX;
|
|
2102
|
+
const deltaY = e.clientY - centerY;
|
|
2103
|
+
let angle = ((Math.atan2(deltaY, deltaX) * 180) / Math.PI + 360) % 360;
|
|
2104
|
+
|
|
2105
|
+
angle = this.#snapToIncrement(angle);
|
|
2106
|
+
this.angle = angle;
|
|
2107
|
+
|
|
2108
|
+
this.#syncHandlePosition();
|
|
2109
|
+
if (this.text && this.angleInput) {
|
|
2110
|
+
this.angleInput.setAttribute("value", this.angle.toFixed(this.precision));
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
this.#emitInputEvent();
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
#emitInputEvent() {
|
|
2117
|
+
this.dispatchEvent(
|
|
2118
|
+
new CustomEvent("input", {
|
|
2119
|
+
bubbles: true,
|
|
2120
|
+
cancelable: true,
|
|
2121
|
+
})
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
#emitChangeEvent() {
|
|
2126
|
+
this.dispatchEvent(
|
|
2127
|
+
new CustomEvent("change", {
|
|
2128
|
+
bubbles: true,
|
|
2129
|
+
cancelable: true,
|
|
2130
|
+
})
|
|
2131
|
+
);
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
#syncHandlePosition() {
|
|
2135
|
+
if (this.handle) {
|
|
2136
|
+
const radians = (this.angle * Math.PI) / 180;
|
|
2137
|
+
const radius = this.plane.offsetWidth / 2 - this.handle.offsetWidth / 2;
|
|
2138
|
+
const x = Math.cos(radians) * radius;
|
|
2139
|
+
const y = Math.sin(radians) * radius;
|
|
2140
|
+
this.handle.style.transform = `translate(${x}px, ${y}px)`;
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
#handleMouseDown(e) {
|
|
2145
|
+
this.isDragging = true;
|
|
2146
|
+
this.#updateAngle(e);
|
|
2147
|
+
|
|
2148
|
+
const handleMouseMove = (e) => {
|
|
2149
|
+
if (this.isDragging) this.#updateAngle(e);
|
|
2150
|
+
};
|
|
2151
|
+
|
|
2152
|
+
const handleMouseUp = () => {
|
|
2153
|
+
this.isDragging = false;
|
|
2154
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
2155
|
+
window.removeEventListener("mouseup", handleMouseUp);
|
|
2156
|
+
this.#emitChangeEvent();
|
|
2157
|
+
};
|
|
2158
|
+
|
|
2159
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
2160
|
+
window.addEventListener("mouseup", handleMouseUp);
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
#handleTouchStart(e) {
|
|
2164
|
+
e.preventDefault();
|
|
2165
|
+
this.isDragging = true;
|
|
2166
|
+
this.#updateAngle(e.touches[0]);
|
|
2167
|
+
|
|
2168
|
+
const handleTouchMove = (e) => {
|
|
2169
|
+
if (this.isDragging) this.#updateAngle(e.touches[0]);
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
const handleTouchEnd = () => {
|
|
2173
|
+
this.isDragging = false;
|
|
2174
|
+
window.removeEventListener("touchmove", handleTouchMove);
|
|
2175
|
+
window.removeEventListener("touchend", handleTouchEnd);
|
|
2176
|
+
this.#emitChangeEvent();
|
|
2177
|
+
};
|
|
2178
|
+
|
|
2179
|
+
window.addEventListener("touchmove", handleTouchMove);
|
|
2180
|
+
window.addEventListener("touchend", handleTouchEnd);
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
#handleKeyDown(e) {
|
|
2184
|
+
if (e.key === "Shift") this.isShiftHeld = true;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
#handleKeyUp(e) {
|
|
2188
|
+
if (e.key === "Shift") this.isShiftHeld = false;
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
static get observedAttributes() {
|
|
2192
|
+
return ["value", "precision", "text"];
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
get value() {
|
|
2196
|
+
return this.angle;
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
set value(value) {
|
|
2200
|
+
if (isNaN(value)) {
|
|
2201
|
+
console.error("Invalid value: must be a number.");
|
|
2202
|
+
return;
|
|
2203
|
+
}
|
|
2204
|
+
this.angle = value;
|
|
2205
|
+
this.#syncHandlePosition();
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
2209
|
+
if (name === "value") {
|
|
2210
|
+
this.value = Number(newValue);
|
|
2211
|
+
}
|
|
2212
|
+
if (name === "precision") {
|
|
2213
|
+
this.precision = parseInt(newValue);
|
|
2214
|
+
}
|
|
2215
|
+
if (name === "text" && newValue !== oldValue) {
|
|
2216
|
+
this.text = newValue.toLowerCase() === "true";
|
|
2217
|
+
this.#render();
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
customElements.define("fig-input-angle", FigInputAngle);
|