@ixfx/components 0.2.3 → 0.2.5
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/LICENSE +1 -1
- package/bundle/chunk-pbuEa-1d.js +13 -0
- package/bundle/index.d.ts +4702 -569
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +34929 -2800
- package/bundle/index.js.map +1 -1
- package/bundle/style.css +133 -0
- package/dist/ac-text.d.ts +97 -0
- package/dist/ac-text.d.ts.map +1 -0
- package/dist/ac-text.js +484 -0
- package/dist/ac-text.js.map +1 -0
- package/dist/button-DgKUzE5o.js +121 -0
- package/dist/button-DgKUzE5o.js.map +1 -0
- package/dist/button.d.ts +21 -0
- package/dist/button.d.ts.map +1 -0
- package/dist/button.js +3 -0
- package/dist/checkbox.d.ts +34 -0
- package/dist/checkbox.d.ts.map +1 -0
- package/dist/checkbox.js +251 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-pbuEa-1d.js +13 -0
- package/dist/colour-C3MQIjFJ-BJV-QC-3.js +4138 -0
- package/dist/colour-C3MQIjFJ-BJV-QC-3.js.map +1 -0
- package/dist/colour-picker-Bw-AZoWx.js +922 -0
- package/dist/colour-picker-Bw-AZoWx.js.map +1 -0
- package/dist/colour-picker.d.ts +2 -0
- package/dist/colour-picker.js +2 -0
- package/dist/crumbs.d.ts +92 -0
- package/dist/crumbs.d.ts.map +1 -0
- package/dist/crumbs.js +789 -0
- package/dist/crumbs.js.map +1 -0
- package/dist/data-display.d.ts +24 -12
- package/dist/data-display.d.ts.map +1 -1
- package/dist/data-display.js +96 -105
- package/dist/data-display.js.map +1 -1
- package/dist/decorate-BZbkqIhA.js +9 -0
- package/dist/defaults-FEZaGiYZ.js +38 -0
- package/dist/defaults-FEZaGiYZ.js.map +1 -0
- package/dist/dist-By5URG0Y.js +1290 -0
- package/dist/dist-By5URG0Y.js.map +1 -0
- package/dist/dist-D7kJgnSE.js +1039 -0
- package/dist/dist-D7kJgnSE.js.map +1 -0
- package/dist/editable-label.d.ts +71 -0
- package/dist/editable-label.d.ts.map +1 -0
- package/dist/editable-label.js +279 -0
- package/dist/editable-label.js.map +1 -0
- package/dist/hex-editor-Gib1Grg2.d.ts +131 -0
- package/dist/hex-editor-Gib1Grg2.d.ts.map +1 -0
- package/dist/hex-editor-Wd6ZtZA2.js +1147 -0
- package/dist/hex-editor-Wd6ZtZA2.js.map +1 -0
- package/dist/hex.d.ts +2 -0
- package/dist/hex.js +2 -0
- package/dist/highlight-CAjwQ4GE.js +50 -0
- package/dist/highlight-CAjwQ4GE.js.map +1 -0
- package/dist/icon-BR5aTIiP.js +100 -0
- package/dist/icon-BR5aTIiP.js.map +1 -0
- package/dist/icon-DQKdfR7U.d.ts +36 -0
- package/dist/icon-DQKdfR7U.d.ts.map +1 -0
- package/dist/icons.d.ts +3 -0
- package/dist/icons.js +9 -0
- package/dist/icons.js.map +1 -0
- package/dist/incr-search-BjCNClnC.js +311 -0
- package/dist/incr-search-BjCNClnC.js.map +1 -0
- package/dist/incr-search.d.ts +2 -0
- package/dist/incr-search.js +3 -0
- package/dist/index-B1hNR7Z9.d.ts +36 -0
- package/dist/index-B1hNR7Z9.d.ts.map +1 -0
- package/dist/index-C5dK8RZa.d.ts +23 -0
- package/dist/index-C5dK8RZa.d.ts.map +1 -0
- package/dist/index-C9iBN908.d.ts +160 -0
- package/dist/index-C9iBN908.d.ts.map +1 -0
- package/dist/index-CPVcTTXo.d.ts +396 -0
- package/dist/index-CPVcTTXo.d.ts.map +1 -0
- package/dist/index-CQxanqXF.d.ts +183 -0
- package/dist/index-CQxanqXF.d.ts.map +1 -0
- package/dist/index-CpbBI3n7.d.ts +1239 -0
- package/dist/index-CpbBI3n7.d.ts.map +1 -0
- package/dist/index.d.ts +422 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5729 -14
- package/dist/index.js.map +1 -1
- package/dist/interaction-CQDQJf2Q.js +1 -0
- package/dist/keyboard-De_vOHLg.js +20 -0
- package/dist/keyboard-De_vOHLg.js.map +1 -0
- package/dist/labelled-input-base-DS6-6C0r.js +155 -0
- package/dist/labelled-input-base-DS6-6C0r.js.map +1 -0
- package/dist/labelled-input-base-DnRh4reU.d.ts +43 -0
- package/dist/labelled-input-base-DnRh4reU.d.ts.map +1 -0
- package/dist/labelled-radial-input.d.ts +34 -0
- package/dist/labelled-radial-input.d.ts.map +1 -0
- package/dist/labelled-radial-input.js +188 -0
- package/dist/labelled-radial-input.js.map +1 -0
- package/dist/labelled-range-input.d.ts +2 -0
- package/dist/labelled-range-input.js +132 -0
- package/dist/labelled-range-input.js.map +1 -0
- package/dist/led.d.ts +25 -0
- package/dist/led.d.ts.map +1 -0
- package/dist/led.js +92 -0
- package/dist/led.js.map +1 -0
- package/dist/menu-BV6UFx_z.js +813 -0
- package/dist/menu-BV6UFx_z.js.map +1 -0
- package/dist/menu-item-Cikacp4F.d.ts +128 -0
- package/dist/menu-item-Cikacp4F.d.ts.map +1 -0
- package/dist/menu-item-DEzL_Yjk.js +766 -0
- package/dist/menu-item-DEzL_Yjk.js.map +1 -0
- package/dist/menu.d.ts +3 -0
- package/dist/menu.js +3 -0
- package/dist/miller.d.ts +324 -0
- package/dist/miller.d.ts.map +1 -0
- package/dist/miller.js +1343 -0
- package/dist/miller.js.map +1 -0
- package/dist/narrowed-text.d.ts +72 -0
- package/dist/narrowed-text.d.ts.map +1 -0
- package/dist/narrowed-text.js +571 -0
- package/dist/narrowed-text.js.map +1 -0
- package/dist/panel.d.ts +43 -0
- package/dist/panel.d.ts.map +1 -0
- package/dist/panel.js +408 -0
- package/dist/panel.js.map +1 -0
- package/dist/plots.d.ts +2 -0
- package/dist/plots.js +2 -0
- package/dist/polar-pad.d.ts +67 -0
- package/dist/polar-pad.d.ts.map +1 -0
- package/dist/polar-pad.js +537 -0
- package/dist/polar-pad.js.map +1 -0
- package/dist/popup-Ddx9LCzY.js +24 -0
- package/dist/popup-Ddx9LCzY.js.map +1 -0
- package/dist/prominence-CreDBdCs.js +98 -0
- package/dist/prominence-CreDBdCs.js.map +1 -0
- package/dist/radial-input-CNJ8asY2.js +849 -0
- package/dist/radial-input-CNJ8asY2.js.map +1 -0
- package/dist/radial-input-xSTd4kEz.d.ts +70 -0
- package/dist/radial-input-xSTd4kEz.d.ts.map +1 -0
- package/dist/radial-input.d.ts +2 -0
- package/dist/radial-input.js +2 -0
- package/dist/range-input.d.ts +43 -0
- package/dist/range-input.d.ts.map +1 -0
- package/dist/range-input.js +459 -0
- package/dist/range-input.js.map +1 -0
- package/dist/range.d.ts +28 -0
- package/dist/range.d.ts.map +1 -0
- package/dist/range.js +136 -0
- package/dist/range.js.map +1 -0
- package/dist/registry-CZEB1YI9.js +21 -0
- package/dist/registry-CZEB1YI9.js.map +1 -0
- package/dist/selecthorizontal.d.ts +13 -8
- package/dist/selecthorizontal.d.ts.map +1 -1
- package/dist/selecthorizontal.js +21 -25
- package/dist/selecthorizontal.js.map +1 -1
- package/dist/snap-container.d.ts +50 -0
- package/dist/snap-container.d.ts.map +1 -0
- package/dist/snap-container.js +297 -0
- package/dist/snap-container.js.map +1 -0
- package/dist/split-layout.d.ts +56 -0
- package/dist/split-layout.d.ts.map +1 -0
- package/dist/split-layout.js +545 -0
- package/dist/split-layout.js.map +1 -0
- package/dist/style.css +133 -0
- package/dist/swipe.d.ts +48 -0
- package/dist/swipe.d.ts.map +1 -0
- package/dist/swipe.js +204 -0
- package/dist/swipe.js.map +1 -0
- package/dist/tab-list-CFF7uSYH.d.ts +66 -0
- package/dist/tab-list-CFF7uSYH.d.ts.map +1 -0
- package/dist/tabs.d.ts +2 -0
- package/dist/tabs.js +203 -0
- package/dist/tabs.js.map +1 -0
- package/dist/tickled-controller-Cq1Va0rR.d.ts +218 -0
- package/dist/tickled-controller-Cq1Va0rR.d.ts.map +1 -0
- package/dist/tickled-styles-Bg3QbcrD.js +327 -0
- package/dist/tickled-styles-Bg3QbcrD.js.map +1 -0
- package/dist/timeline-DBWJsSjd.js +1748 -0
- package/dist/timeline-DBWJsSjd.js.map +1 -0
- package/dist/timeline.d.ts +2 -0
- package/dist/timeline.js +2 -0
- package/dist/tooltip-DMxmBNky.js +104 -0
- package/dist/tooltip-DMxmBNky.js.map +1 -0
- package/dist/tooltip-kfUBWYVB.d.ts +26 -0
- package/dist/tooltip-kfUBWYVB.d.ts.map +1 -0
- package/dist/tree-component-CQpoPo4s.d.ts +326 -0
- package/dist/tree-component-CQpoPo4s.d.ts.map +1 -0
- package/dist/tree-data-model-DGvRVOFY.js +190 -0
- package/dist/tree-data-model-DGvRVOFY.js.map +1 -0
- package/dist/tree.d.ts +100 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +1144 -0
- package/dist/tree.js.map +1 -0
- package/dist/types-BKaqnpwx.d.ts +8 -0
- package/dist/types-BKaqnpwx.d.ts.map +1 -0
- package/dist/xy-axis-BANbgrI5.js +6243 -0
- package/dist/xy-axis-BANbgrI5.js.map +1 -0
- package/dist/xy-axis-CIFok7MF.d.ts +141 -0
- package/dist/xy-axis-CIFok7MF.d.ts.map +1 -0
- package/dist/xy-pad.d.ts +81 -0
- package/dist/xy-pad.d.ts.map +1 -0
- package/dist/xy-pad.js +435 -0
- package/dist/xy-pad.js.map +1 -0
- package/package.json +48 -39
- package/README.md +0 -14
- package/dist/charts/frequency-histogram-plot.d.ts +0 -33
- package/dist/charts/frequency-histogram-plot.d.ts.map +0 -1
- package/dist/charts/frequency-histogram-plot.js +0 -54
- package/dist/charts/frequency-histogram-plot.js.map +0 -1
- package/dist/charts/histogram-vis.d.ts +0 -57
- package/dist/charts/histogram-vis.d.ts.map +0 -1
- package/dist/charts/histogram-vis.js +0 -222
- package/dist/charts/histogram-vis.js.map +0 -1
- package/dist/charts/plot.d.ts +0 -199
- package/dist/charts/plot.d.ts.map +0 -1
- package/dist/charts/plot.js +0 -914
- package/dist/charts/plot.js.map +0 -1
- package/dist/crumb-nav.d.ts +0 -41
- package/dist/crumb-nav.d.ts.map +0 -1
- package/dist/crumb-nav.js +0 -198
- package/dist/crumb-nav.js.map +0 -1
- package/dist/crumb-navigation.d.ts +0 -30
- package/dist/crumb-navigation.d.ts.map +0 -1
- package/dist/crumb-navigation.js +0 -307
- package/dist/crumb-navigation.js.map +0 -1
- package/dist/dial.d.ts +0 -89
- package/dist/dial.d.ts.map +0 -1
- package/dist/dial.js +0 -506
- package/dist/dial.js.map +0 -1
- package/dist/my-element.d.ts +0 -14
- package/dist/my-element.d.ts.map +0 -1
- package/dist/my-element.js +0 -44
- package/dist/my-element.js.map +0 -1
- package/dist/split-layout/split-layout.d.ts +0 -35
- package/dist/split-layout/split-layout.d.ts.map +0 -1
- package/dist/split-layout/split-layout.js +0 -220
- package/dist/split-layout/split-layout.js.map +0 -1
- package/dist/svg-edit-label.d.ts +0 -2
- package/dist/svg-edit-label.d.ts.map +0 -1
- package/dist/svg-edit-label.js +0 -110
- package/dist/svg-edit-label.js.map +0 -1
- package/dist/tabs/tab-layout-item.d.ts +0 -10
- package/dist/tabs/tab-layout-item.d.ts.map +0 -1
- package/dist/tabs/tab-layout-item.js +0 -20
- package/dist/tabs/tab-layout-item.js.map +0 -1
- package/dist/tabs/tab-layout.d.ts +0 -10
- package/dist/tabs/tab-layout.d.ts.map +0 -1
- package/dist/tabs/tab-layout.js +0 -25
- package/dist/tabs/tab-layout.js.map +0 -1
- package/dist/tabs/tab-list-item.d.ts +0 -18
- package/dist/tabs/tab-list-item.d.ts.map +0 -1
- package/dist/tabs/tab-list-item.js +0 -63
- package/dist/tabs/tab-list-item.js.map +0 -1
- package/dist/tabs/tab-list.d.ts +0 -21
- package/dist/tabs/tab-list.d.ts.map +0 -1
- package/dist/tabs/tab-list.js +0 -148
- package/dist/tabs/tab-list.js.map +0 -1
- package/dist/tabs/tab-panel.d.ts +0 -11
- package/dist/tabs/tab-panel.d.ts.map +0 -1
- package/dist/tabs/tab-panel.js +0 -30
- package/dist/tabs/tab-panel.js.map +0 -1
- package/dist/tabs/tab-panels.d.ts +0 -30
- package/dist/tabs/tab-panels.d.ts.map +0 -1
- package/dist/tabs/tab-panels.js +0 -80
- package/dist/tabs/tab-panels.js.map +0 -1
- package/dist/util/circle-arc.d.ts +0 -34
- package/dist/util/circle-arc.d.ts.map +0 -1
- package/dist/util/circle-arc.js +0 -77
- package/dist/util/circle-arc.js.map +0 -1
- package/dist/util/compare.d.ts +0 -53
- package/dist/util/compare.d.ts.map +0 -1
- package/dist/util/compare.js +0 -91
- package/dist/util/compare.js.map +0 -1
- package/dist/util/content-editable.d.ts +0 -2
- package/dist/util/content-editable.d.ts.map +0 -1
- package/dist/util/content-editable.js +0 -13
- package/dist/util/content-editable.js.map +0 -1
- package/dist/util/drag-controller.d.ts +0 -13
- package/dist/util/drag-controller.d.ts.map +0 -1
- package/dist/util/drag-controller.js +0 -21
- package/dist/util/drag-controller.js.map +0 -1
- package/dist/util/key-value.d.ts +0 -5
- package/dist/util/key-value.d.ts.map +0 -1
- package/dist/util/key-value.js +0 -30
- package/dist/util/key-value.js.map +0 -1
- package/dist/util/primitive-types.d.ts +0 -6
- package/dist/util/primitive-types.d.ts.map +0 -1
- package/dist/util/primitive-types.js +0 -2
- package/dist/util/primitive-types.js.map +0 -1
- package/dist/util/svg-editable-text.d.ts +0 -22
- package/dist/util/svg-editable-text.d.ts.map +0 -1
- package/dist/util/svg-editable-text.js +0 -121
- package/dist/util/svg-editable-text.js.map +0 -1
- package/dist/util/time.d.ts +0 -2
- package/dist/util/time.d.ts.map +0 -1
- package/dist/util/time.js +0 -2
- package/dist/util/time.js.map +0 -1
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import { t as __decorate } from "./decorate-BZbkqIhA.js";
|
|
2
|
+
import { LitElement, css, html, svg } from "lit";
|
|
3
|
+
import { customElement, property } from "lit/decorators.js";
|
|
4
|
+
//#region src/polar-pad/polar-pad.ts
|
|
5
|
+
/**
|
|
6
|
+
* <ixfx-polar-pad> — circular pad for setting polar coordinates (angle + radius).
|
|
7
|
+
*
|
|
8
|
+
* The user clicks or drags within a circle to position a marker. The marker's
|
|
9
|
+
* position encodes an angle (degrees, 0 = right, clockwise) and a radius (0–1).
|
|
10
|
+
*
|
|
11
|
+
* Properties / attributes
|
|
12
|
+
* angle – current angle in degrees (0 = right, clockwise). Default: 0
|
|
13
|
+
* radius – current radius 0–1 where 1 = edge. Default: 0.5
|
|
14
|
+
* rings – number of concentric rings to draw (0 = none). Default: 0
|
|
15
|
+
* rays – number of evenly-spaced radial spokes to draw (0 = none). Default: 0
|
|
16
|
+
* show-ray – draw a line from the origin to the marker
|
|
17
|
+
* show-origin – draw a dot at the centre
|
|
18
|
+
* hide-cursor – hide cursor during drag and hover (default: false)
|
|
19
|
+
* snap-value – when set, marker snaps to nearest ring/spoke depending on what's displayed
|
|
20
|
+
* disabled – disable all interaction (default: false)
|
|
21
|
+
*
|
|
22
|
+
* Customisable CSS variables:
|
|
23
|
+
*
|
|
24
|
+
* Pad background
|
|
25
|
+
* --pad-background – CSS `background` of the circular pad. Accepts any CSS background
|
|
26
|
+
* value: solid colour, conic-gradient(), radial-gradient(), etc.
|
|
27
|
+
* Dynamic CSS vars like --angle-deg / --radius-pct are available
|
|
28
|
+
* so the gradient can track the current marker position.
|
|
29
|
+
* Default: var(--surface-4)
|
|
30
|
+
* --pad-border-color – stroke of the outer circle (default: --surface-6)
|
|
31
|
+
* --pad-border-width – thickness of outer border (default: 1px)
|
|
32
|
+
*
|
|
33
|
+
* Marker
|
|
34
|
+
* --marker-size – diameter of the draggable marker (default: 10cqb)
|
|
35
|
+
* --marker-color – fill colour of the marker (default: --accent)
|
|
36
|
+
* --marker-opacity – opacity of the marker (default: 1)
|
|
37
|
+
* --marker-stroke – stroke colour of the marker (default: none)
|
|
38
|
+
* --marker-stroke-width – stroke thickness of the marker (default: 0)
|
|
39
|
+
*
|
|
40
|
+
* Origin dot (show-origin)
|
|
41
|
+
* --origin-size – diameter of the origin dot (default: 6cqb)
|
|
42
|
+
* --origin-color – fill colour of the origin dot (default: --accent)
|
|
43
|
+
* --origin-opacity – opacity of the origin dot (default: 1)
|
|
44
|
+
*
|
|
45
|
+
* Ray line (show-ray)
|
|
46
|
+
* --ray-color – stroke colour (default: --surface-6)
|
|
47
|
+
* --ray-width – thickness (default: 2px)
|
|
48
|
+
* --ray-opacity – opacity (default: 1)
|
|
49
|
+
* --ray-dash – stroke-dasharray value e.g. "4 2" (default: none)
|
|
50
|
+
*
|
|
51
|
+
* Concentric rings (rings > 0)
|
|
52
|
+
* --ring-color – stroke colour (default: --surface-6)
|
|
53
|
+
* --ring-width – thickness (default: 1px)
|
|
54
|
+
* --ring-opacity – opacity (default: 1)
|
|
55
|
+
* --ring-dash – stroke-dasharray e.g. "4 2" (default: none)
|
|
56
|
+
*
|
|
57
|
+
* Radial spokes (rays > 0)
|
|
58
|
+
* --spoke-color – stroke colour (default: --surface-6)
|
|
59
|
+
* --spoke-width – thickness (default: 1px)
|
|
60
|
+
* --spoke-opacity – opacity (default: 1)
|
|
61
|
+
* --spoke-dash – stroke-dasharray e.g. "4 2" (default: none)
|
|
62
|
+
*
|
|
63
|
+
* CSS variables set on host for external dynamic styling:
|
|
64
|
+
* --angle-deg – current angle as unitless number in degrees
|
|
65
|
+
* --angle-rad – current angle as unitless number in radians
|
|
66
|
+
* --radius-pct – current radius as unitless number 0–100
|
|
67
|
+
*
|
|
68
|
+
* Events
|
|
69
|
+
* input – CustomEvent<PolarPadInputDetail> { angle: number (deg), radius: number (0–1) }
|
|
70
|
+
* bubbles + composed, fires continuously during drag
|
|
71
|
+
* change – CustomEvent<PolarPadInputDetail> { angle: number (deg), radius: number (0–1) }
|
|
72
|
+
* bubbles + composed, fires when drag ends
|
|
73
|
+
*/
|
|
74
|
+
const DEG_TO_RAD = Math.PI / 180;
|
|
75
|
+
const RAD_TO_DEG = 180 / Math.PI;
|
|
76
|
+
/**
|
|
77
|
+
* Convert polar (angle in radians, radius 0-1) to SVG coordinates.
|
|
78
|
+
* SVG viewBox 0 0 100 100; origin at (50,50); full radius = 50.
|
|
79
|
+
* Convention: 0 rad = right (+x), increases CLOCKWISE (+y = downward in SVG).
|
|
80
|
+
*/
|
|
81
|
+
function polarToSvg(angleRad, radius) {
|
|
82
|
+
const r = radius * 50;
|
|
83
|
+
return {
|
|
84
|
+
x: 50 + Math.cos(angleRad) * r,
|
|
85
|
+
y: 50 + Math.sin(angleRad) * r
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Convert SVG coordinates back to polar (angle in radians 0..2π, radius 0-1).
|
|
90
|
+
* SVG: Y increases downward. Convention: 0=right, CW positive.
|
|
91
|
+
*/
|
|
92
|
+
function svgToPolar(svgX, svgY) {
|
|
93
|
+
const dx = svgX - 50;
|
|
94
|
+
const dy = svgY - 50;
|
|
95
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
96
|
+
const radius = Math.min(1, dist / 50);
|
|
97
|
+
return {
|
|
98
|
+
angleRad: (Math.atan2(dy, dx) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI),
|
|
99
|
+
radius
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const clamp01 = (v) => Math.max(0, Math.min(1, v));
|
|
103
|
+
function snapAngle(angleDeg, prevAngleDeg, rays, snapEnabled) {
|
|
104
|
+
if (rays <= 0 || !snapEnabled) return angleDeg;
|
|
105
|
+
const spokeDeg = 360 / rays;
|
|
106
|
+
const normalized = (angleDeg % 360 + 360) % 360;
|
|
107
|
+
const nearest = Math.round(normalized / spokeDeg) * spokeDeg;
|
|
108
|
+
const remainder = normalized % spokeDeg;
|
|
109
|
+
if (Math.abs(remainder) < 1e-4 || Math.abs(spokeDeg - remainder) < 1e-4) {
|
|
110
|
+
let delta = angleDeg - prevAngleDeg;
|
|
111
|
+
if (delta > 180) delta -= 360;
|
|
112
|
+
if (delta < -180) delta += 360;
|
|
113
|
+
return (nearest + (delta >= 0 ? 1 : -1) * spokeDeg + 360) % 360;
|
|
114
|
+
}
|
|
115
|
+
return nearest;
|
|
116
|
+
}
|
|
117
|
+
function snapRadius(radius, prevRadius, rings, snapEnabled) {
|
|
118
|
+
if (rings <= 0 || !snapEnabled) return radius;
|
|
119
|
+
const ringStep = 1 / rings;
|
|
120
|
+
const nearest = Math.round(radius / ringStep) * ringStep;
|
|
121
|
+
const remainder = radius % ringStep;
|
|
122
|
+
if (Math.abs(remainder) < 1e-4 || Math.abs(ringStep - remainder) < 1e-4) return Math.max(0, Math.min(1, nearest + (radius >= prevRadius ? 1 : -1) * ringStep));
|
|
123
|
+
return nearest;
|
|
124
|
+
}
|
|
125
|
+
function quantiseAngle(angleDeg, stops) {
|
|
126
|
+
if (!stops || stops <= 1) return angleDeg;
|
|
127
|
+
const stepDeg = 360 / stops;
|
|
128
|
+
const normalized = (angleDeg % 360 + 360) % 360;
|
|
129
|
+
return Math.round(normalized / stepDeg) * stepDeg;
|
|
130
|
+
}
|
|
131
|
+
function quantiseRadius(radius, stops) {
|
|
132
|
+
if (!stops || stops <= 1) return radius;
|
|
133
|
+
const step = 1 / stops;
|
|
134
|
+
return Math.round(radius / step) * step;
|
|
135
|
+
}
|
|
136
|
+
let PolarPad = class PolarPad extends LitElement {
|
|
137
|
+
constructor(..._args) {
|
|
138
|
+
super(..._args);
|
|
139
|
+
this.angle = 0;
|
|
140
|
+
this.radius = .5;
|
|
141
|
+
this.rings = 0;
|
|
142
|
+
this.rays = 0;
|
|
143
|
+
this.showRay = false;
|
|
144
|
+
this.showOrigin = false;
|
|
145
|
+
this.hideCursor = false;
|
|
146
|
+
this.snapValue = false;
|
|
147
|
+
this.disabled = false;
|
|
148
|
+
this._dragging = false;
|
|
149
|
+
this._dragStartAngle = 0;
|
|
150
|
+
this._dragStartRadius = 0;
|
|
151
|
+
this._pressedKeys = /* @__PURE__ */ new Set();
|
|
152
|
+
this._prevAngle = 0;
|
|
153
|
+
this._prevRadius = 0;
|
|
154
|
+
this._onPointerDown = (e) => {
|
|
155
|
+
e.preventDefault();
|
|
156
|
+
this.renderRoot.querySelector(`svg`)?.focus();
|
|
157
|
+
const area = this.renderRoot.querySelector(`.polar-pad-area`);
|
|
158
|
+
if (area) area.setPointerCapture(e.pointerId);
|
|
159
|
+
this._dragging = true;
|
|
160
|
+
this._dragStartAngle = this.angle;
|
|
161
|
+
this._dragStartRadius = this.radius;
|
|
162
|
+
this.setAttribute(`dragging`, ``);
|
|
163
|
+
this._updateFromPointer(e);
|
|
164
|
+
globalThis.addEventListener(`pointermove`, this._onPointerMove);
|
|
165
|
+
globalThis.addEventListener(`pointerup`, this._onPointerUp);
|
|
166
|
+
};
|
|
167
|
+
this._onPointerMove = (e) => {
|
|
168
|
+
if (!this._dragging) return;
|
|
169
|
+
e.preventDefault();
|
|
170
|
+
this._updateFromPointer(e);
|
|
171
|
+
};
|
|
172
|
+
this._onPointerUp = () => {
|
|
173
|
+
const hasChanged = this.angle !== this._dragStartAngle || this.radius !== this._dragStartRadius;
|
|
174
|
+
this._dragging = false;
|
|
175
|
+
this.removeAttribute(`dragging`);
|
|
176
|
+
globalThis.removeEventListener(`pointermove`, this._onPointerMove);
|
|
177
|
+
globalThis.removeEventListener(`pointerup`, this._onPointerUp);
|
|
178
|
+
if (hasChanged) this.dispatchEvent(new CustomEvent(`change`, {
|
|
179
|
+
detail: {
|
|
180
|
+
angle: this.angle,
|
|
181
|
+
radius: this.radius
|
|
182
|
+
},
|
|
183
|
+
bubbles: true,
|
|
184
|
+
composed: true
|
|
185
|
+
}));
|
|
186
|
+
};
|
|
187
|
+
this._onKeyDown = (e) => {
|
|
188
|
+
if (this.disabled) return;
|
|
189
|
+
if ([
|
|
190
|
+
`ArrowLeft`,
|
|
191
|
+
`ArrowRight`,
|
|
192
|
+
`ArrowUp`,
|
|
193
|
+
`ArrowDown`
|
|
194
|
+
].includes(e.key)) {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
this._pressedKeys.add(e.key);
|
|
197
|
+
this._handleKeyboardMove(e.shiftKey);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
this._onKeyUp = (e) => {
|
|
201
|
+
this._pressedKeys.delete(e.key);
|
|
202
|
+
};
|
|
203
|
+
this._handleKeyboardMove = (shiftKey) => {
|
|
204
|
+
const shiftDivisor = shiftKey ? 10 : 1;
|
|
205
|
+
const effectiveStopsAngle = this.stopsAngle ?? this.stops;
|
|
206
|
+
const effectiveStopsRadius = this.stopsRadius ?? this.stops;
|
|
207
|
+
let angleStep;
|
|
208
|
+
if (effectiveStopsAngle && effectiveStopsAngle > 1) angleStep = 360 / effectiveStopsAngle;
|
|
209
|
+
else angleStep = 360 / (this.rays > 0 && this.snapValue ? this.rays : 20);
|
|
210
|
+
let radiusStep;
|
|
211
|
+
if (effectiveStopsRadius && effectiveStopsRadius > 1) radiusStep = 1 / effectiveStopsRadius;
|
|
212
|
+
else radiusStep = 1 / 20;
|
|
213
|
+
angleStep /= shiftDivisor;
|
|
214
|
+
radiusStep /= shiftDivisor;
|
|
215
|
+
this._prevAngle = this.angle;
|
|
216
|
+
this._prevRadius = this.radius;
|
|
217
|
+
let newAngle = this.angle;
|
|
218
|
+
let newRadius = this.radius;
|
|
219
|
+
if (this._pressedKeys.has(`ArrowLeft`)) newAngle -= angleStep;
|
|
220
|
+
if (this._pressedKeys.has(`ArrowRight`)) newAngle += angleStep;
|
|
221
|
+
if (this._pressedKeys.has(`ArrowUp`)) newRadius = Math.min(1, newRadius + radiusStep);
|
|
222
|
+
if (this._pressedKeys.has(`ArrowDown`)) newRadius = Math.max(0, newRadius - radiusStep);
|
|
223
|
+
newAngle = (newAngle % 360 + 360) % 360;
|
|
224
|
+
let finalAngle = snapAngle(newAngle, this._prevAngle, this.rays, this.snapValue);
|
|
225
|
+
let finalRadius = snapRadius(newRadius, this._prevRadius, this.rings, this.snapValue);
|
|
226
|
+
finalAngle = quantiseAngle(finalAngle, effectiveStopsAngle);
|
|
227
|
+
finalRadius = quantiseRadius(finalRadius, effectiveStopsRadius);
|
|
228
|
+
if (finalAngle !== this.angle || finalRadius !== this.radius) {
|
|
229
|
+
this.angle = finalAngle;
|
|
230
|
+
this.radius = finalRadius;
|
|
231
|
+
this.dispatchEvent(new CustomEvent(`input`, {
|
|
232
|
+
detail: {
|
|
233
|
+
angle: this.angle,
|
|
234
|
+
radius: this.radius
|
|
235
|
+
},
|
|
236
|
+
bubbles: true,
|
|
237
|
+
composed: true
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
this._uid = Math.random().toString(36).slice(2, 8);
|
|
242
|
+
}
|
|
243
|
+
static {
|
|
244
|
+
this.styles = css`
|
|
245
|
+
:host {
|
|
246
|
+
display: block;
|
|
247
|
+
width: 200px;
|
|
248
|
+
height: 200px;
|
|
249
|
+
touch-action: none;
|
|
250
|
+
user-select: none;
|
|
251
|
+
container-type: size;
|
|
252
|
+
|
|
253
|
+
/* Pad background */
|
|
254
|
+
--pad-background: var(--surface-4, oklch(22% 0.02 240));
|
|
255
|
+
--pad-border-color: var(--surface-6, oklch(35% 0.02 240));
|
|
256
|
+
--pad-border-width: 1px;
|
|
257
|
+
|
|
258
|
+
/* Marker */
|
|
259
|
+
--marker-size: 10cqb;
|
|
260
|
+
--marker-color: var(--accent, oklch(60% 0.15 140));
|
|
261
|
+
--marker-opacity: 1;
|
|
262
|
+
--marker-stroke: none;
|
|
263
|
+
--marker-stroke-width: 0;
|
|
264
|
+
|
|
265
|
+
/* Origin dot */
|
|
266
|
+
--origin-size: 6cqb;
|
|
267
|
+
--origin-color: var(--accent, oklch(60% 0.15 140));
|
|
268
|
+
--origin-opacity: 1;
|
|
269
|
+
|
|
270
|
+
/* Ray line */
|
|
271
|
+
--ray-color: var(--surface-6, oklch(35% 0.02 240));
|
|
272
|
+
--ray-width: 2px;
|
|
273
|
+
--ray-opacity: 1;
|
|
274
|
+
--ray-dash: none;
|
|
275
|
+
|
|
276
|
+
/* Concentric rings */
|
|
277
|
+
--ring-color: var(--surface-6, oklch(35% 0.02 240));
|
|
278
|
+
--ring-width: 1px;
|
|
279
|
+
--ring-opacity: 1;
|
|
280
|
+
--ring-dash: none;
|
|
281
|
+
|
|
282
|
+
/* Radial spokes */
|
|
283
|
+
--spoke-color: var(--surface-6, oklch(35% 0.02 240));
|
|
284
|
+
--spoke-width: 1px;
|
|
285
|
+
--spoke-opacity: 1;
|
|
286
|
+
--spoke-dash: none;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
:host([disabled]) {
|
|
290
|
+
opacity: 0.5;
|
|
291
|
+
pointer-events: none;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.polar-pad-area {
|
|
295
|
+
position: relative;
|
|
296
|
+
width: 100%;
|
|
297
|
+
height: 100%;
|
|
298
|
+
cursor: var(--cursor-display, crosshair);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
:host([dragging]) .polar-pad-area {
|
|
302
|
+
cursor: none;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
svg {
|
|
306
|
+
width: 100%;
|
|
307
|
+
height: 100%;
|
|
308
|
+
overflow: visible;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.pad-background {
|
|
312
|
+
/* Used on the foreignObject div — accepts any CSS background value */
|
|
313
|
+
width: 100%;
|
|
314
|
+
height: 100%;
|
|
315
|
+
background: var(--pad-background);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.pad-border {
|
|
319
|
+
fill: none;
|
|
320
|
+
stroke: var(--pad-border-color);
|
|
321
|
+
stroke-width: var(--pad-border-width);
|
|
322
|
+
vector-effect: non-scaling-stroke;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.ring {
|
|
326
|
+
fill: none;
|
|
327
|
+
stroke: var(--ring-color);
|
|
328
|
+
stroke-width: var(--ring-width);
|
|
329
|
+
stroke-dasharray: var(--ring-dash);
|
|
330
|
+
opacity: var(--ring-opacity);
|
|
331
|
+
vector-effect: non-scaling-stroke;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.spoke {
|
|
335
|
+
fill: none;
|
|
336
|
+
stroke: var(--spoke-color);
|
|
337
|
+
stroke-width: var(--spoke-width);
|
|
338
|
+
stroke-dasharray: var(--spoke-dash);
|
|
339
|
+
opacity: var(--spoke-opacity);
|
|
340
|
+
vector-effect: non-scaling-stroke;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.ray {
|
|
344
|
+
fill: none;
|
|
345
|
+
stroke: var(--ray-color);
|
|
346
|
+
stroke-width: var(--ray-width);
|
|
347
|
+
stroke-dasharray: var(--ray-dash);
|
|
348
|
+
opacity: var(--ray-opacity);
|
|
349
|
+
vector-effect: non-scaling-stroke;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.origin-dot {
|
|
353
|
+
fill: var(--origin-color);
|
|
354
|
+
opacity: var(--origin-opacity);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.marker {
|
|
358
|
+
fill: var(--marker-color);
|
|
359
|
+
opacity: var(--marker-opacity);
|
|
360
|
+
stroke: var(--marker-stroke);
|
|
361
|
+
stroke-width: var(--marker-stroke-width);
|
|
362
|
+
cursor: grab;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.marker:active {
|
|
366
|
+
cursor: grabbing;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
svg:focus {
|
|
370
|
+
outline: none;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
svg:focus-visible .pad-border {
|
|
374
|
+
stroke: var(--accent);
|
|
375
|
+
stroke-width: 3;
|
|
376
|
+
}
|
|
377
|
+
`;
|
|
378
|
+
}
|
|
379
|
+
_updateFromPointer(e) {
|
|
380
|
+
const area = this.renderRoot.querySelector(`.polar-pad-area`);
|
|
381
|
+
if (!area) return;
|
|
382
|
+
const rect = area.getBoundingClientRect();
|
|
383
|
+
const size = Math.min(rect.width, rect.height);
|
|
384
|
+
const { angleRad, radius } = svgToPolar((e.clientX - rect.left) / size * 100, (e.clientY - rect.top) / size * 100);
|
|
385
|
+
const newAngleDeg = angleRad * RAD_TO_DEG;
|
|
386
|
+
const newRadius = clamp01(radius);
|
|
387
|
+
this._prevAngle = this.angle;
|
|
388
|
+
this._prevRadius = this.radius;
|
|
389
|
+
const snappedAngle = snapAngle(newAngleDeg, this._prevAngle, this.rays, this.snapValue);
|
|
390
|
+
const snappedRadius = snapRadius(newRadius, this._prevRadius, this.rings, this.snapValue);
|
|
391
|
+
const effectiveStopsAngle = this.stopsAngle ?? this.stops;
|
|
392
|
+
const effectiveStopsRadius = this.stopsRadius ?? this.stops;
|
|
393
|
+
this.angle = quantiseAngle(snappedAngle, effectiveStopsAngle);
|
|
394
|
+
this.radius = quantiseRadius(snappedRadius, effectiveStopsRadius);
|
|
395
|
+
this._prevAngle = newAngleDeg;
|
|
396
|
+
this._prevRadius = newRadius;
|
|
397
|
+
this.dispatchEvent(new CustomEvent(`input`, {
|
|
398
|
+
detail: {
|
|
399
|
+
angle: this.angle,
|
|
400
|
+
radius: this.radius
|
|
401
|
+
},
|
|
402
|
+
bubbles: true,
|
|
403
|
+
composed: true
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
_setCssVars() {
|
|
407
|
+
this.style.setProperty(`--angle-deg`, `${this.angle}`);
|
|
408
|
+
this.style.setProperty(`--angle-rad`, `${this.angle * DEG_TO_RAD}`);
|
|
409
|
+
this.style.setProperty(`--radius-pct`, `${clamp01(this.radius) * 100}`);
|
|
410
|
+
}
|
|
411
|
+
updated(_changed) {
|
|
412
|
+
super.updated(_changed);
|
|
413
|
+
this._setCssVars();
|
|
414
|
+
}
|
|
415
|
+
disconnectedCallback() {
|
|
416
|
+
super.disconnectedCallback();
|
|
417
|
+
this._onPointerUp();
|
|
418
|
+
this._pressedKeys.clear();
|
|
419
|
+
}
|
|
420
|
+
_renderRings() {
|
|
421
|
+
if (this.rings <= 0) return ``;
|
|
422
|
+
const items = [];
|
|
423
|
+
for (let i = 1; i <= this.rings; i++) {
|
|
424
|
+
const r = i / this.rings * 50;
|
|
425
|
+
items.push(svg`<circle class="ring" cx="50" cy="50" r="${r}" />`);
|
|
426
|
+
}
|
|
427
|
+
return items;
|
|
428
|
+
}
|
|
429
|
+
_renderSpokes() {
|
|
430
|
+
if (this.rays <= 0) return ``;
|
|
431
|
+
const items = [];
|
|
432
|
+
for (let i = 0; i < this.rays; i++) {
|
|
433
|
+
const angleRad = i / this.rays * 2 * Math.PI;
|
|
434
|
+
const cos = Math.cos(angleRad);
|
|
435
|
+
const sin = Math.sin(angleRad);
|
|
436
|
+
const x1 = 50 + cos * 50;
|
|
437
|
+
const y1 = 50 + sin * 50;
|
|
438
|
+
const x2 = 50 - cos * 50;
|
|
439
|
+
const y2 = 50 - sin * 50;
|
|
440
|
+
items.push(svg`<line class="spoke" x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" />`);
|
|
441
|
+
}
|
|
442
|
+
return items;
|
|
443
|
+
}
|
|
444
|
+
_renderRay(markerX, markerY) {
|
|
445
|
+
if (!this.showRay) return ``;
|
|
446
|
+
return svg`<line class="ray" x1="50" y1="50" x2="${markerX}" y2="${markerY}" />`;
|
|
447
|
+
}
|
|
448
|
+
_renderOrigin() {
|
|
449
|
+
if (!this.showOrigin) return ``;
|
|
450
|
+
return svg`<circle class="origin-dot" cx="50" cy="50" r="3" style="r: calc(var(--origin-size) / 2)" />`;
|
|
451
|
+
}
|
|
452
|
+
render() {
|
|
453
|
+
const { x: markerX, y: markerY } = polarToSvg(this.angle * DEG_TO_RAD, clamp01(this.radius));
|
|
454
|
+
return html`
|
|
455
|
+
<div class="polar-pad-area"
|
|
456
|
+
@pointerdown=${this._onPointerDown}
|
|
457
|
+
@keydown=${this._onKeyDown}
|
|
458
|
+
@keyup=${this._onKeyUp}
|
|
459
|
+
@blur=${() => this._pressedKeys.clear()}>
|
|
460
|
+
<svg viewBox="0 0 100 100"
|
|
461
|
+
preserveAspectRatio="xMidYMid meet"
|
|
462
|
+
tabindex=${this.disabled ? -1 : 0}>
|
|
463
|
+
<defs>
|
|
464
|
+
<clipPath id="circle-clip-${this._uid}">
|
|
465
|
+
<circle cx="50" cy="50" r="50" />
|
|
466
|
+
</clipPath>
|
|
467
|
+
</defs>
|
|
468
|
+
|
|
469
|
+
<!-- clipped group: background + rings + spokes -->
|
|
470
|
+
<g clip-path="url(#circle-clip-${this._uid})">
|
|
471
|
+
<foreignObject x="0" y="0" width="100" height="100">
|
|
472
|
+
<div class="pad-background" xmlns="http://www.w3.org/1999/xhtml"></div>
|
|
473
|
+
</foreignObject>
|
|
474
|
+
${this._renderRings()}
|
|
475
|
+
${this._renderSpokes()}
|
|
476
|
+
</g>
|
|
477
|
+
|
|
478
|
+
<!-- border circle (on top of clip, non-scaling stroke) -->
|
|
479
|
+
<circle class="pad-border" cx="50" cy="50" r="49.75" />
|
|
480
|
+
|
|
481
|
+
<!-- ray + origin + marker -->
|
|
482
|
+
${this._renderRay(markerX, markerY)}
|
|
483
|
+
${this._renderOrigin()}
|
|
484
|
+
<circle
|
|
485
|
+
class="marker"
|
|
486
|
+
cx="${markerX}"
|
|
487
|
+
cy="${markerY}"
|
|
488
|
+
r="5"
|
|
489
|
+
style="r: calc(var(--marker-size) / 2)"
|
|
490
|
+
/>
|
|
491
|
+
</svg>
|
|
492
|
+
</div>
|
|
493
|
+
`;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
__decorate([property({ type: Number })], PolarPad.prototype, "angle", void 0);
|
|
497
|
+
__decorate([property({ type: Number })], PolarPad.prototype, "radius", void 0);
|
|
498
|
+
__decorate([property({ type: Number })], PolarPad.prototype, "rings", void 0);
|
|
499
|
+
__decorate([property({ type: Number })], PolarPad.prototype, "rays", void 0);
|
|
500
|
+
__decorate([property({
|
|
501
|
+
type: Boolean,
|
|
502
|
+
reflect: true,
|
|
503
|
+
attribute: `show-ray`
|
|
504
|
+
})], PolarPad.prototype, "showRay", void 0);
|
|
505
|
+
__decorate([property({
|
|
506
|
+
type: Boolean,
|
|
507
|
+
reflect: true,
|
|
508
|
+
attribute: `show-origin`
|
|
509
|
+
})], PolarPad.prototype, "showOrigin", void 0);
|
|
510
|
+
__decorate([property({
|
|
511
|
+
type: Boolean,
|
|
512
|
+
reflect: true,
|
|
513
|
+
attribute: `hide-cursor`
|
|
514
|
+
})], PolarPad.prototype, "hideCursor", void 0);
|
|
515
|
+
__decorate([property({
|
|
516
|
+
type: Boolean,
|
|
517
|
+
attribute: `snap-value`,
|
|
518
|
+
reflect: true
|
|
519
|
+
})], PolarPad.prototype, "snapValue", void 0);
|
|
520
|
+
__decorate([property({
|
|
521
|
+
type: Boolean,
|
|
522
|
+
reflect: true
|
|
523
|
+
})], PolarPad.prototype, "disabled", void 0);
|
|
524
|
+
__decorate([property({ type: Number })], PolarPad.prototype, "stops", void 0);
|
|
525
|
+
__decorate([property({
|
|
526
|
+
type: Number,
|
|
527
|
+
attribute: `stops-angle`
|
|
528
|
+
})], PolarPad.prototype, "stopsAngle", void 0);
|
|
529
|
+
__decorate([property({
|
|
530
|
+
type: Number,
|
|
531
|
+
attribute: `stops-radius`
|
|
532
|
+
})], PolarPad.prototype, "stopsRadius", void 0);
|
|
533
|
+
PolarPad = __decorate([customElement(`ixfx-polar-pad`)], PolarPad);
|
|
534
|
+
//#endregion
|
|
535
|
+
export { PolarPad };
|
|
536
|
+
|
|
537
|
+
//# sourceMappingURL=polar-pad.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polar-pad.js","names":[],"sources":["../src/polar-pad/polar-pad.ts"],"sourcesContent":["import type { PropertyValues } from 'lit';\n/**\n * <ixfx-polar-pad> — circular pad for setting polar coordinates (angle + radius).\n *\n * The user clicks or drags within a circle to position a marker. The marker's\n * position encodes an angle (degrees, 0 = right, clockwise) and a radius (0–1).\n *\n * Properties / attributes\n * angle – current angle in degrees (0 = right, clockwise). Default: 0\n * radius – current radius 0–1 where 1 = edge. Default: 0.5\n * rings – number of concentric rings to draw (0 = none). Default: 0\n * rays – number of evenly-spaced radial spokes to draw (0 = none). Default: 0\n * show-ray – draw a line from the origin to the marker\n * show-origin – draw a dot at the centre\n * hide-cursor – hide cursor during drag and hover (default: false)\n * snap-value – when set, marker snaps to nearest ring/spoke depending on what's displayed\n * disabled – disable all interaction (default: false)\n *\n * Customisable CSS variables:\n *\n * Pad background\n * --pad-background – CSS `background` of the circular pad. Accepts any CSS background\n * value: solid colour, conic-gradient(), radial-gradient(), etc.\n * Dynamic CSS vars like --angle-deg / --radius-pct are available\n * so the gradient can track the current marker position.\n * Default: var(--surface-4)\n * --pad-border-color – stroke of the outer circle (default: --surface-6)\n * --pad-border-width – thickness of outer border (default: 1px)\n *\n * Marker\n * --marker-size – diameter of the draggable marker (default: 10cqb)\n * --marker-color – fill colour of the marker (default: --accent)\n * --marker-opacity – opacity of the marker (default: 1)\n * --marker-stroke – stroke colour of the marker (default: none)\n * --marker-stroke-width – stroke thickness of the marker (default: 0)\n *\n * Origin dot (show-origin)\n * --origin-size – diameter of the origin dot (default: 6cqb)\n * --origin-color – fill colour of the origin dot (default: --accent)\n * --origin-opacity – opacity of the origin dot (default: 1)\n *\n * Ray line (show-ray)\n * --ray-color – stroke colour (default: --surface-6)\n * --ray-width – thickness (default: 2px)\n * --ray-opacity – opacity (default: 1)\n * --ray-dash – stroke-dasharray value e.g. \"4 2\" (default: none)\n *\n * Concentric rings (rings > 0)\n * --ring-color – stroke colour (default: --surface-6)\n * --ring-width – thickness (default: 1px)\n * --ring-opacity – opacity (default: 1)\n * --ring-dash – stroke-dasharray e.g. \"4 2\" (default: none)\n *\n * Radial spokes (rays > 0)\n * --spoke-color – stroke colour (default: --surface-6)\n * --spoke-width – thickness (default: 1px)\n * --spoke-opacity – opacity (default: 1)\n * --spoke-dash – stroke-dasharray e.g. \"4 2\" (default: none)\n *\n * CSS variables set on host for external dynamic styling:\n * --angle-deg – current angle as unitless number in degrees\n * --angle-rad – current angle as unitless number in radians\n * --radius-pct – current radius as unitless number 0–100\n *\n * Events\n * input – CustomEvent<PolarPadInputDetail> { angle: number (deg), radius: number (0–1) }\n * bubbles + composed, fires continuously during drag\n * change – CustomEvent<PolarPadInputDetail> { angle: number (deg), radius: number (0–1) }\n * bubbles + composed, fires when drag ends\n */\nimport { css, html, LitElement, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { KEY_STEP_DIVISOR } from '../keyboard.js';\n\n// ---------------------------------------------------------------------------\n// Geometry helpers\n// ---------------------------------------------------------------------------\n\nconst DEG_TO_RAD = Math.PI / 180;\nconst RAD_TO_DEG = 180 / Math.PI;\n\n/**\n * Convert polar (angle in radians, radius 0-1) to SVG coordinates.\n * SVG viewBox 0 0 100 100; origin at (50,50); full radius = 50.\n * Convention: 0 rad = right (+x), increases CLOCKWISE (+y = downward in SVG).\n */\nfunction polarToSvg(angleRad: number, radius: number): { x: number; y: number } {\n const r = radius * 50;\n return { x: 50 + Math.cos(angleRad) * r, y: 50 + Math.sin(angleRad) * r };\n}\n\n/**\n * Convert SVG coordinates back to polar (angle in radians 0..2π, radius 0-1).\n * SVG: Y increases downward. Convention: 0=right, CW positive.\n */\nfunction svgToPolar(svgX: number, svgY: number): { angleRad: number; radius: number } {\n const dx = svgX - 50;\n const dy = svgY - 50; // +dy = downward = clockwise\n const dist = Math.sqrt(dx * dx + dy * dy);\n const radius = Math.min(1, dist / 50);\n const raw = Math.atan2(dy, dx);\n const angleRad = ((raw % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);\n return { angleRad, radius };\n}\n\nconst clamp01 = (v: number): number => Math.max(0, Math.min(1, v));\n\n// ---------------------------------------------------------------------------\n// Direction-aware snapping helpers\n// ---------------------------------------------------------------------------\n\nfunction snapAngle(angleDeg: number, prevAngleDeg: number, rays: number, snapEnabled: boolean): number {\n if (rays <= 0 || !snapEnabled) return angleDeg;\n const spokeDeg = 360 / rays;\n const normalized = ((angleDeg % 360) + 360) % 360;\n const nearest = Math.round(normalized / spokeDeg) * spokeDeg;\n const remainder = normalized % spokeDeg;\n const tie = Math.abs(remainder) < 0.0001 || Math.abs(spokeDeg - remainder) < 0.0001;\n if (tie) {\n let delta = angleDeg - prevAngleDeg;\n if (delta > 180) delta -= 360;\n if (delta < -180) delta += 360;\n const direction = delta >= 0 ? 1 : -1;\n return (nearest + direction * spokeDeg + 360) % 360;\n }\n return nearest;\n}\n\nfunction snapRadius(radius: number, prevRadius: number, rings: number, snapEnabled: boolean): number {\n if (rings <= 0 || !snapEnabled) return radius;\n const ringStep = 1 / rings;\n const nearest = Math.round(radius / ringStep) * ringStep;\n const remainder = radius % ringStep;\n const tie = Math.abs(remainder) < 0.0001 || Math.abs(ringStep - remainder) < 0.0001;\n if (tie) {\n const direction = radius >= prevRadius ? 1 : -1;\n return Math.max(0, Math.min(1, nearest + direction * ringStep));\n }\n return nearest;\n}\n\nfunction quantiseAngle(angleDeg: number, stops?: number): number {\n if (!stops || stops <= 1) return angleDeg;\n const stepDeg = 360 / stops;\n const normalized = ((angleDeg % 360) + 360) % 360;\n return Math.round(normalized / stepDeg) * stepDeg;\n}\n\nfunction quantiseRadius(radius: number, stops?: number): number {\n if (!stops || stops <= 1) return radius;\n const step = 1 / stops;\n return Math.round(radius / step) * step;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\n@customElement(`ixfx-polar-pad`)\nexport class PolarPad extends LitElement {\n static override styles = css`\n :host {\n display: block;\n width: 200px;\n height: 200px;\n touch-action: none;\n user-select: none;\n container-type: size;\n\n /* Pad background */\n --pad-background: var(--surface-4, oklch(22% 0.02 240));\n --pad-border-color: var(--surface-6, oklch(35% 0.02 240));\n --pad-border-width: 1px;\n\n /* Marker */\n --marker-size: 10cqb;\n --marker-color: var(--accent, oklch(60% 0.15 140));\n --marker-opacity: 1;\n --marker-stroke: none;\n --marker-stroke-width: 0;\n\n /* Origin dot */\n --origin-size: 6cqb;\n --origin-color: var(--accent, oklch(60% 0.15 140));\n --origin-opacity: 1;\n\n /* Ray line */\n --ray-color: var(--surface-6, oklch(35% 0.02 240));\n --ray-width: 2px;\n --ray-opacity: 1;\n --ray-dash: none;\n\n /* Concentric rings */\n --ring-color: var(--surface-6, oklch(35% 0.02 240));\n --ring-width: 1px;\n --ring-opacity: 1;\n --ring-dash: none;\n\n /* Radial spokes */\n --spoke-color: var(--surface-6, oklch(35% 0.02 240));\n --spoke-width: 1px;\n --spoke-opacity: 1;\n --spoke-dash: none;\n }\n\n :host([disabled]) {\n opacity: 0.5;\n pointer-events: none;\n }\n\n .polar-pad-area {\n position: relative;\n width: 100%;\n height: 100%;\n cursor: var(--cursor-display, crosshair);\n }\n\n :host([dragging]) .polar-pad-area {\n cursor: none;\n }\n\n svg {\n width: 100%;\n height: 100%;\n overflow: visible;\n }\n\n .pad-background {\n /* Used on the foreignObject div — accepts any CSS background value */\n width: 100%;\n height: 100%;\n background: var(--pad-background);\n }\n\n .pad-border {\n fill: none;\n stroke: var(--pad-border-color);\n stroke-width: var(--pad-border-width);\n vector-effect: non-scaling-stroke;\n }\n\n .ring {\n fill: none;\n stroke: var(--ring-color);\n stroke-width: var(--ring-width);\n stroke-dasharray: var(--ring-dash);\n opacity: var(--ring-opacity);\n vector-effect: non-scaling-stroke;\n }\n\n .spoke {\n fill: none;\n stroke: var(--spoke-color);\n stroke-width: var(--spoke-width);\n stroke-dasharray: var(--spoke-dash);\n opacity: var(--spoke-opacity);\n vector-effect: non-scaling-stroke;\n }\n\n .ray {\n fill: none;\n stroke: var(--ray-color);\n stroke-width: var(--ray-width);\n stroke-dasharray: var(--ray-dash);\n opacity: var(--ray-opacity);\n vector-effect: non-scaling-stroke;\n }\n\n .origin-dot {\n fill: var(--origin-color);\n opacity: var(--origin-opacity);\n }\n\n .marker {\n fill: var(--marker-color);\n opacity: var(--marker-opacity);\n stroke: var(--marker-stroke);\n stroke-width: var(--marker-stroke-width);\n cursor: grab;\n }\n\n .marker:active {\n cursor: grabbing;\n }\n\n svg:focus {\n outline: none;\n }\n\n svg:focus-visible .pad-border {\n stroke: var(--accent);\n stroke-width: 3;\n }\n `;\n\n /** Current angle in degrees. 0 = right, increases clockwise. */\n @property({ type: Number }) angle = 0;\n\n /** Current radius 0–1. 0 = origin, 1 = edge. */\n @property({ type: Number }) radius = 0.5;\n\n /** Number of concentric rings to display. 0 = none. */\n @property({ type: Number }) rings = 0;\n\n /** Number of evenly-spaced radial spoke lines to display. 0 = none. */\n @property({ type: Number }) rays = 0;\n\n /** Show a line from origin to the marker. */\n @property({ type: Boolean, reflect: true, attribute: `show-ray` }) showRay = false;\n\n /** Show a dot at the origin (centre). */\n @property({ type: Boolean, reflect: true, attribute: `show-origin` }) showOrigin = false;\n\n /** Hide cursor during drag and hover. */\n @property({ type: Boolean, reflect: true, attribute: `hide-cursor` }) hideCursor = false;\n\n /** When set, marker snaps to nearest ring/spoke depending on what's displayed. */\n @property({ type: Boolean, attribute: `snap-value`, reflect: true }) snapValue = false;\n\n /** Disable all interaction (pointer and keyboard). */\n @property({ type: Boolean, reflect: true }) disabled = false;\n\n /** Number of quantised stops for both angle and radius. Overridden by stops-angle/stops-radius if set. */\n @property({ type: Number }) stops?: number;\n\n /** Number of quantised stops for angle. If set, overrides the stops setting for angle. */\n @property({ type: Number, attribute: `stops-angle` }) stopsAngle?: number;\n\n /** Number of quantised stops for radius. If set, overrides the stops setting for radius. */\n @property({ type: Number, attribute: `stops-radius` }) stopsRadius?: number;\n\n private _dragging = false;\n private _dragStartAngle = 0;\n private _dragStartRadius = 0;\n private _pressedKeys = new Set<string>();\n private _prevAngle = 0;\n private _prevRadius = 0;\n\n // -------------------------------------------------------------------------\n // Pointer handling\n // -------------------------------------------------------------------------\n\n private _onPointerDown = (e: PointerEvent): void => {\n e.preventDefault();\n const svg = this.renderRoot.querySelector(`svg`) as SVGSVGElement | undefined;\n (svg as HTMLElement | undefined)?.focus();\n const area = this.renderRoot.querySelector(`.polar-pad-area`) as HTMLElement | undefined;\n if (area)\n area.setPointerCapture(e.pointerId);\n this._dragging = true;\n this._dragStartAngle = this.angle;\n this._dragStartRadius = this.radius;\n this.setAttribute(`dragging`, ``);\n this._updateFromPointer(e);\n globalThis.addEventListener(`pointermove`, this._onPointerMove);\n globalThis.addEventListener(`pointerup`, this._onPointerUp);\n };\n\n private _onPointerMove = (e: PointerEvent): void => {\n if (!this._dragging)\n return;\n e.preventDefault();\n this._updateFromPointer(e);\n };\n\n private _onPointerUp = (): void => {\n const hasChanged = this.angle !== this._dragStartAngle || this.radius !== this._dragStartRadius;\n this._dragging = false;\n this.removeAttribute(`dragging`);\n globalThis.removeEventListener(`pointermove`, this._onPointerMove);\n globalThis.removeEventListener(`pointerup`, this._onPointerUp);\n if (hasChanged) {\n this.dispatchEvent(new CustomEvent<PolarPadInputDetail>(`change`, {\n detail: { angle: this.angle, radius: this.radius },\n bubbles: true,\n composed: true,\n }));\n }\n };\n\n private _updateFromPointer(e: PointerEvent): void {\n const area = this.renderRoot.querySelector(`.polar-pad-area`);\n if (!area)\n return;\n\n const rect = area.getBoundingClientRect();\n const size = Math.min(rect.width, rect.height);\n const svgX = ((e.clientX - rect.left) / size) * 100;\n const svgY = ((e.clientY - rect.top) / size) * 100;\n\n const { angleRad, radius } = svgToPolar(svgX, svgY);\n const newAngleDeg = angleRad * RAD_TO_DEG;\n const newRadius = clamp01(radius);\n\n this._prevAngle = this.angle;\n this._prevRadius = this.radius;\n\n const snappedAngle = snapAngle(newAngleDeg, this._prevAngle, this.rays, this.snapValue);\n const snappedRadius = snapRadius(newRadius, this._prevRadius, this.rings, this.snapValue);\n\n const effectiveStopsAngle = this.stopsAngle ?? this.stops;\n const effectiveStopsRadius = this.stopsRadius ?? this.stops;\n\n this.angle = quantiseAngle(snappedAngle, effectiveStopsAngle);\n this.radius = quantiseRadius(snappedRadius, effectiveStopsRadius);\n this._prevAngle = newAngleDeg;\n this._prevRadius = newRadius;\n\n this.dispatchEvent(new CustomEvent<PolarPadInputDetail>(`input`, {\n detail: { angle: this.angle, radius: this.radius },\n bubbles: true,\n composed: true,\n }));\n }\n\n // -------------------------------------------------------------------------\n // Keyboard handling\n // -------------------------------------------------------------------------\n\n private _onKeyDown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if ([`ArrowLeft`, `ArrowRight`, `ArrowUp`, `ArrowDown`].includes(e.key)) {\n e.preventDefault();\n this._pressedKeys.add(e.key);\n this._handleKeyboardMove(e.shiftKey);\n }\n };\n\n private _onKeyUp = (e: KeyboardEvent): void => {\n this._pressedKeys.delete(e.key);\n };\n\n private _handleKeyboardMove = (shiftKey: boolean): void => {\n const shiftDivisor = shiftKey ? KEY_STEP_DIVISOR : 1;\n const effectiveStopsAngle = this.stopsAngle ?? this.stops;\n const effectiveStopsRadius = this.stopsRadius ?? this.stops;\n\n let angleStep: number;\n if (effectiveStopsAngle && effectiveStopsAngle > 1) {\n angleStep = 360 / effectiveStopsAngle;\n } else {\n const angleRange = this.rays > 0 && this.snapValue ? this.rays : 20;\n angleStep = 360 / angleRange;\n }\n\n let radiusStep: number;\n if (effectiveStopsRadius && effectiveStopsRadius > 1) {\n radiusStep = 1 / effectiveStopsRadius;\n } else {\n radiusStep = 1 / 20;\n }\n\n angleStep /= shiftDivisor;\n radiusStep /= shiftDivisor;\n\n this._prevAngle = this.angle;\n this._prevRadius = this.radius;\n\n let newAngle = this.angle;\n let newRadius = this.radius;\n\n if (this._pressedKeys.has(`ArrowLeft`)) {\n newAngle -= angleStep;\n }\n if (this._pressedKeys.has(`ArrowRight`)) {\n newAngle += angleStep;\n }\n if (this._pressedKeys.has(`ArrowUp`)) {\n newRadius = Math.min(1, newRadius + radiusStep);\n }\n if (this._pressedKeys.has(`ArrowDown`)) {\n newRadius = Math.max(0, newRadius - radiusStep);\n }\n\n newAngle = ((newAngle % 360) + 360) % 360;\n\n let finalAngle = snapAngle(newAngle, this._prevAngle, this.rays, this.snapValue);\n let finalRadius = snapRadius(newRadius, this._prevRadius, this.rings, this.snapValue);\n\n finalAngle = quantiseAngle(finalAngle, effectiveStopsAngle);\n finalRadius = quantiseRadius(finalRadius, effectiveStopsRadius);\n\n if (finalAngle !== this.angle || finalRadius !== this.radius) {\n this.angle = finalAngle;\n this.radius = finalRadius;\n this.dispatchEvent(new CustomEvent<PolarPadInputDetail>(`input`, {\n detail: { angle: this.angle, radius: this.radius },\n bubbles: true,\n composed: true,\n }));\n }\n };\n\n // -------------------------------------------------------------------------\n // CSS variable sync\n // -------------------------------------------------------------------------\n\n private _setCssVars(): void {\n this.style.setProperty(`--angle-deg`, `${this.angle}`);\n this.style.setProperty(`--angle-rad`, `${this.angle * DEG_TO_RAD}`);\n this.style.setProperty(`--radius-pct`, `${clamp01(this.radius) * 100}`);\n }\n\n override updated(_changed: PropertyValues): void {\n super.updated(_changed);\n this._setCssVars();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._onPointerUp();\n this._pressedKeys.clear();\n }\n\n // -------------------------------------------------------------------------\n // SVG helpers\n // -------------------------------------------------------------------------\n\n private _renderRings() {\n if (this.rings <= 0)\n return ``;\n const items = [];\n for (let i = 1; i <= this.rings; i++) {\n const r = (i / this.rings) * 50;\n items.push(svg`<circle class=\"ring\" cx=\"50\" cy=\"50\" r=\"${r}\" />`);\n }\n return items;\n }\n\n private _renderSpokes() {\n if (this.rays <= 0)\n return ``;\n const items = [];\n for (let i = 0; i < this.rays; i++) {\n const angleRad = (i / this.rays) * 2 * Math.PI;\n const cos = Math.cos(angleRad);\n const sin = Math.sin(angleRad); // SVG +y downward matches CW convention directly\n const x1 = 50 + cos * 50;\n const y1 = 50 + sin * 50;\n const x2 = 50 - cos * 50;\n const y2 = 50 - sin * 50;\n items.push(svg`<line class=\"spoke\" x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\" />`);\n }\n return items;\n }\n\n private _renderRay(markerX: number, markerY: number) {\n if (!this.showRay)\n return ``;\n return svg`<line class=\"ray\" x1=\"50\" y1=\"50\" x2=\"${markerX}\" y2=\"${markerY}\" />`;\n }\n\n private _renderOrigin() {\n if (!this.showOrigin)\n return ``;\n return svg`<circle class=\"origin-dot\" cx=\"50\" cy=\"50\" r=\"3\" style=\"r: calc(var(--origin-size) / 2)\" />`;\n }\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n\n override render(): ReturnType<typeof html> {\n const angleRad = this.angle * DEG_TO_RAD;\n const { x: markerX, y: markerY } = polarToSvg(angleRad, clamp01(this.radius));\n\n return html`\n <div class=\"polar-pad-area\"\n @pointerdown=${this._onPointerDown}\n @keydown=${this._onKeyDown}\n @keyup=${this._onKeyUp}\n @blur=${() => this._pressedKeys.clear()}>\n <svg viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"xMidYMid meet\"\n tabindex=${this.disabled ? -1 : 0}>\n <defs>\n <clipPath id=\"circle-clip-${this._uid}\">\n <circle cx=\"50\" cy=\"50\" r=\"50\" />\n </clipPath>\n </defs>\n\n <!-- clipped group: background + rings + spokes -->\n <g clip-path=\"url(#circle-clip-${this._uid})\">\n <foreignObject x=\"0\" y=\"0\" width=\"100\" height=\"100\">\n <div class=\"pad-background\" xmlns=\"http://www.w3.org/1999/xhtml\"></div>\n </foreignObject>\n ${this._renderRings()}\n ${this._renderSpokes()}\n </g>\n\n <!-- border circle (on top of clip, non-scaling stroke) -->\n <circle class=\"pad-border\" cx=\"50\" cy=\"50\" r=\"49.75\" />\n\n <!-- ray + origin + marker -->\n ${this._renderRay(markerX, markerY)}\n ${this._renderOrigin()}\n <circle\n class=\"marker\"\n cx=\"${markerX}\"\n cy=\"${markerY}\"\n r=\"5\"\n style=\"r: calc(var(--marker-size) / 2)\"\n />\n </svg>\n </div>\n `;\n }\n\n /** Stable per-instance uid for SVG clipPath IDs. */\n private readonly _uid = Math.random().toString(36).slice(2, 8);\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type PolarPadInputDetail = {\n readonly angle: number; // degrees, 0 = right, clockwise\n readonly radius: number; // 0–1\n};\n\nexport type PolarPadInputEvent = CustomEvent<PolarPadInputDetail>;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-polar-pad': PolarPad;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { css } from "lit";
|
|
2
|
+
//#region src/styles/popup.ts
|
|
3
|
+
/**
|
|
4
|
+
* Canonical surface styles for floating popup elements (menus, dropdowns,
|
|
5
|
+
* colour picker, tooltips). Apply by adding `popupSurfaceStyles` to a
|
|
6
|
+
* component's `static styles` array and the class `popup-surface` to the
|
|
7
|
+
* popup container element.
|
|
8
|
+
*
|
|
9
|
+
* Intentionally omitted (remain per-component): positioning, padding,
|
|
10
|
+
* dimensions, z-index, and open/close animations.
|
|
11
|
+
*/
|
|
12
|
+
const popupSurfaceStyles = css`
|
|
13
|
+
.popup-surface {
|
|
14
|
+
background: var(--surface-5);
|
|
15
|
+
border: 1px solid var(--surface-6);
|
|
16
|
+
border-radius: var(--radius-l);
|
|
17
|
+
box-shadow: var(--shadow-m);
|
|
18
|
+
color: var(--surface-5-text);
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { popupSurfaceStyles as t };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=popup-Ddx9LCzY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popup-Ddx9LCzY.js","names":[],"sources":["../src/styles/popup.ts"],"sourcesContent":["import { css } from \"lit\";\n\n/**\n * Canonical surface styles for floating popup elements (menus, dropdowns,\n * colour picker, tooltips). Apply by adding `popupSurfaceStyles` to a\n * component's `static styles` array and the class `popup-surface` to the\n * popup container element.\n *\n * Intentionally omitted (remain per-component): positioning, padding,\n * dimensions, z-index, and open/close animations.\n */\nexport const popupSurfaceStyles = css`\n .popup-surface {\n background: var(--surface-5);\n border: 1px solid var(--surface-6);\n border-radius: var(--radius-l);\n box-shadow: var(--shadow-m);\n color: var(--surface-5-text);\n }\n`;\n"],"mappings":";;;;;;;;;;;AAWA,MAAa,qBAAqB,GAAG"}
|