x4js 2.0.5 → 2.0.7

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 (222) hide show
  1. package/build/x4.css +1 -0
  2. package/build/x4.js +1 -0
  3. package/lib/README.txt +15 -0
  4. package/lib/cjs/x4.css +1 -0
  5. package/lib/cjs/x4.js +1 -0
  6. package/lib/esm/x4.css +1 -0
  7. package/lib/esm/x4.mjs +1 -0
  8. package/lib/src/components/base.scss +26 -0
  9. package/lib/src/components/boxes/boxes.module.scss +37 -0
  10. package/lib/src/components/boxes/boxes.ts +125 -0
  11. package/lib/src/components/btngroup/btngroup.module.scss +29 -0
  12. package/lib/src/components/btngroup/btngroup.ts +106 -0
  13. package/lib/src/components/button/button.module.scss +154 -0
  14. package/lib/src/components/button/button.ts +117 -0
  15. package/lib/src/components/calendar/calendar-check-sharp-light.svg +1 -0
  16. package/lib/src/components/calendar/calendar.module.scss +163 -0
  17. package/lib/src/components/calendar/calendar.ts +326 -0
  18. package/lib/src/components/calendar/chevron-left-sharp-light.svg +1 -0
  19. package/lib/src/components/calendar/chevron-right-sharp-light.svg +1 -0
  20. package/lib/src/components/checkbox/check.svg +4 -0
  21. package/lib/src/components/checkbox/checkbox.module.scss +142 -0
  22. package/lib/src/components/checkbox/checkbox.ts +125 -0
  23. package/lib/src/components/colorinput/colorinput.module.scss +65 -0
  24. package/lib/src/components/colorinput/colorinput.ts +88 -0
  25. package/lib/src/components/colorinput/crosshairs-simple-sharp-light.svg +1 -0
  26. package/lib/src/components/colorpicker/colorpicker.module.scss +133 -0
  27. package/lib/src/components/colorpicker/colorpicker.ts +477 -0
  28. package/lib/src/components/combobox/combobox.module.scss +121 -0
  29. package/lib/src/components/combobox/combobox.ts +190 -0
  30. package/lib/src/components/combobox/updown.svg +4 -0
  31. package/lib/src/components/dialog/dialog.module.scss +71 -0
  32. package/lib/src/components/dialog/dialog.ts +91 -0
  33. package/lib/src/components/dialog/xmark-sharp-light.svg +1 -0
  34. package/lib/src/components/form/form.module.scss +34 -0
  35. package/lib/src/components/form/form.ts +36 -0
  36. package/lib/src/components/header/header.module.scss +40 -0
  37. package/lib/src/components/header/header.ts +124 -0
  38. package/lib/src/components/icon/icon.module.scss +30 -0
  39. package/lib/src/components/icon/icon.ts +134 -0
  40. package/lib/src/components/image/image.module.scss +21 -0
  41. package/lib/src/components/image/image.ts +67 -0
  42. package/lib/src/components/input/input.module.scss +69 -0
  43. package/lib/src/components/input/input.ts +274 -0
  44. package/lib/src/components/label/label.module.scss +52 -0
  45. package/lib/src/components/label/label.ts +55 -0
  46. package/lib/src/components/listbox/listbox.module.scss +103 -0
  47. package/lib/src/components/listbox/listbox.ts +427 -0
  48. package/lib/src/components/menu/caret-right-solid.svg +1 -0
  49. package/lib/src/components/menu/menu.module.scss +108 -0
  50. package/lib/src/components/menu/menu.ts +168 -0
  51. package/lib/src/components/messages/circle-exclamation.svg +1 -0
  52. package/lib/src/components/messages/messages.module.scss +47 -0
  53. package/lib/src/components/messages/messages.ts +64 -0
  54. package/lib/src/components/normalize.scss +386 -0
  55. package/lib/src/components/notification/circle-check-solid.svg +1 -0
  56. package/lib/src/components/notification/circle-exclamation-solid.svg +1 -0
  57. package/lib/src/components/notification/circle-notch-light.svg +1 -0
  58. package/lib/src/components/notification/notification.module.scss +82 -0
  59. package/lib/src/components/notification/notification.ts +108 -0
  60. package/lib/src/components/notification/xmark-sharp-light.svg +1 -0
  61. package/lib/src/components/panel/panel.module.scss +48 -0
  62. package/lib/src/components/panel/panel.ts +57 -0
  63. package/lib/src/components/popup/popup.module.scss +43 -0
  64. package/lib/src/components/popup/popup.ts +395 -0
  65. package/lib/src/components/progress/progress.module.scss +57 -0
  66. package/lib/src/components/progress/progress.ts +43 -0
  67. package/lib/src/components/rating/rating.module.scss +23 -0
  68. package/lib/src/components/rating/rating.ts +125 -0
  69. package/lib/src/components/rating/star-sharp-light.svg +1 -0
  70. package/lib/src/components/rating/star-sharp-solid.svg +1 -0
  71. package/lib/src/components/shared.scss +76 -0
  72. package/lib/src/components/sizers/sizer.module.scss +90 -0
  73. package/lib/src/components/sizers/sizer.ts +120 -0
  74. package/lib/src/components/slider/slider.module.scss +71 -0
  75. package/lib/src/components/slider/slider.ts +143 -0
  76. package/lib/src/components/switch/switch.module.scss +127 -0
  77. package/lib/src/components/switch/switch.ts +56 -0
  78. package/lib/src/components/tabs/tabs.module.scss +46 -0
  79. package/lib/src/components/tabs/tabs.ts +157 -0
  80. package/lib/src/components/textarea/textarea.module.scss +59 -0
  81. package/lib/src/components/textarea/textarea.ts +54 -0
  82. package/lib/src/components/textedit/textedit.module.scss +114 -0
  83. package/lib/src/components/textedit/textedit.ts +82 -0
  84. package/lib/src/components/themes.scss +77 -0
  85. package/lib/src/components/tooltips/circle-info-sharp-light.svg +1 -0
  86. package/lib/src/components/tooltips/tooltips.scss +51 -0
  87. package/lib/src/components/tooltips/tooltips.ts +103 -0
  88. package/lib/src/components/treeview/chevron-down-light.svg +1 -0
  89. package/lib/src/components/treeview/treeview.module.scss +116 -0
  90. package/lib/src/components/treeview/treeview.ts +403 -0
  91. package/lib/src/components/viewport/viewport.module.scss +25 -0
  92. package/lib/src/components/viewport/viewport.ts +38 -0
  93. package/lib/src/core/component.ts +979 -0
  94. package/lib/src/core/core_colors.ts +250 -0
  95. package/lib/src/core/core_dom.ts +471 -0
  96. package/lib/src/core/core_dragdrop.ts +201 -0
  97. package/lib/src/core/core_element.ts +98 -0
  98. package/lib/src/core/core_events.ts +149 -0
  99. package/lib/src/core/core_i18n.ts +377 -0
  100. package/lib/src/core/core_router.ts +221 -0
  101. package/lib/src/core/core_styles.ts +215 -0
  102. package/lib/src/core/core_svg.ts +550 -0
  103. package/lib/src/core/core_tools.ts +673 -0
  104. package/lib/src/demo/assets/house-light.svg +1 -0
  105. package/lib/src/demo/assets/radio.svg +4 -0
  106. package/lib/src/demo/index.html +12 -0
  107. package/lib/src/demo/main.scss +21 -0
  108. package/lib/src/demo/main.tsx +323 -0
  109. package/lib/src/x4.scss +19 -0
  110. package/lib/src/x4.ts +60 -0
  111. package/lib/styles/x4.css +1 -0
  112. package/lib/types/x4.d.ts +51026 -0
  113. package/package.json +3 -12
  114. package/scripts/build.mjs +362 -0
  115. package/scripts/prepack.mjs +51 -0
  116. package/src/components/base.scss +26 -0
  117. package/src/components/boxes/boxes.module.scss +37 -0
  118. package/src/components/boxes/boxes.ts +125 -0
  119. package/src/components/btngroup/btngroup.module.scss +29 -0
  120. package/src/components/btngroup/btngroup.ts +106 -0
  121. package/src/components/button/button.module.scss +154 -0
  122. package/src/components/button/button.ts +117 -0
  123. package/src/components/calendar/calendar-check-sharp-light.svg +1 -0
  124. package/src/components/calendar/calendar.module.scss +163 -0
  125. package/src/components/calendar/calendar.ts +326 -0
  126. package/src/components/calendar/chevron-left-sharp-light.svg +1 -0
  127. package/src/components/calendar/chevron-right-sharp-light.svg +1 -0
  128. package/src/components/checkbox/check.svg +4 -0
  129. package/src/components/checkbox/checkbox.module.scss +142 -0
  130. package/src/components/checkbox/checkbox.ts +125 -0
  131. package/src/components/colorinput/colorinput.module.scss +65 -0
  132. package/src/components/colorinput/colorinput.ts +88 -0
  133. package/src/components/colorinput/crosshairs-simple-sharp-light.svg +1 -0
  134. package/src/components/colorpicker/colorpicker.module.scss +133 -0
  135. package/src/components/colorpicker/colorpicker.ts +477 -0
  136. package/src/components/combobox/combobox.module.scss +121 -0
  137. package/src/components/combobox/combobox.ts +190 -0
  138. package/src/components/combobox/updown.svg +4 -0
  139. package/src/components/dialog/dialog.module.scss +71 -0
  140. package/src/components/dialog/dialog.ts +91 -0
  141. package/src/components/dialog/xmark-sharp-light.svg +1 -0
  142. package/src/components/form/form.module.scss +34 -0
  143. package/src/components/form/form.ts +36 -0
  144. package/src/components/header/header.module.scss +40 -0
  145. package/src/components/header/header.ts +124 -0
  146. package/src/components/icon/icon.module.scss +30 -0
  147. package/src/components/icon/icon.ts +134 -0
  148. package/src/components/image/image.module.scss +21 -0
  149. package/src/components/image/image.ts +67 -0
  150. package/src/components/input/input.module.scss +69 -0
  151. package/src/components/input/input.ts +274 -0
  152. package/src/components/label/label.module.scss +52 -0
  153. package/src/components/label/label.ts +55 -0
  154. package/src/components/listbox/listbox.module.scss +103 -0
  155. package/src/components/listbox/listbox.ts +427 -0
  156. package/src/components/menu/caret-right-solid.svg +1 -0
  157. package/src/components/menu/menu.module.scss +108 -0
  158. package/src/components/menu/menu.ts +168 -0
  159. package/src/components/messages/circle-exclamation.svg +1 -0
  160. package/src/components/messages/messages.module.scss +47 -0
  161. package/src/components/messages/messages.ts +64 -0
  162. package/src/components/normalize.scss +386 -0
  163. package/src/components/notification/circle-check-solid.svg +1 -0
  164. package/src/components/notification/circle-exclamation-solid.svg +1 -0
  165. package/src/components/notification/circle-notch-light.svg +1 -0
  166. package/src/components/notification/notification.module.scss +82 -0
  167. package/src/components/notification/notification.ts +108 -0
  168. package/src/components/notification/xmark-sharp-light.svg +1 -0
  169. package/src/components/panel/panel.module.scss +48 -0
  170. package/src/components/panel/panel.ts +57 -0
  171. package/src/components/popup/popup.module.scss +43 -0
  172. package/src/components/popup/popup.ts +395 -0
  173. package/src/components/progress/progress.module.scss +57 -0
  174. package/src/components/progress/progress.ts +43 -0
  175. package/src/components/rating/rating.module.scss +23 -0
  176. package/src/components/rating/rating.ts +125 -0
  177. package/src/components/rating/star-sharp-light.svg +1 -0
  178. package/src/components/rating/star-sharp-solid.svg +1 -0
  179. package/src/components/shared.scss +76 -0
  180. package/src/components/sizers/sizer.module.scss +90 -0
  181. package/src/components/sizers/sizer.ts +120 -0
  182. package/src/components/slider/slider.module.scss +71 -0
  183. package/src/components/slider/slider.ts +143 -0
  184. package/src/components/switch/switch.module.scss +127 -0
  185. package/src/components/switch/switch.ts +56 -0
  186. package/src/components/tabs/tabs.module.scss +46 -0
  187. package/src/components/tabs/tabs.ts +157 -0
  188. package/src/components/textarea/textarea.module.scss +59 -0
  189. package/src/components/textarea/textarea.ts +54 -0
  190. package/src/components/textedit/textedit.module.scss +114 -0
  191. package/src/components/textedit/textedit.ts +82 -0
  192. package/src/components/themes.scss +77 -0
  193. package/src/components/tooltips/circle-info-sharp-light.svg +1 -0
  194. package/src/components/tooltips/tooltips.scss +51 -0
  195. package/src/components/tooltips/tooltips.ts +103 -0
  196. package/src/components/treeview/chevron-down-light.svg +1 -0
  197. package/src/components/treeview/treeview.module.scss +116 -0
  198. package/src/components/treeview/treeview.ts +403 -0
  199. package/src/components/viewport/viewport.module.scss +25 -0
  200. package/src/components/viewport/viewport.ts +38 -0
  201. package/src/core/component.ts +979 -0
  202. package/src/core/core_colors.ts +250 -0
  203. package/src/core/core_dom.ts +471 -0
  204. package/src/core/core_dragdrop.ts +201 -0
  205. package/src/core/core_element.ts +98 -0
  206. package/src/core/core_events.ts +149 -0
  207. package/src/core/core_i18n.ts +377 -0
  208. package/src/core/core_router.ts +221 -0
  209. package/src/core/core_styles.ts +215 -0
  210. package/src/core/core_svg.ts +550 -0
  211. package/src/core/core_tools.ts +673 -0
  212. package/src/demo/assets/house-light.svg +1 -0
  213. package/src/demo/assets/radio.svg +4 -0
  214. package/src/demo/index.html +12 -0
  215. package/src/demo/main.scss +21 -0
  216. package/src/demo/main.tsx +323 -0
  217. package/src/x4.scss +19 -0
  218. package/src/x4.ts +60 -0
  219. package/tsconfig.json +14 -0
  220. package/types/scss.d.ts +4 -0
  221. package/types/svg.d.ts +4 -0
  222. package/types/x4react.d.ts +9 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|
7
+ *
8
+ * @file colorinput.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2024 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
17
+ import { Component } from '@core/component';
18
+ import { isFeatureAvailable } from '@core/core_tools.js';
19
+ import { Color } from '@core/core_colors';
20
+
21
+ import { BoxProps, HBox } from '../boxes/boxes';
22
+ import { Input } from '../input/input.js';
23
+ import { Button } from '../button/button.js';
24
+
25
+
26
+ import "./colorinput.module.scss"
27
+ import icon from "./crosshairs-simple-sharp-light.svg"
28
+
29
+ //TODO: add swatches
30
+ //TODO: better keyboard handling (selection after cursor)
31
+
32
+ /**
33
+ *
34
+ */
35
+
36
+ interface ColorInputProps extends BoxProps {
37
+ color: Color | string;
38
+ }
39
+
40
+ /**
41
+ *
42
+ */
43
+
44
+ export class ColorInput extends HBox<ColorInputProps> {
45
+ constructor( props: ColorInputProps ) {
46
+ super( props );
47
+
48
+ let swatch: Component;
49
+ let edit: Input;
50
+
51
+ this.setContent( [
52
+ swatch = new Component( { cls: "swatch" } ),
53
+ edit = new Input( { type: "text", value: "", spellcheck: false } ),
54
+
55
+ isFeatureAvailable("eyedropper") ? new Button( { icon: icon, click: ( ) => {
56
+ const eyeDropper = new (window as any).EyeDropper();
57
+ eyeDropper.open( ).then( ( result: any ) => {
58
+ color = new Color( result.sRGBHex );
59
+ updateColor( color );
60
+ });
61
+ } } ) : null
62
+ ])
63
+
64
+ edit.addDOMEvent( "input", ( ) => {
65
+ const txt = edit.getValue( );
66
+ const clr = new Color( txt );
67
+ if( !clr.isInvalid() ) {
68
+ color = clr;
69
+ updateColor( color );
70
+ }
71
+ });
72
+
73
+ const updateColor = ( clr: Color ) => {
74
+ swatch.setStyleValue( "backgroundColor", clr.toRgbString(false) );
75
+ edit.setValue( clr.toRgbString(false) );
76
+ }
77
+
78
+ let color: Color;
79
+ if( props.color instanceof Color ) {
80
+ color = props.color;
81
+ }
82
+ else {
83
+ color = new Color( props.color );
84
+ }
85
+
86
+ updateColor( color );
87
+ }
88
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><!--!Font Awesome Pro 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2024 Fonticons, Inc.--><path d="M479.4 240L384 240l-16 0 0 32 16 0 95.4 0C471.6 383 383 471.6 272 479.4l0-95.4 0-16-32 0 0 16 0 95.4C129 471.6 40.4 383 32.6 272l95.4 0 16 0 0-32-16 0-95.4 0C40.4 129 129 40.4 240 32.6l0 95.4 0 16 32 0 0-16 0-95.4C383 40.4 471.6 129 479.4 240zM256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/></svg>
@@ -0,0 +1,133 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|
7
+ *
8
+ * @file colorpicker.module.scss
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2024 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
17
+ @use "../shared.scss";
18
+
19
+ @mixin overlay-shadow {
20
+ width: 12px;
21
+ height: 12px;
22
+ border: 2px solid white;
23
+ border-radius: 8px;
24
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
25
+ }
26
+
27
+ .x4colorpicker {
28
+ width: 240px;
29
+ gap: 4px;
30
+
31
+ touch-action: none;
32
+ outline: none;
33
+
34
+ margin: 8px;
35
+ &:focus {
36
+ //@include outline-focus;
37
+ }
38
+
39
+ .overlay {
40
+ position: absolute;
41
+ left: 0;
42
+ top: 0;
43
+ right: 0;
44
+ bottom: 0;
45
+ }
46
+
47
+ .x4saturation {
48
+ width: 100%;
49
+
50
+ height: 140px;
51
+ position: relative;
52
+
53
+ .thumb {
54
+ @include overlay-shadow;
55
+ position: absolute;
56
+ transform: translate(-50%,50%);
57
+ }
58
+ }
59
+
60
+ .body {
61
+ gap: 4px;
62
+
63
+ &> .x4vbox {
64
+ gap: 4px;
65
+ }
66
+
67
+ .x4hueslider {
68
+ position: relative;
69
+ height: 16px;
70
+ overflow: hidden;
71
+
72
+ background-image: linear-gradient(to right, rgb(255, 0, 0), rgb(255, 255, 0), rgb(0, 255, 0), rgb(0, 255, 212), rgb(0, 0, 255), rgb(255, 0, 255), rgb(255, 0, 0));
73
+ border: 1px solid var( --color-gray-3 );
74
+
75
+ .thumb {
76
+ @include overlay-shadow;
77
+ position: absolute;
78
+ transform: translate(-50%,-50%);
79
+ top: 50%;
80
+ }
81
+
82
+ }
83
+
84
+ .x4alphaslider {
85
+ position: relative;
86
+ height: 16px;
87
+ overflow: hidden;
88
+
89
+ .checkers {
90
+ background-image: linear-gradient(45deg, #ccc 25%, transparent 25%),
91
+ linear-gradient(-45deg, #ccc 25%, transparent 25%),
92
+ linear-gradient(45deg, transparent 75%, #ccc 75%),
93
+ linear-gradient(-45deg, transparent 75%, #ccc 75%);
94
+ background-size: 8px 8px;
95
+ background-position: 0 0, 0 20px, 20px -20px, -20px 0;
96
+ }
97
+
98
+ .color {
99
+ //border-radius: 8px;
100
+ background-image: linear-gradient(90deg, transparent, rgb(0, 178, 255));
101
+ }
102
+
103
+ .thumb {
104
+ @include overlay-shadow;
105
+
106
+ position: absolute;
107
+ transform: translate(-50%,-50%);
108
+ top: 50%;
109
+ }
110
+
111
+ }
112
+
113
+ .swatch {
114
+ width: 36px;
115
+ height: 36px;
116
+
117
+ .checkers {
118
+ border-radius: 8px;
119
+ background-image: linear-gradient(45deg, #ccc 25%, transparent 25%),
120
+ linear-gradient(-45deg, #ccc 25%, transparent 25%),
121
+ linear-gradient(45deg, transparent 75%, #ccc 75%),
122
+ linear-gradient(-45deg, transparent 75%, #ccc 75%);
123
+ background-size: 8px 8px;
124
+ background-position: 0 0, 0 20px, 20px -20px, -20px 0;
125
+ }
126
+
127
+ .color {
128
+ border-radius: 8px;
129
+ background-image: linear-gradient(90deg, transparent, rgb(0, 178, 255));
130
+ }
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,477 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|
7
+ *
8
+ * @file colorpicker.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2024 R-libre ingenierie
12
+ *
13
+ * Use of this source code is governed by an MIT-style license
14
+ * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
+ **/
16
+
17
+ import { Color, Hsv } from '@core/core_colors';
18
+ import { Rect, clamp, isFeatureAvailable } from '@core/core_tools';
19
+
20
+ import { Component, ComponentEvent, ComponentEvents, ComponentProps } from '@core/component';
21
+ import { Box, BoxProps, HBox, VBox } from '../boxes/boxes';
22
+
23
+ import "./colorpicker.module.scss"
24
+
25
+ interface ColorPickerProps extends ComponentProps {
26
+ color: string | Color;
27
+ }
28
+
29
+ interface HueChangeEvent extends ComponentEvent {
30
+ hue: number;
31
+ }
32
+
33
+ interface AlphaChangeEvent extends ComponentEvent {
34
+ alpha: number;
35
+ }
36
+
37
+ interface SatChangeEvent extends ComponentEvent {
38
+ saturation: number;
39
+ value: number;
40
+ }
41
+
42
+ interface CommonEvents extends ComponentEvents {
43
+ hue_change: HueChangeEvent;
44
+ alpha_change: AlphaChangeEvent;
45
+ sat_change: SatChangeEvent;
46
+ }
47
+
48
+ /**
49
+ *
50
+ */
51
+
52
+ export class Saturation extends Box<BoxProps,CommonEvents> {
53
+
54
+ private mdown = false;
55
+ private irect: Rect;
56
+
57
+ private hsv: Hsv = { hue: 1, saturation: 1, value: 1, alpha: 1 };
58
+
59
+ private color: Component;
60
+ private thumb: Component;
61
+
62
+ constructor( props: BoxProps, init: Hsv ) {
63
+ super( props );
64
+
65
+ this.setContent( [
66
+ this.color = new Component( { cls: "overlay" } ),
67
+ new Component( { cls: "overlay", style: { backgroundImage: "linear-gradient(90deg, rgb(255, 255, 255), transparent)" } } ),
68
+ new Component( { cls: "overlay", style: { backgroundImage: "linear-gradient(0deg, rgb(0, 0, 0), transparent)" } } ),
69
+ this.thumb = new Component( { cls: "thumb" } ),
70
+ ]);
71
+
72
+ this.setDOMEvents( {
73
+ pointerdown: ( e ) => this.mousedown( e ),
74
+ pointermove: ( e ) => this.mousemove( e ),
75
+ pointerup: ( e ) => this.mouseup( e ),
76
+ created: () => this.updateThumbMarker( ),
77
+ } );
78
+
79
+ this.updateBaseColor( init );
80
+ }
81
+
82
+ mousedown( ev: PointerEvent ) {
83
+ this.mdown = true;
84
+ this.irect = this.getBoundingRect( );
85
+ this.setCapture( ev.pointerId );
86
+ }
87
+
88
+ mousemove( ev: PointerEvent ) {
89
+
90
+ if( this.mdown ) {
91
+ const ir = this.irect;
92
+
93
+ let hpos = clamp(ev.clientX - ir.left, 0, ir.width );
94
+ let hperc = hpos / ir.width;
95
+
96
+ let vpos = clamp(ev.clientY - ir.top, 0, ir.height );
97
+ let vperc = vpos / ir.height;
98
+
99
+ this.hsv.saturation = hperc;
100
+ this.hsv.value = 1-vperc;
101
+
102
+ this.updateThumbMarker( );
103
+ this.fire( "sat_change", { saturation: this.hsv.saturation, value: this.hsv.value } );
104
+ }
105
+ }
106
+
107
+ mouseup( ev: PointerEvent ) {
108
+ if( this.mdown ) {
109
+ this.releaseCapture( ev.pointerId );
110
+ this.mdown = false;
111
+ }
112
+ }
113
+
114
+ updateThumbMarker( ) {
115
+ const rc = this.color.getBoundingRect( );
116
+
117
+ this.thumb.setStyle( {
118
+ left: (this.hsv.saturation * rc.width ) + 'px',
119
+ bottom: ( this.hsv.value * rc.height ) + 'px'
120
+ } );
121
+ }
122
+
123
+ updateBaseColor( hsv: Hsv ) {
124
+ const base = new Color(0,0,0)
125
+ base.setHsv( hsv.hue, 1, 1, 1 );
126
+ this.color.setStyleValue( "backgroundColor", base.toRgbString(false) );
127
+ }
128
+
129
+ move( sens: string, delta: number ) {
130
+ switch( sens ) {
131
+ case 'saturation': {
132
+ this.hsv.saturation += delta;
133
+ if( this.hsv.saturation<0 ) {
134
+ this.hsv.saturation = 0;
135
+ }
136
+ else if( this.hsv.saturation>1 ) {
137
+ this.hsv.saturation = 1;
138
+ }
139
+
140
+ this.fire( "sat_change", { saturation: this.hsv.saturation, value: this.hsv.value } );
141
+ this.updateThumbMarker( );
142
+ break;
143
+ }
144
+
145
+ case 'value': {
146
+ this.hsv.value += delta;
147
+ if( this.hsv.value<0 ) {
148
+ this.hsv.value = 0;
149
+ }
150
+ else if( this.hsv.value>1 ) {
151
+ this.hsv.value = 1;
152
+ }
153
+
154
+ this.fire( "sat_change", { saturation: this.hsv.saturation, value: this.hsv.value } );
155
+ this.updateThumbMarker( );
156
+ break;
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+
163
+
164
+ /**
165
+ *
166
+ */
167
+
168
+ class HueSlider extends Box<BoxProps,CommonEvents> {
169
+
170
+ private thumb: Component;
171
+ private hsv: Hsv = { hue: 1, saturation: 1, value: 1, alpha: 1 };
172
+
173
+ private mdown = false;
174
+ private irect: Rect;
175
+
176
+ constructor( props: BoxProps, init: Hsv ) {
177
+ super( props );
178
+
179
+ this.setContent( [
180
+ this.thumb = new Component( { cls: "thumb", left: "50%" } ),
181
+ ]);
182
+
183
+ this.setDOMEvents( {
184
+ pointerdown: ( e ) => this.mousedown( e ),
185
+ pointermove: ( e ) => this.mousemove( e ),
186
+ pointerup: ( e ) => this.mouseup( e ),
187
+ } );
188
+
189
+ this.updateHue( init );
190
+ }
191
+
192
+ mousedown( ev: PointerEvent ) {
193
+ this.mdown = true;
194
+ this.irect = this.getBoundingRect( );
195
+ this.setCapture( ev.pointerId );
196
+ }
197
+
198
+ mousemove( ev: PointerEvent ) {
199
+
200
+ if( this.mdown ) {
201
+ const ir = this.irect;
202
+
203
+ let hpos = clamp(ev.clientX - ir.left, 0, ir.width );
204
+ let hperc = hpos / ir.width;
205
+
206
+ this.hsv.hue = hperc;
207
+
208
+ this.updateHue( this.hsv );
209
+ this.fire( "hue_change", { hue: this.hsv.hue } );
210
+ }
211
+ }
212
+
213
+ mouseup( ev: PointerEvent ) {
214
+ if( this.mdown ) {
215
+ this.releaseCapture( ev.pointerId );
216
+ this.mdown = false;
217
+ }
218
+ }
219
+
220
+ updateHue( hsv: Hsv ) {
221
+ this.hsv.hue = hsv.hue;
222
+ this.thumb.setStyleValue( "left", (hsv.hue*100)+'%' );
223
+ }
224
+
225
+ move( delta: number ) {
226
+ this.hsv.hue += delta;
227
+ if( this.hsv.hue<0 ) {
228
+ this.hsv.hue = 0;
229
+ }
230
+ else if( this.hsv.hue>1 ) {
231
+ this.hsv.hue = 1;
232
+ }
233
+
234
+ this.fire( "hue_change", { hue: this.hsv.hue } );
235
+ this.updateHue( this.hsv );
236
+ }
237
+ }
238
+
239
+
240
+ /**
241
+ *
242
+ */
243
+
244
+ class AlphaSlider extends Box<BoxProps,CommonEvents> {
245
+
246
+ private thumb: Component;
247
+ private color: Component;
248
+ private hsv: Hsv = { hue: 1, saturation: 1, value: 1, alpha: 1 };
249
+
250
+ private mdown = false;
251
+ private irect: Rect;
252
+
253
+ constructor( props: BoxProps, init: Hsv ) {
254
+ super( props );
255
+
256
+ this.setContent( [
257
+ new Component( { cls: "overlay checkers"} ),
258
+ this.color = new Component( { cls: "overlay color"} ),
259
+ this.thumb = new Component( { cls: "thumb", left: "50%" } ),
260
+ ]);
261
+
262
+ this.setDOMEvents( {
263
+ pointerdown: ( e ) => this._on_mousedown( e ),
264
+ pointermove: ( e ) => this._on_mousemove( e ),
265
+ pointerup: ( e ) => this._on_mouseup( e ),
266
+ } );
267
+
268
+ this.updateAlpha( );
269
+ this.updateBaseColor( init );
270
+ }
271
+
272
+ _on_mousedown( ev: PointerEvent ) {
273
+ this.mdown = true;
274
+ this.irect = this.getBoundingRect( );
275
+ this.setCapture( ev.pointerId );
276
+ }
277
+
278
+ _on_mousemove( ev: PointerEvent ) {
279
+
280
+ if( this.mdown ) {
281
+ const ir = this.irect;
282
+
283
+ let hpos = clamp(ev.clientX - ir.left, 0, ir.width );
284
+ let hperc = hpos / ir.width;
285
+
286
+ this.hsv.alpha = hperc;
287
+
288
+ this.updateAlpha( );
289
+ this.fire( "alpha_change", { alpha: this.hsv.alpha } );
290
+ }
291
+ }
292
+
293
+ _on_mouseup( ev: PointerEvent ) {
294
+ if( this.mdown ) {
295
+ this.releaseCapture( ev.pointerId );
296
+ this.mdown = false;
297
+ }
298
+ }
299
+
300
+ updateAlpha( ) {
301
+ this.thumb.setStyleValue( "left", (this.hsv.alpha*100)+'%' );
302
+ }
303
+
304
+ updateBaseColor( hsv: Hsv ) {
305
+ const base = new Color(0,0,0)
306
+ base.setHsv( hsv.hue, hsv.saturation, hsv.value, 1 );
307
+ this.color.setStyleValue( "backgroundImage", `linear-gradient(90deg, transparent, ${base.toRgbString(false)})` );
308
+ }
309
+
310
+ setColor( hsv: Hsv ) {
311
+ this.hsv = hsv;
312
+ this.updateBaseColor( hsv );
313
+ this.updateAlpha( );
314
+ }
315
+
316
+ move( delta: number ) {
317
+ this.hsv.alpha += delta;
318
+ if( this.hsv.alpha<0 ) {
319
+ this.hsv.alpha = 0;
320
+ }
321
+ else if( this.hsv.alpha>1 ) {
322
+ this.hsv.alpha = 1;
323
+ }
324
+
325
+ this.fire( "alpha_change", { alpha: this.hsv.alpha } );
326
+ this.updateAlpha( );
327
+ }
328
+ }
329
+
330
+
331
+ /**
332
+ *
333
+ */
334
+
335
+ interface ChangeEvent extends ComponentEvent {
336
+ color: Color;
337
+ }
338
+
339
+ interface ColorPickerChangeEvents extends ComponentEvents {
340
+ change: ChangeEvent
341
+ }
342
+
343
+ /**
344
+ *
345
+ */
346
+ export class ColorPicker extends VBox<ColorPickerProps,ColorPickerChangeEvents> {
347
+
348
+ private _base: Color;
349
+ private _sat: Saturation;
350
+ private _swatch: Component;
351
+ private _hue: HueSlider;
352
+ private _alpha: AlphaSlider;
353
+
354
+
355
+ constructor( props: ColorPickerProps ) {
356
+ super( props );
357
+
358
+ if( props.color instanceof Color ) {
359
+ this._base = props.color;
360
+ }
361
+ else {
362
+ this._base = new Color( props.color );
363
+ }
364
+
365
+ let hsv = this._base.toHsv( );
366
+
367
+ this.setAttribute( "tabindex", 0 );
368
+
369
+ this.setContent( [
370
+ this._sat = new Saturation( { }, hsv ),
371
+ new HBox( {
372
+ cls: "body",
373
+ content: [
374
+ new VBox( {cls: "x4flex", content: [
375
+ this._hue = new HueSlider( { }, hsv ),
376
+ this._alpha = new AlphaSlider( { }, hsv ),
377
+ ] } ),
378
+ new Box( { cls: "swatch", content: [
379
+ new Component( { cls: "overlay checkers" } ),
380
+ this._swatch = new Component( { cls: "overlay" } ),
381
+ ] } )
382
+ ]
383
+ })
384
+ ]);
385
+
386
+ this._sat.on( "sat_change", ( ev ) => {
387
+ hsv.saturation = ev.saturation;
388
+ hsv.value = ev.value;
389
+ updateColor( );
390
+ this._alpha.updateBaseColor( hsv );
391
+ } );
392
+
393
+ this._hue.on( 'hue_change', ( ev ) => {
394
+ hsv.hue = ev.hue;
395
+ this._sat.updateBaseColor( hsv );
396
+ this._alpha.updateBaseColor( hsv );
397
+ updateColor( );
398
+ } );
399
+
400
+ this._alpha.on( 'alpha_change', ( ev ) => {
401
+ hsv.alpha = ev.alpha;
402
+ updateColor( );
403
+ } );
404
+
405
+ const updateColor = ( ) => {
406
+ this._base.setHsv( hsv.hue, hsv.saturation, hsv.value, hsv.alpha );
407
+ this._swatch.setStyleValue( "backgroundColor", this._base.toRgbString() );
408
+ this._swatch.setAttribute( "tooltip", this._base.toRgbString() );
409
+
410
+ this.fire( "change", { color: this._base } );
411
+ }
412
+
413
+ if( isFeatureAvailable("eyedropper") ) {
414
+ this._swatch.addDOMEvent( "click", ( e ) => {
415
+ const eyeDropper = new (window as any).EyeDropper();
416
+ eyeDropper.open( ).then( ( result: any ) => {
417
+ const color = new Color( result.sRGBHex );
418
+ hsv = color.toHsv( );
419
+
420
+ this._alpha.setColor( hsv );
421
+
422
+ this._sat.updateBaseColor( hsv );
423
+ this._hue.updateHue( hsv );
424
+ updateColor( );
425
+ });
426
+ })
427
+ }
428
+
429
+ this.addDOMEvent( "keydown", ( ev ) => this._onkey( ev ) );
430
+
431
+ updateColor( );
432
+ }
433
+
434
+ private _onkey( ev: KeyboardEvent ) {
435
+ switch( ev.key ) {
436
+ case "ArrowLeft": {
437
+ if( ev.ctrlKey ) {
438
+ this._hue.move( -0.01 );
439
+ }
440
+ else {
441
+ this._sat.move( "saturation", -0.01 );
442
+ }
443
+ break;
444
+ }
445
+
446
+ case "ArrowRight": {
447
+ if( ev.ctrlKey ) {
448
+ this._hue.move( 0.01 );
449
+ }
450
+ else {
451
+ this._sat.move( "saturation", 0.01 );
452
+ }
453
+ break;
454
+ }
455
+
456
+ case "ArrowUp": {
457
+ if( ev.ctrlKey ) {
458
+ this._alpha.move( 0.01 );
459
+ }
460
+ else {
461
+ this._sat.move( "value", 0.01 );
462
+ }
463
+ break;
464
+ }
465
+
466
+ case "ArrowDown": {
467
+ if( ev.ctrlKey ) {
468
+ this._alpha.move( -0.01 );
469
+ }
470
+ else {
471
+ this._sat.move( "value", -0.01 );
472
+ }
473
+ break;
474
+ }
475
+ }
476
+ }
477
+ }