@rogieking/figui3 1.3.2 → 1.3.4

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.
Files changed (4) hide show
  1. package/example.html +10 -1
  2. package/fig.css +70 -22
  3. package/fig.js +350 -26
  4. 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.adjacent, event.target.opposite)"></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 on="true"
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
@@ -415,7 +415,7 @@
415
415
  --body-medium-fontWeight: 450;
416
416
  --handle-shadow: 0px 0 0 0.75px rgba(0, 0, 0, 0.1),
417
417
  0px 1px 3px 0px rgba(0, 0, 0, 0.05), 0px 3px 8px 0px rgba(0, 0, 0, 0.05),
418
- 0px 0px 0.5px 0px rgba(0, 0, 0, 0.1);
418
+ 0px 0px 0.5px 0px rgba(0, 0, 0, 0.1), var(--figma-elevation-200);
419
419
 
420
420
  --popover-min-width: 15rem;
421
421
  --figma-color-bg-ghost-hover: rgba(0, 0, 0, 0.05);
@@ -2263,22 +2263,11 @@ 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;
2281
2269
  gap: var(--spacer-2);
2270
+ user-select: none;
2282
2271
  .fig-input-joystick-plane-container {
2283
2272
  display: flex;
2284
2273
  width: 1.5rem;
@@ -2288,6 +2277,9 @@ fig-input-joystick {
2288
2277
  flex-grow: 0;
2289
2278
  align-items: center;
2290
2279
  justify-content: center;
2280
+ &:focus {
2281
+ outline: 0;
2282
+ }
2291
2283
  }
2292
2284
  .fig-input-joystick-plane {
2293
2285
  display: inline-grid;
@@ -2296,10 +2288,10 @@ fig-input-joystick {
2296
2288
  width: var(--size);
2297
2289
  height: var(--size);
2298
2290
  flex-shrink: 0;
2299
- &.dragging,
2300
- &:hover {
2291
+ &.dragging {
2301
2292
  cursor: grab;
2302
2293
  --size: 3rem;
2294
+ z-index: 2;
2303
2295
  }
2304
2296
  }
2305
2297
  .fig-input-joystick-plane > * {
@@ -2309,7 +2301,7 @@ fig-input-joystick {
2309
2301
  position: absolute;
2310
2302
  width: var(--size);
2311
2303
  height: var(--size);
2312
- border: 1px solid var(--figma-color-border);
2304
+ box-shadow: inset 0 0 0 1px var(--figma-color-border);
2313
2305
  border-radius: var(--radius-medium);
2314
2306
  overflow: hidden;
2315
2307
  background: var(--figma-color-bg-secondary);
@@ -2319,8 +2311,8 @@ fig-input-joystick {
2319
2311
  position: absolute;
2320
2312
  height: 0;
2321
2313
  border-left: 1px solid var(--figma-color-border);
2322
- height: 100%;
2323
- top: 0;
2314
+ height: calc(100% - 2px);
2315
+ top: 1px;
2324
2316
  left: calc(50% - 0.5px);
2325
2317
  pointer-events: none;
2326
2318
  }
@@ -2329,14 +2321,13 @@ fig-input-joystick {
2329
2321
  position: absolute;
2330
2322
  height: 0;
2331
2323
  border-top: 1px solid var(--figma-color-border);
2332
- width: 100%;
2324
+ width: calc(100% - 2px);
2333
2325
  top: calc(50% - 0.5px);
2334
- left: 0;
2326
+ left: 1px;
2335
2327
  pointer-events: none;
2336
2328
  }
2337
2329
  }
2338
- .fig-input-joystick-plane.dragging .fig-input-joystick-guides,
2339
- .fig-input-joystick-plane:hover .fig-input-joystick-guides {
2330
+ .fig-input-joystick-plane.dragging .fig-input-joystick-guides {
2340
2331
  background: linear-gradient(
2341
2332
  45deg,
2342
2333
  transparent calc(50% - 0.5px),
@@ -2352,7 +2343,12 @@ fig-input-joystick {
2352
2343
  transparent calc(50% + 0.5px)
2353
2344
  ),
2354
2345
  var(--figma-color-bg-secondary);
2346
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
2347
+ }
2348
+ .fig-input-joystick-plane-container:focus .fig-input-joystick-guides {
2349
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
2355
2350
  }
2351
+
2356
2352
  .fig-input-joystick-handle {
2357
2353
  position: absolute;
2358
2354
  z-index: 1;
@@ -2364,3 +2360,55 @@ fig-input-joystick {
2364
2360
  transform: translate(-50%, -50%);
2365
2361
  }
2366
2362
  }
2363
+
2364
+ fig-input-angle {
2365
+ --size: 1.5rem;
2366
+ display: inline-flex;
2367
+ gap: var(--spacer-2);
2368
+ user-select: none;
2369
+
2370
+ .fig-input-angle-plane {
2371
+ display: inline-grid;
2372
+ place-items: center;
2373
+ width: var(--size);
2374
+ height: var(--size);
2375
+ aspect-ratio: 1/1;
2376
+ flex-shrink: 0;
2377
+ background-color: var(--figma-color-bg-secondary);
2378
+ border-radius: 100%;
2379
+ box-shadow: inset 0 0 0 1px var(--figma-color-border);
2380
+ &:focus,
2381
+ &.dragging {
2382
+ outline: 0;
2383
+ box-shadow: inset 0 0 0 1px var(--figma-color-border-selected);
2384
+ }
2385
+ }
2386
+ .fig-input-angle-handle {
2387
+ display: inline-grid;
2388
+ place-items: center;
2389
+ grid-area: 1/1;
2390
+ width: calc(0.5rem + 2px);
2391
+ height: calc(0.5rem + 2px);
2392
+ &:before {
2393
+ content: "";
2394
+ display: block;
2395
+ width: 0.5rem;
2396
+ height: 0.5rem;
2397
+ background: var(--figma-color-icon-onbrand);
2398
+ box-shadow: var(--handle-shadow);
2399
+ border-radius: 50%;
2400
+ }
2401
+ }
2402
+ }
2403
+
2404
+ /* Utilities */
2405
+
2406
+ @keyframes fig-spinner-spin {
2407
+ from {
2408
+ transform: rotate(0deg);
2409
+ }
2410
+
2411
+ to {
2412
+ transform: rotate(360deg);
2413
+ }
2414
+ }
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,19 +1746,28 @@ class FigInputJoystick extends HTMLElement {
1734
1746
  this.#setupListeners();
1735
1747
 
1736
1748
  this.#syncHandlePosition();
1737
- if (this.text) {
1738
- this.xInput.value = this.position.x.toFixed(this.precision);
1739
- this.yInput.value = this.position.y.toFixed(this.precision);
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();
1746
1767
  }
1747
1768
  #getInnerHTML() {
1748
1769
  return `
1749
- <div class="fig-input-joystick-plane-container">
1770
+ <div class="fig-input-joystick-plane-container" tabindex="0">
1750
1771
  <div class="fig-input-joystick-plane">
1751
1772
  <div class="fig-input-joystick-guides"></div>
1752
1773
  <div class="fig-input-joystick-handle"></div>
@@ -1780,23 +1801,34 @@ 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
-
1804
+ this.xInput = this.querySelector("fig-input-text[name='x']");
1805
+ this.yInput = this.querySelector("fig-input-text[name='y']");
1788
1806
  this.plane.addEventListener("mousedown", this.#handleMouseDown.bind(this));
1807
+ this.plane.addEventListener(
1808
+ "touchstart",
1809
+ this.#handleTouchStart.bind(this)
1810
+ );
1789
1811
  window.addEventListener("keydown", this.#handleKeyDown.bind(this));
1790
1812
  window.addEventListener("keyup", this.#handleKeyUp.bind(this));
1813
+ if (this.text && this.xInput && this.yInput) {
1814
+ this.xInput.addEventListener("input", this.#handleXInput.bind(this));
1815
+ this.yInput.addEventListener("input", this.#handleYInput.bind(this));
1816
+ }
1817
+ }
1791
1818
 
1792
- this.xInput.addEventListener("input", this.#handleXInput.bind(this));
1793
- this.yInput.addEventListener("input", this.#handleYInput.bind(this));
1819
+ #cleanupListeners() {
1820
+ this.plane.removeEventListener("mousedown", this.#handleMouseDown);
1821
+ window.removeEventListener("keydown", this.#handleKeyDown);
1822
+ window.removeEventListener("keyup", this.#handleKeyUp);
1823
+ if (this.text && this.xInput && this.yInput) {
1824
+ this.xInput.removeEventListener("input", this.#handleXInput);
1825
+ this.yInput.removeEventListener("input", this.#handleYInput);
1826
+ }
1794
1827
  }
1795
1828
 
1796
1829
  #handleXInput(e) {
1797
1830
  e.stopPropagation();
1798
1831
  this.position.x = Number(e.target.value);
1799
- this.value = [this.position.x, this.position.y];
1800
1832
  this.#syncHandlePosition();
1801
1833
  this.#emitInputEvent();
1802
1834
  this.#emitChangeEvent();
@@ -1805,7 +1837,6 @@ class FigInputJoystick extends HTMLElement {
1805
1837
  #handleYInput(e) {
1806
1838
  e.stopPropagation();
1807
1839
  this.position.y = Number(e.target.value);
1808
- this.value = [this.position.x, this.position.y];
1809
1840
  this.#syncHandlePosition();
1810
1841
  this.#emitInputEvent();
1811
1842
  this.#emitChangeEvent();
@@ -1837,17 +1868,17 @@ class FigInputJoystick extends HTMLElement {
1837
1868
 
1838
1869
  const snapped = this.#snapToDiagonal(x, y);
1839
1870
  this.position = snapped;
1840
- this.value = [snapped.x, snapped.y];
1841
1871
 
1842
1872
  this.cursor.style.left = `${snapped.x * 100}%`;
1843
- this.cursor.style.top = `${(1 - snapped.y) * 100}%`; // Invert Y for display
1844
- if (this.text) {
1873
+ this.cursor.style.top = `${snapped.y * 100}%`; // Invert Y for display
1874
+ if (this.text && this.xInput && this.yInput) {
1845
1875
  this.xInput.setAttribute("value", snapped.x.toFixed(3));
1846
1876
  this.yInput.setAttribute("value", snapped.y.toFixed(3));
1847
1877
  }
1848
1878
 
1849
1879
  this.#emitInputEvent();
1850
1880
  }
1881
+
1851
1882
  #emitInputEvent() {
1852
1883
  this.dispatchEvent(
1853
1884
  new CustomEvent("input", {
@@ -1875,12 +1906,13 @@ class FigInputJoystick extends HTMLElement {
1875
1906
 
1876
1907
  #handleMouseDown(e) {
1877
1908
  this.isDragging = true;
1878
- this.plane.classList.add("dragging");
1909
+
1879
1910
  this.#updatePosition(e);
1880
1911
 
1881
1912
  this.plane.style.cursor = "grabbing";
1882
1913
 
1883
1914
  const handleMouseMove = (e) => {
1915
+ this.plane.classList.add("dragging");
1884
1916
  if (this.isDragging) this.#updatePosition(e);
1885
1917
  };
1886
1918
 
@@ -1897,6 +1929,27 @@ class FigInputJoystick extends HTMLElement {
1897
1929
  window.addEventListener("mouseup", handleMouseUp);
1898
1930
  }
1899
1931
 
1932
+ #handleTouchStart(e) {
1933
+ e.preventDefault();
1934
+ this.isDragging = true;
1935
+ this.#updatePosition(e.touches[0]);
1936
+
1937
+ const handleTouchMove = (e) => {
1938
+ if (this.isDragging) this.#updatePosition(e.touches[0]);
1939
+ };
1940
+
1941
+ const handleTouchEnd = () => {
1942
+ this.isDragging = false;
1943
+ this.plane.classList.remove("dragging");
1944
+ window.removeEventListener("touchmove", handleTouchMove);
1945
+ window.removeEventListener("touchend", handleTouchEnd);
1946
+ this.#emitChangeEvent();
1947
+ };
1948
+
1949
+ window.addEventListener("touchmove", handleTouchMove);
1950
+ window.addEventListener("touchend", handleTouchEnd);
1951
+ }
1952
+
1900
1953
  #handleKeyDown(e) {
1901
1954
  if (e.key === "Shift") this.isShiftHeld = true;
1902
1955
  }
@@ -1907,25 +1960,296 @@ class FigInputJoystick extends HTMLElement {
1907
1960
  static get observedAttributes() {
1908
1961
  return ["value", "precision", "transform", "text"];
1909
1962
  }
1963
+ get value() {
1964
+ return [this.position.x, this.position.y];
1965
+ }
1966
+ set value(value) {
1967
+ let v = value.toString().split(",").map(Number);
1968
+ this.position = { x: v[0], y: v[1] };
1969
+ this.#syncHandlePosition();
1970
+ }
1910
1971
  attributeChangedCallback(name, oldValue, newValue) {
1911
1972
  if (name === "value") {
1912
- this.value = newValue.split(",").map(Number);
1913
- this.position = { x: this.value[0], y: this.value[1] };
1914
- this.#syncHandlePosition();
1973
+ this.value = newValue;
1915
1974
  }
1916
1975
  if (name === "precision") {
1917
- this.precision = newValue;
1918
- this.precision = parseInt(this.precision);
1976
+ this.precision = parseInt(newValue);
1919
1977
  }
1920
1978
  if (name === "transform") {
1921
- this.transform = newValue;
1922
- this.transform = Number(this.transform);
1979
+ this.transform = Number(newValue);
1923
1980
  }
1924
- if (name === "text") {
1981
+ if (name === "text" && newValue !== oldValue) {
1925
1982
  this.text = newValue.toLowerCase() === "true";
1926
- this.innerHTML = this.#getInnerHTML();
1983
+ this.#render();
1927
1984
  }
1928
1985
  }
1929
1986
  }
1930
1987
 
1931
1988
  customElements.define("fig-input-joystick", FigInputJoystick);
1989
+
1990
+ /**
1991
+ * A custom angle chooser input element.
1992
+ * @attr {number} value - The current angle of the handle in degrees.
1993
+ * @attr {number} precision - The number of decimal places for the output.
1994
+ * @attr {boolean} text - Whether to display a text input for the angle value.
1995
+ * @attr {number} adjacent - The adjacent value of the angle.
1996
+ * @attr {number} opposite - The opposite value of the angle.
1997
+ */
1998
+ class FigInputAngle extends HTMLElement {
1999
+ // Declare private fields first
2000
+ #adjacent;
2001
+ #opposite;
2002
+
2003
+ constructor() {
2004
+ super();
2005
+
2006
+ this.angle = 0; // Angle in degrees
2007
+ this.#adjacent = 1;
2008
+ this.#opposite = 0;
2009
+ this.isDragging = false;
2010
+ this.isShiftHeld = false;
2011
+ this.handle = null;
2012
+ this.angleInput = null;
2013
+ this.plane = null;
2014
+
2015
+ // Initialize position
2016
+ requestAnimationFrame(() => {
2017
+ this.precision = this.getAttribute("precision") || 1;
2018
+ this.precision = parseInt(this.precision);
2019
+ this.text = this.getAttribute("text") === "true";
2020
+
2021
+ this.#render();
2022
+
2023
+ this.#setupListeners();
2024
+
2025
+ this.#syncHandlePosition();
2026
+ if (this.text && this.angleInput) {
2027
+ this.angleInput.setAttribute(
2028
+ "value",
2029
+ this.angle.toFixed(this.precision)
2030
+ );
2031
+ }
2032
+ });
2033
+ }
2034
+
2035
+ disconnectedCallback() {
2036
+ this.#cleanupListeners();
2037
+ }
2038
+
2039
+ #render() {
2040
+ this.innerHTML = this.#getInnerHTML();
2041
+ }
2042
+
2043
+ #getInnerHTML() {
2044
+ return `
2045
+ <div class="fig-input-angle-plane" tabindex="0">
2046
+ <div class="fig-input-angle-handle"></div>
2047
+ </div>
2048
+ ${
2049
+ this.text
2050
+ ? `<fig-input-text
2051
+ type="number"
2052
+ name="angle"
2053
+ step="0.1"
2054
+ value="${this.angle}"
2055
+ min="0"
2056
+ max="360">
2057
+ <span slot="append">°</span>
2058
+ </fig-input-text>`
2059
+ : ""
2060
+ }
2061
+ `;
2062
+ }
2063
+
2064
+ #setupListeners() {
2065
+ this.handle = this.querySelector(".fig-input-angle-handle");
2066
+ this.plane = this.querySelector(".fig-input-angle-plane");
2067
+ this.angleInput = this.querySelector("fig-input-text[name='angle']");
2068
+ this.plane.addEventListener("mousedown", this.#handleMouseDown.bind(this));
2069
+ this.plane.addEventListener(
2070
+ "touchstart",
2071
+ this.#handleTouchStart.bind(this)
2072
+ );
2073
+ window.addEventListener("keydown", this.#handleKeyDown.bind(this));
2074
+ window.addEventListener("keyup", this.#handleKeyUp.bind(this));
2075
+ if (this.text && this.angleInput) {
2076
+ this.angleInput = this.querySelector("fig-input-text");
2077
+ this.angleInput.addEventListener(
2078
+ "input",
2079
+ this.#handleAngleInput.bind(this)
2080
+ );
2081
+ }
2082
+ }
2083
+
2084
+ #cleanupListeners() {
2085
+ this.plane.removeEventListener("mousedown", this.#handleMouseDown);
2086
+ this.plane.removeEventListener("touchstart", this.#handleTouchStart);
2087
+ window.removeEventListener("keydown", this.#handleKeyDown);
2088
+ window.removeEventListener("keyup", this.#handleKeyUp);
2089
+ if (this.text && this.angleInput) {
2090
+ this.angleInput.removeEventListener("input", this.#handleAngleInput);
2091
+ }
2092
+ }
2093
+
2094
+ #handleAngleInput(e) {
2095
+ e.stopPropagation();
2096
+ this.angle = Number(e.target.value);
2097
+ this.#calculateAdjacentAndOpposite();
2098
+ this.#syncHandlePosition();
2099
+ this.#emitInputEvent();
2100
+ this.#emitChangeEvent();
2101
+ }
2102
+
2103
+ #calculateAdjacentAndOpposite() {
2104
+ const radians = (this.angle * Math.PI) / 180;
2105
+ this.#adjacent = Math.cos(radians);
2106
+ this.#opposite = Math.sin(radians);
2107
+ }
2108
+
2109
+ #snapToIncrement(angle) {
2110
+ if (!this.isShiftHeld) return angle;
2111
+ const increment = 45;
2112
+ return Math.round(angle / increment) * increment;
2113
+ }
2114
+
2115
+ #updateAngle(e) {
2116
+ const rect = this.plane.getBoundingClientRect();
2117
+ const centerX = rect.left + rect.width / 2;
2118
+ const centerY = rect.top + rect.height / 2;
2119
+ const deltaX = e.clientX - centerX;
2120
+ const deltaY = e.clientY - centerY;
2121
+ let angle = ((Math.atan2(deltaY, deltaX) * 180) / Math.PI + 360) % 360;
2122
+
2123
+ angle = this.#snapToIncrement(angle);
2124
+ this.angle = angle;
2125
+
2126
+ this.#calculateAdjacentAndOpposite();
2127
+
2128
+ this.#syncHandlePosition();
2129
+ if (this.text && this.angleInput) {
2130
+ this.angleInput.setAttribute("value", this.angle.toFixed(this.precision));
2131
+ }
2132
+
2133
+ this.#emitInputEvent();
2134
+ }
2135
+
2136
+ #emitInputEvent() {
2137
+ this.dispatchEvent(
2138
+ new CustomEvent("input", {
2139
+ bubbles: true,
2140
+ cancelable: true,
2141
+ })
2142
+ );
2143
+ }
2144
+
2145
+ #emitChangeEvent() {
2146
+ this.dispatchEvent(
2147
+ new CustomEvent("change", {
2148
+ bubbles: true,
2149
+ cancelable: true,
2150
+ })
2151
+ );
2152
+ }
2153
+
2154
+ #syncHandlePosition() {
2155
+ if (this.handle) {
2156
+ const radians = (this.angle * Math.PI) / 180;
2157
+ const radius = this.plane.offsetWidth / 2 - this.handle.offsetWidth / 2;
2158
+ const x = Math.cos(radians) * radius;
2159
+ const y = Math.sin(radians) * radius;
2160
+ this.handle.style.transform = `translate(${x}px, ${y}px)`;
2161
+ }
2162
+ }
2163
+
2164
+ #handleMouseDown(e) {
2165
+ this.isDragging = true;
2166
+ this.#updateAngle(e);
2167
+
2168
+ const handleMouseMove = (e) => {
2169
+ this.plane.classList.add("dragging");
2170
+ if (this.isDragging) this.#updateAngle(e);
2171
+ };
2172
+
2173
+ const handleMouseUp = () => {
2174
+ this.isDragging = false;
2175
+ this.plane.classList.remove("dragging");
2176
+ window.removeEventListener("mousemove", handleMouseMove);
2177
+ window.removeEventListener("mouseup", handleMouseUp);
2178
+ this.#emitChangeEvent();
2179
+ };
2180
+
2181
+ window.addEventListener("mousemove", handleMouseMove);
2182
+ window.addEventListener("mouseup", handleMouseUp);
2183
+ }
2184
+
2185
+ #handleTouchStart(e) {
2186
+ e.preventDefault();
2187
+ this.isDragging = true;
2188
+ this.#updateAngle(e.touches[0]);
2189
+
2190
+ const handleTouchMove = (e) => {
2191
+ this.plane.classList.add("dragging");
2192
+ if (this.isDragging) this.#updateAngle(e.touches[0]);
2193
+ };
2194
+
2195
+ const handleTouchEnd = () => {
2196
+ this.isDragging = false;
2197
+ this.plane.classList.remove("dragging");
2198
+ window.removeEventListener("touchmove", handleTouchMove);
2199
+ window.removeEventListener("touchend", handleTouchEnd);
2200
+ this.#emitChangeEvent();
2201
+ };
2202
+
2203
+ window.addEventListener("touchmove", handleTouchMove);
2204
+ window.addEventListener("touchend", handleTouchEnd);
2205
+ }
2206
+
2207
+ #handleKeyDown(e) {
2208
+ if (e.key === "Shift") this.isShiftHeld = true;
2209
+ }
2210
+
2211
+ #handleKeyUp(e) {
2212
+ if (e.key === "Shift") this.isShiftHeld = false;
2213
+ }
2214
+
2215
+ static get observedAttributes() {
2216
+ return ["value", "precision", "text"];
2217
+ }
2218
+
2219
+ get value() {
2220
+ return this.angle;
2221
+ }
2222
+
2223
+ get adjacent() {
2224
+ return this.#adjacent;
2225
+ }
2226
+
2227
+ get opposite() {
2228
+ return this.#opposite;
2229
+ }
2230
+
2231
+ set value(value) {
2232
+ if (isNaN(value)) {
2233
+ console.error("Invalid value: must be a number.");
2234
+ return;
2235
+ }
2236
+ this.angle = value;
2237
+ this.#calculateAdjacentAndOpposite();
2238
+ this.#syncHandlePosition();
2239
+ }
2240
+
2241
+ attributeChangedCallback(name, oldValue, newValue) {
2242
+ if (name === "value") {
2243
+ this.value = Number(newValue);
2244
+ }
2245
+ if (name === "precision") {
2246
+ this.precision = parseInt(newValue);
2247
+ }
2248
+ if (name === "text" && newValue !== oldValue) {
2249
+ this.text = newValue.toLowerCase() === "true";
2250
+ this.#render();
2251
+ }
2252
+ }
2253
+ }
2254
+
2255
+ customElements.define("fig-input-angle", FigInputAngle);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rogieking/figui3",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "devDependencies": {