x4js 2.0.13 → 2.0.15

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 (260) hide show
  1. package/.vscode/launch.json +14 -0
  2. package/README.md +5 -0
  3. package/{lib/src/demo → demo}/main.scss +3 -1
  4. package/{lib/src/demo/main.tsx → demo/main.ts} +37 -36
  5. package/demo/package.json +26 -0
  6. package/demo/scss.d.ts +4 -0
  7. package/demo/svg.d.ts +1 -0
  8. package/demo/tsconfig.json +14 -0
  9. package/lib/README.txt +5 -0
  10. package/lib/cjs/x4.css +1 -1
  11. package/lib/cjs/x4.js +2 -1
  12. package/lib/esm/x4.css +1 -1
  13. package/lib/esm/x4.mjs +2 -1
  14. package/lib/src/components/boxes/boxes.module.scss +17 -0
  15. package/lib/src/components/boxes/boxes.ts +258 -17
  16. package/lib/src/components/breadcrumb/breadcrumb.scss +56 -28
  17. package/lib/src/components/breadcrumb/breadcrumb.ts +93 -84
  18. package/lib/src/components/btngroup/btngroup.module.scss +12 -0
  19. package/lib/src/components/btngroup/btngroup.ts +41 -8
  20. package/lib/src/components/button/button.module.scss +23 -5
  21. package/lib/src/components/button/button.ts +72 -4
  22. package/lib/src/components/canvas/canvas.module.scss +25 -0
  23. package/lib/src/components/canvas/canvas.ts +189 -0
  24. package/lib/src/components/canvas/canvas_ex.ts +276 -0
  25. package/lib/src/components/checkbox/checkbox.ts +18 -4
  26. package/lib/src/components/combobox/combobox.module.scss +24 -15
  27. package/lib/src/components/combobox/combobox.ts +107 -24
  28. package/lib/src/components/components.ts +7 -0
  29. package/lib/src/components/dialog/dialog.module.scss +40 -7
  30. package/lib/src/components/dialog/dialog.ts +166 -31
  31. package/lib/src/components/filedrop/cloud-arrow-up.svg +1 -0
  32. package/lib/src/components/filedrop/filedrop.module.scss +70 -0
  33. package/lib/src/components/filedrop/filedrop.ts +131 -0
  34. package/lib/src/components/form/form.module.scss +4 -0
  35. package/lib/src/components/form/form.ts +137 -6
  36. package/lib/src/components/gridview/arrow-down-light.svg +1 -0
  37. package/lib/src/components/gridview/arrow-up-light.svg +1 -0
  38. package/lib/src/components/gridview/gridview.module.scss +324 -0
  39. package/lib/src/components/gridview/gridview.ts +1175 -0
  40. package/lib/src/components/icon/icon.module.scss +2 -1
  41. package/lib/src/components/icon/icon.ts +4 -3
  42. package/lib/src/components/image/image.module.scss +8 -1
  43. package/lib/src/components/image/image.ts +105 -6
  44. package/lib/src/components/input/input.module.scss +8 -3
  45. package/lib/src/components/input/input.ts +178 -31
  46. package/lib/src/components/keyboard/arrow-up.svg +1 -0
  47. package/lib/src/components/keyboard/delete-left.svg +1 -0
  48. package/lib/src/components/keyboard/eye-slash.svg +1 -0
  49. package/lib/src/components/keyboard/keyboard.module.scss +134 -0
  50. package/lib/src/components/keyboard/keyboard.ts +526 -0
  51. package/lib/src/components/label/label.module.scss +22 -4
  52. package/lib/src/components/label/label.ts +33 -0
  53. package/lib/src/components/link/link.ts +81 -78
  54. package/lib/src/components/listbox/listbox.module.scss +61 -3
  55. package/lib/src/components/listbox/listbox.ts +164 -56
  56. package/lib/src/components/menu/menu.module.scss +10 -1
  57. package/lib/src/components/menu/menu.ts +6 -3
  58. package/lib/src/components/messages/messages.module.scss +44 -0
  59. package/lib/src/components/messages/messages.ts +164 -18
  60. package/lib/src/components/messages/pen-field.svg +1 -0
  61. package/lib/src/components/normalize.scss +5 -0
  62. package/lib/src/components/notification/notification.module.scss +4 -2
  63. package/lib/src/components/notification/notification.ts +2 -4
  64. package/lib/src/components/panel/panel.module.scss +12 -0
  65. package/lib/src/components/popup/popup.module.scss +10 -2
  66. package/lib/src/components/popup/popup.ts +141 -95
  67. package/lib/src/components/propgrid/folder-closed.svg +1 -0
  68. package/lib/src/components/propgrid/folder-open.svg +1 -0
  69. package/lib/src/components/propgrid/progrid.module.scss +112 -0
  70. package/lib/src/components/propgrid/propgrid.ts +288 -0
  71. package/lib/src/components/propgrid/updown.svg +4 -0
  72. package/lib/src/components/radio/radio.module.scss +147 -0
  73. package/lib/src/components/radio/radio.svg +4 -0
  74. package/lib/src/components/radio/radio.ts +142 -0
  75. package/lib/src/components/select/select.module.scss +9 -0
  76. package/lib/src/components/select/select.ts +134 -0
  77. package/lib/src/components/shared.scss +47 -0
  78. package/lib/src/components/sizers/sizer.ts +10 -2
  79. package/lib/src/components/slider/slider.module.scss +77 -30
  80. package/lib/src/components/slider/slider.ts +72 -22
  81. package/lib/src/components/tabs/tabs.module.scss +1 -2
  82. package/lib/src/components/tabs/tabs.ts +49 -12
  83. package/lib/src/components/textarea/textarea.module.scss +6 -2
  84. package/lib/src/components/textarea/textarea.ts +73 -8
  85. package/lib/src/components/textedit/textedit.module.scss +3 -1
  86. package/lib/src/components/textedit/textedit.ts +47 -15
  87. package/lib/src/components/themes.scss +7 -0
  88. package/lib/src/components/tickline/tickline.module.scss +26 -0
  89. package/lib/src/components/tickline/tickline.ts +82 -0
  90. package/lib/src/components/tooltips/comments-question.svg +1 -0
  91. package/lib/src/components/tooltips/tooltips.scss +30 -9
  92. package/lib/src/components/tooltips/tooltips.ts +10 -5
  93. package/lib/src/components/treeview/treeview.module.scss +129 -60
  94. package/lib/src/components/treeview/treeview.ts +47 -12
  95. package/lib/src/components/viewport/viewport.module.scss +7 -0
  96. package/lib/src/core/component.ts +113 -40
  97. package/lib/src/core/core_application.ts +223 -2
  98. package/lib/src/core/core_colors.ts +2 -2
  99. package/lib/src/{components/grid/datastore.ts → core/core_data.ts} +264 -252
  100. package/lib/src/core/core_dragdrop.ts +3 -3
  101. package/lib/src/core/core_element.ts +18 -1
  102. package/lib/src/core/core_events.ts +28 -0
  103. package/lib/src/core/core_i18n.ts +19 -3
  104. package/lib/src/core/core_react.ts +79 -0
  105. package/lib/src/core/core_router.ts +25 -9
  106. package/lib/src/core/core_state.ts +62 -0
  107. package/lib/src/core/core_styles.ts +5 -5
  108. package/lib/src/core/core_svg.ts +174 -12
  109. package/lib/src/core/core_tools.ts +305 -87
  110. package/lib/src/x4tsx.d.ts +25 -0
  111. package/lib/styles/x4.css +1 -1
  112. package/lib/types/x4js.d.ts +828 -119
  113. package/package.json +4 -4
  114. package/scripts/build.mjs +378 -0
  115. package/scripts/prepack.mjs +346 -0
  116. package/src/components/base.scss +25 -0
  117. package/src/components/boxes/boxes.module.scss +54 -0
  118. package/src/components/boxes/boxes.ts +370 -0
  119. package/src/components/breadcrumb/breadcrumb.scss +56 -0
  120. package/src/components/breadcrumb/breadcrumb.ts +93 -0
  121. package/src/components/breadcrumb/chevron-right.svg +1 -0
  122. package/src/components/btngroup/btngroup.module.scss +41 -0
  123. package/src/components/btngroup/btngroup.ts +153 -0
  124. package/src/components/button/button.module.scss +173 -0
  125. package/src/components/button/button.ts +185 -0
  126. package/src/components/calendar/calendar-check-sharp-light.svg +1 -0
  127. package/src/components/calendar/calendar.module.scss +163 -0
  128. package/src/components/calendar/calendar.ts +327 -0
  129. package/src/components/calendar/chevron-left-sharp-light.svg +1 -0
  130. package/src/components/calendar/chevron-right-sharp-light.svg +1 -0
  131. package/src/components/canvas/canvas.module.scss +25 -0
  132. package/src/components/canvas/canvas.ts +189 -0
  133. package/src/components/canvas/canvas_ex.ts +276 -0
  134. package/src/components/checkbox/check.svg +4 -0
  135. package/src/components/checkbox/checkbox.module.scss +142 -0
  136. package/src/components/checkbox/checkbox.ts +140 -0
  137. package/src/components/colorinput/colorinput.module.scss +65 -0
  138. package/src/components/colorinput/colorinput.ts +91 -0
  139. package/src/components/colorinput/crosshairs-simple-sharp-light.svg +1 -0
  140. package/src/components/colorpicker/colorpicker.module.scss +133 -0
  141. package/src/components/colorpicker/colorpicker.ts +482 -0
  142. package/src/components/combobox/combobox.module.scss +133 -0
  143. package/src/components/combobox/combobox.ts +275 -0
  144. package/src/components/combobox/updown.svg +4 -0
  145. package/src/components/components.ts +41 -0
  146. package/src/components/dialog/dialog.module.scss +104 -0
  147. package/src/components/dialog/dialog.ts +229 -0
  148. package/src/components/dialog/xmark-sharp-light.svg +1 -0
  149. package/src/components/filedrop/cloud-arrow-up.svg +1 -0
  150. package/src/components/filedrop/filedrop.module.scss +70 -0
  151. package/src/components/filedrop/filedrop.ts +131 -0
  152. package/src/components/form/form.module.scss +38 -0
  153. package/src/components/form/form.ts +172 -0
  154. package/src/components/gridview/arrow-down-light.svg +1 -0
  155. package/src/components/gridview/arrow-up-light.svg +1 -0
  156. package/src/components/gridview/gridview.module.scss +324 -0
  157. package/src/components/gridview/gridview.ts +1175 -0
  158. package/src/components/header/header.module.scss +40 -0
  159. package/src/components/header/header.ts +130 -0
  160. package/src/components/icon/icon.module.scss +31 -0
  161. package/src/components/icon/icon.ts +137 -0
  162. package/src/components/image/image.module.scss +28 -0
  163. package/src/components/image/image.ts +168 -0
  164. package/src/components/input/input.module.scss +74 -0
  165. package/src/components/input/input.ts +422 -0
  166. package/src/components/keyboard/arrow-up.svg +1 -0
  167. package/src/components/keyboard/delete-left.svg +1 -0
  168. package/src/components/keyboard/eye-slash.svg +1 -0
  169. package/src/components/keyboard/keyboard.module.scss +134 -0
  170. package/src/components/keyboard/keyboard.ts +526 -0
  171. package/src/components/label/label.module.scss +76 -0
  172. package/src/components/label/label.ts +97 -0
  173. package/src/components/link/link.ts +81 -0
  174. package/src/components/listbox/listbox.module.scss +161 -0
  175. package/src/components/listbox/listbox.ts +539 -0
  176. package/src/components/menu/caret-right-solid.svg +1 -0
  177. package/src/components/menu/menu.module.scss +117 -0
  178. package/src/components/menu/menu.ts +174 -0
  179. package/src/components/messages/circle-exclamation.svg +1 -0
  180. package/src/components/messages/messages.module.scss +92 -0
  181. package/src/components/messages/messages.ts +215 -0
  182. package/src/components/messages/pen-field.svg +1 -0
  183. package/src/components/normalize.scss +391 -0
  184. package/src/components/notification/circle-check-solid.svg +1 -0
  185. package/src/components/notification/circle-exclamation-solid.svg +1 -0
  186. package/src/components/notification/circle-notch-light.svg +1 -0
  187. package/src/components/notification/notification.module.scss +84 -0
  188. package/src/components/notification/notification.ts +107 -0
  189. package/src/components/notification/xmark-sharp-light.svg +1 -0
  190. package/src/components/panel/panel.module.scss +60 -0
  191. package/src/components/panel/panel.ts +58 -0
  192. package/src/components/popup/popup.module.scss +51 -0
  193. package/src/components/popup/popup.ts +442 -0
  194. package/src/components/progress/progress.module.scss +57 -0
  195. package/src/components/progress/progress.ts +44 -0
  196. package/src/components/propgrid/folder-closed.svg +1 -0
  197. package/src/components/propgrid/folder-open.svg +1 -0
  198. package/src/components/propgrid/progrid.module.scss +112 -0
  199. package/src/components/propgrid/propgrid.ts +288 -0
  200. package/src/components/propgrid/updown.svg +4 -0
  201. package/src/components/radio/radio.module.scss +147 -0
  202. package/src/components/radio/radio.svg +4 -0
  203. package/src/components/radio/radio.ts +142 -0
  204. package/src/components/rating/rating.module.scss +23 -0
  205. package/src/components/rating/rating.ts +131 -0
  206. package/src/components/rating/star-sharp-light.svg +1 -0
  207. package/src/components/rating/star-sharp-solid.svg +1 -0
  208. package/src/components/select/select.module.scss +9 -0
  209. package/src/components/select/select.ts +134 -0
  210. package/src/components/shared.scss +137 -0
  211. package/src/components/sizers/sizer.module.scss +90 -0
  212. package/src/components/sizers/sizer.ts +132 -0
  213. package/src/components/slider/slider.module.scss +118 -0
  214. package/src/components/slider/slider.ts +198 -0
  215. package/src/components/switch/switch.module.scss +127 -0
  216. package/src/components/switch/switch.ts +62 -0
  217. package/src/components/tabs/tabs.module.scss +45 -0
  218. package/src/components/tabs/tabs.ts +205 -0
  219. package/src/components/textarea/textarea.module.scss +63 -0
  220. package/src/components/textarea/textarea.ts +125 -0
  221. package/src/components/textedit/textedit.module.scss +116 -0
  222. package/src/components/textedit/textedit.ts +115 -0
  223. package/src/components/themes.scss +88 -0
  224. package/src/components/tickline/tickline.module.scss +26 -0
  225. package/src/components/tickline/tickline.ts +82 -0
  226. package/src/components/tooltips/circle-info-sharp-light.svg +1 -0
  227. package/src/components/tooltips/comments-question.svg +1 -0
  228. package/src/components/tooltips/tooltips.scss +72 -0
  229. package/src/components/tooltips/tooltips.ts +109 -0
  230. package/src/components/treeview/chevron-down-light.svg +1 -0
  231. package/src/components/treeview/treeview.module.scss +185 -0
  232. package/src/components/treeview/treeview.ts +445 -0
  233. package/src/components/viewport/viewport.module.scss +32 -0
  234. package/src/components/viewport/viewport.ts +41 -0
  235. package/src/core/component.ts +1075 -0
  236. package/src/core/core_application.ts +265 -0
  237. package/src/core/core_colors.ts +250 -0
  238. package/src/core/core_data.ts +1310 -0
  239. package/src/core/core_dom.ts +471 -0
  240. package/src/core/core_dragdrop.ts +201 -0
  241. package/src/core/core_element.ts +115 -0
  242. package/src/core/core_events.ts +177 -0
  243. package/src/core/core_i18n.ts +393 -0
  244. package/src/core/core_react.ts +79 -0
  245. package/src/core/core_router.ts +237 -0
  246. package/src/core/core_state.ts +62 -0
  247. package/src/core/core_styles.ts +214 -0
  248. package/src/core/core_svg.ts +712 -0
  249. package/src/core/core_tools.ts +906 -0
  250. package/src/types/scss.d.ts +4 -0
  251. package/src/types/svg.d.ts +1 -0
  252. package/src/types/x4react.d.ts +9 -0
  253. package/src/x4.scss +19 -0
  254. package/src/x4tsx.d.ts +25 -0
  255. package/tsconfig.json +14 -0
  256. package/lib/src/components/grid/gridview.ts +0 -1108
  257. package/lib/src/components/grid/memdb.ts +0 -325
  258. /package/{lib/src/demo → demo}/assets/house-light.svg +0 -0
  259. /package/{lib/src/demo → demo}/assets/radio.svg +0 -0
  260. /package/{lib/src/demo → demo}/index.html +0 -0
@@ -0,0 +1,276 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file canvas_ex.ts
9
+ * @author Etienne Cochard
10
+ *
11
+ * @copyright (c) 2025 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 { Point } from "../../core/core_tools"
18
+
19
+ export interface CanvasEx extends CanvasRenderingContext2D {
20
+ width: number;
21
+ height: number;
22
+
23
+ smoothLine(points: any[], path: CanvasPath, move: boolean): void;
24
+ smoothLineEx(_points: any[], tension: number, numOfSeg: number, path: CanvasPath, move?: boolean, close?: boolean): void;
25
+ line(x1: number, y1: number, x2: number, y2: number, color: string, lineWidth: number): void;
26
+ roundRect(x: number, y: number, width: number, height: number, radius: number): void;
27
+ calcTextSize(text: string, rounded: boolean): { width: number, height: number };
28
+ setFontSize(fs: number): void;
29
+ circle(x: number, y: number, radius: number): void;
30
+ }
31
+
32
+ export function createPainter(c2d: CanvasRenderingContext2D, w: number, h: number): CanvasEx {
33
+
34
+ let cp = c2d as CanvasEx;
35
+
36
+ cp.width = w;
37
+ cp.height = h;
38
+
39
+ cp.smoothLine = smoothLine;
40
+ cp.smoothLineEx = smoothLineEx;
41
+ cp.line = line;
42
+ cp.roundRect = roundRect;
43
+ cp.calcTextSize = calcTextSize;
44
+ cp.setFontSize = setFontSize;
45
+ cp.circle = circle;
46
+
47
+ return cp;
48
+ }
49
+
50
+ /**
51
+ *
52
+ */
53
+
54
+ function smoothLine( this: CanvasRenderingContext2D, points: any[], path: CanvasPath = null, move = true) {
55
+ if (points.length < 2) {
56
+ return;
57
+ }
58
+
59
+ if (!path) {
60
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
61
+ path = this;
62
+ }
63
+
64
+ if (points.length == 2) {
65
+ if (move !== false) {
66
+ path.moveTo(points[0].x, points[0].y);
67
+ }
68
+ else {
69
+ path.lineTo(points[0].x, points[0].y);
70
+ }
71
+
72
+ path.lineTo(points[1].x, points[1].y);
73
+ return;
74
+ }
75
+
76
+ function midPointBtw(p1: Point, p2: Point ) {
77
+ return {
78
+ x: p1.x + (p2.x - p1.x) / 2,
79
+ y: p1.y + (p2.y - p1.y) / 2
80
+ };
81
+ }
82
+
83
+ function getQuadraticXY(t: number, sx: number, sy: number, cp1x: number, cp1y: number, ex: number, ey: number) : Point {
84
+ return {
85
+ x: (1 - t) * (1 - t) * sx + 2 * (1 - t) * t * cp1x + t * t * ex,
86
+ y: (1 - t) * (1 - t) * sy + 2 * (1 - t) * t * cp1y + t * t * ey
87
+ };
88
+ }
89
+
90
+ let p1 = points[0],
91
+ p2 = points[1],
92
+ p3 = p1;
93
+
94
+ path.moveTo(p1.x, p1.y);
95
+
96
+ for (let i = 1, len = points.length; i < len; i++) {
97
+ // we pick the point between pi+1 & pi+2 as the
98
+ // end point and p1 as our control point
99
+ let midPoint = midPointBtw(p1, p2);
100
+ //this.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);
101
+ for (let i = 0; i < 8; i++) {
102
+ let { x, y } = getQuadraticXY(i / 8, p3.x, p3.y, p1.x, p1.y, midPoint.x, midPoint.y);
103
+ path.lineTo(x, y);
104
+ }
105
+
106
+ p1 = points[i];
107
+ p2 = points[i + 1];
108
+ p3 = midPoint;
109
+ }
110
+
111
+ // Draw last line as a straight line while
112
+ // we wait for the next point to be able to calculate
113
+ // the bezier control point
114
+
115
+ path.lineTo(p1.x, p1.y);
116
+ }
117
+
118
+ function smoothLineEx(this: CanvasRenderingContext2D, _points: any[], tension: number = 0.5, numOfSeg: number = 10, path: CanvasPath = null, move = true, close = false) {
119
+
120
+ let points = [];
121
+
122
+ //pts = points.slice(0);
123
+ for (let p = 0, pc = _points.length; p < pc; p++) {
124
+ points.push(_points[p].x);
125
+ points.push(_points[p].y);
126
+ }
127
+
128
+ let pts,
129
+ i = 1,
130
+ l = points.length,
131
+ rPos = 0,
132
+ rLen = (l - 2) * numOfSeg + 2 + (close ? 2 * numOfSeg : 0),
133
+ res = new Float32Array(rLen),
134
+ cache = new Float32Array((numOfSeg + 2) * 4),
135
+ cachePtr = 4;
136
+
137
+ pts = points.slice(0);
138
+
139
+ if (close) {
140
+ pts.unshift(points[l - 1]); // insert end point as first point
141
+ pts.unshift(points[l - 2]);
142
+ pts.push(points[0], points[1]); // first point as last point
143
+ }
144
+ else {
145
+ pts.unshift(points[1]); // copy 1. point and insert at beginning
146
+ pts.unshift(points[0]);
147
+ pts.push(points[l - 2], points[l - 1]); // duplicate end-points
148
+ }
149
+
150
+ // cache inner-loop calculations as they are based on t alone
151
+ cache[0] = 1; // 1,0,0,0
152
+
153
+ for (; i < numOfSeg; i++) {
154
+
155
+ const st = i / numOfSeg,
156
+ st2 = st * st,
157
+ st3 = st2 * st,
158
+ st23 = st3 * 2,
159
+ st32 = st2 * 3;
160
+
161
+ cache[cachePtr++] = st23 - st32 + 1; // c1
162
+ cache[cachePtr++] = st32 - st23; // c2
163
+ cache[cachePtr++] = st3 - 2 * st2 + st; // c3
164
+ cache[cachePtr++] = st3 - st2; // c4
165
+ }
166
+
167
+ cache[cachePtr] = 1; // 0,1,0,0
168
+
169
+ // calc. points
170
+ parse(pts, cache, l);
171
+
172
+ if (close) {
173
+ //l = points.length;
174
+ pts = [];
175
+ pts.push(points[l - 4], points[l - 3], points[l - 2], points[l - 1]); // second last and last
176
+ pts.push(points[0], points[1], points[2], points[3]); // first and second
177
+ parse(pts, cache, 4);
178
+ }
179
+
180
+ function parse(pts: number[], cache: Float32Array, l: number) {
181
+
182
+ for (let i = 2, t; i < l; i += 2) {
183
+
184
+ let pt1 = pts[i],
185
+ pt2 = pts[i + 1],
186
+ pt3 = pts[i + 2],
187
+ pt4 = pts[i + 3],
188
+
189
+ t1x = (pt3 - pts[i - 2]) * tension,
190
+ t1y = (pt4 - pts[i - 1]) * tension,
191
+ t2x = (pts[i + 4] - pt1) * tension,
192
+ t2y = (pts[i + 5] - pt2) * tension;
193
+
194
+ for (t = 0; t < numOfSeg; t++) {
195
+
196
+ let c = t << 2, //t * 4;
197
+
198
+ c1 = cache[c],
199
+ c2 = cache[c + 1],
200
+ c3 = cache[c + 2],
201
+ c4 = cache[c + 3];
202
+
203
+ res[rPos++] = c1 * pt1 + c2 * pt3 + c3 * t1x + c4 * t2x;
204
+ res[rPos++] = c1 * pt2 + c2 * pt4 + c3 * t1y + c4 * t2y;
205
+ }
206
+ }
207
+ }
208
+
209
+ // add last point
210
+ l = close ? 0 : points.length - 2;
211
+ res[rPos++] = points[l];
212
+ res[rPos] = points[l + 1];
213
+
214
+ if (!path) {
215
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
216
+ path = this;
217
+ }
218
+
219
+ // add lines to path
220
+ for (let i = 0, l = res.length; i < l; i += 2) {
221
+ if (i == 0 && move !== false) {
222
+ path.moveTo(res[i], res[i + 1]);
223
+ }
224
+ else {
225
+ path.lineTo(res[i], res[i + 1]);
226
+ }
227
+ }
228
+ }
229
+
230
+ function line(this: CanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: string, lineWidth: number = 1) {
231
+ this.save();
232
+ this.beginPath();
233
+ this.moveTo(x1, y1);
234
+ this.lineTo(x2, y2);
235
+ this.lineWidth = lineWidth;
236
+ this.strokeStyle = color;
237
+ this.stroke();
238
+ this.restore();
239
+ }
240
+
241
+ function roundRect(this: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number) {
242
+ //this.beginPath( );
243
+ this.moveTo(x + radius, y);
244
+ this.lineTo(x + width - radius, y);
245
+ this.quadraticCurveTo(x + width, y, x + width, y + radius);
246
+ this.lineTo(x + width, y + height - radius);
247
+ this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
248
+ this.lineTo(x + radius, y + height);
249
+ this.quadraticCurveTo(x, y + height, x, y + height - radius);
250
+ this.lineTo(x, y + radius);
251
+ this.quadraticCurveTo(x, y, x + radius, y);
252
+ this.closePath();
253
+ }
254
+
255
+ function calcTextSize( this: CanvasRenderingContext2D, text: string, rounded = false): { width: number, height: number } {
256
+
257
+ let fh = this.measureText(text);
258
+ let lh = fh.fontBoundingBoxAscent + fh.fontBoundingBoxDescent;
259
+
260
+ if (rounded) {
261
+ return { width: Math.round(fh.width), height: Math.round(lh) };
262
+ }
263
+ else {
264
+ return { width: fh.width, height: lh };
265
+ }
266
+ }
267
+
268
+ function setFontSize( this: CanvasRenderingContext2D, fs: number) {
269
+ let fsize = Math.round(fs) + 'px';
270
+ this.font = this.font.replace(/\d+px/, fsize);
271
+ }
272
+
273
+ function circle( this: CanvasRenderingContext2D, x: number, y: number, radius: number) {
274
+ this.moveTo(x + radius, y);
275
+ this.arc(x, y, radius, 0, Math.PI * 2);
276
+ }
@@ -26,6 +26,7 @@ interface CheckboxProps extends ComponentProps {
26
26
  label: string; // The text label for the checkbox.
27
27
  checked?: boolean; // Optional boolean indicating if the checkbox is checked by default.
28
28
  value?: boolean | number | string; // Optional value associated with the checkbox.
29
+ name?: string;
29
30
  change?: EventCallback<EvChange>;
30
31
  }
31
32
 
@@ -59,6 +60,7 @@ export class Checkbox extends Component<CheckboxProps,CheckBoxEvents> {
59
60
  this._input = new Input( {
60
61
  type:"checkbox",
61
62
  id: inputId,
63
+ name: props.name,
62
64
  checked: props.checked,
63
65
  dom_events: {
64
66
  change: ( ) => this._on_change( ),
@@ -77,6 +79,20 @@ export class Checkbox extends Component<CheckboxProps,CheckBoxEvents> {
77
79
  svgLoader.load( icon ).then( svg => {
78
80
  this.query<Label>( '.inner' ).dom.insertAdjacentHTML( "beforeend", svg );
79
81
  });
82
+
83
+ this.addDOMEvent('click', (e) => this._on_click(e)); // for outside click
84
+ }
85
+
86
+ /**
87
+ * handle click outside label & input
88
+ */
89
+
90
+ protected _on_click( ev: MouseEvent ) {
91
+ if( ev.target==this.dom ) {
92
+ (this._input.dom as HTMLInputElement).click( );
93
+ ev.preventDefault();
94
+ ev.stopPropagation();
95
+ }
80
96
  }
81
97
 
82
98
  /**
@@ -92,8 +108,7 @@ export class Checkbox extends Component<CheckboxProps,CheckBoxEvents> {
92
108
  */
93
109
 
94
110
  public getCheck() {
95
- const d = this._input.dom as HTMLInputElement;
96
- return d.checked;
111
+ return this._input.getCheck();
97
112
  }
98
113
 
99
114
  /**
@@ -102,8 +117,7 @@ export class Checkbox extends Component<CheckboxProps,CheckBoxEvents> {
102
117
  */
103
118
 
104
119
  public setCheck(ck: boolean) {
105
- const d = this._input.dom as HTMLInputElement;
106
- d.checked = ck;
120
+ this._input.setCheck( ck );
107
121
  }
108
122
 
109
123
  /**
@@ -28,7 +28,7 @@
28
28
  --combobox-btn-color-hover: var( --text-primary );
29
29
  }
30
30
 
31
- .x4dropdown {
31
+ .x4dropdownlist {
32
32
  @extend .shadow-xl;
33
33
  @extend .hbox;
34
34
 
@@ -44,35 +44,42 @@
44
44
  margin: 0;
45
45
  width: 100%;
46
46
  height: 200px;
47
+
48
+ .x4item {
49
+ white-space: nowrap;
50
+ }
47
51
  }
48
52
  }
49
53
 
50
54
  .x4combobox {
51
55
  @extend .hbox;
52
56
  margin: 5px;
57
+ gap: 6px;
53
58
 
54
- //&> #label {
55
- // padding: 0 6px;
56
- // border-bottom: 1px solid transparent;
57
-
59
+ &> #label {
60
+
58
61
  &> .x4label {
59
- padding: 0 6px;
62
+ padding: 0 6px 0 0;
60
63
  border-bottom: 1px solid transparent;
61
64
 
62
65
  height: 100%;
63
- padding: 0;
64
66
  font-weight: 500;
65
- gap: 0;
67
+ gap: 0px;
66
68
 
67
- #text::not(.empty)::after {
68
- content: ":"
69
+ #text:not(.empty) {
70
+ &::after {
71
+ content: ":"
72
+ }
69
73
  }
70
74
  }
71
- //}
75
+ }
72
76
 
73
77
  &>#edit {
74
78
  @extend .flex;
75
79
  border-bottom: 1px solid var( --combobox-border );
80
+ &:focus-within {
81
+ border-bottom-color: var( --combobox-border-focus );
82
+ }
76
83
 
77
84
  .x4input {
78
85
  @extend .flex;
@@ -97,10 +104,10 @@
97
104
  color: var( --combobox-btn-color-hover );
98
105
  }
99
106
 
100
- &:focus {
107
+ //&:focus {
101
108
  //background-color: var( --color-30 );
102
109
  //color: var( --color-10 );
103
- }
110
+ //}
104
111
  }
105
112
  }
106
113
 
@@ -116,9 +123,11 @@
116
123
  }
117
124
 
118
125
  &[required] {
119
- .x4label::before {
126
+ & > #label > .x4label::before {
120
127
  content: "*";
121
- color: var( --color-90 )
128
+ font-weight: bold;
129
+ color: var( --textedit-required );
130
+ margin-right: 2px;
122
131
  }
123
132
  }
124
133
  }
@@ -14,8 +14,11 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { Component, ComponentEvent, ComponentProps, EvChange, EvSelectionChange, makeUniqueComponentId } from '../../core/component';
18
- import { Listbox, ListboxID, ListItem, kbNav } from '../listbox/listbox';
17
+ import { Component, ComponentEvents, ComponentProps, EvSelectionChange, makeUniqueComponentId } from '../../core/component';
18
+ import { class_ns, IComponentInterface, IFormElement, kbNav } from '@core/core_tools';
19
+ import { EventCallback } from '@core/core_events';
20
+
21
+ import { Listbox, ListboxID, ListItem } from '../listbox/listbox';
19
22
  import { Popup, PopupEvents, PopupProps } from '../popup/popup.js';
20
23
  import { Label } from '../label/label';
21
24
  import { Input } from '../input/input';
@@ -24,7 +27,6 @@ import { HBox } from '../boxes/boxes';
24
27
 
25
28
  import "./combobox.module.scss";
26
29
  import icon from "./updown.svg";
27
- import { class_ns } from '@core/core_tools.js';
28
30
 
29
31
 
30
32
 
@@ -37,8 +39,9 @@ interface DropdownProps extends Omit<PopupProps,"content"> {
37
39
  items: ListItem[];
38
40
  }
39
41
 
42
+
40
43
  @class_ns( "x4" )
41
- class Dropdown extends Popup<DropdownProps,DropdownEvents> {
44
+ export class DropdownList extends Popup<DropdownProps,DropdownEvents> {
42
45
 
43
46
  private _list: Listbox;
44
47
 
@@ -70,18 +73,26 @@ class Dropdown extends Popup<DropdownProps,DropdownEvents> {
70
73
  *
71
74
  */
72
75
 
76
+ interface ComboboxEvents extends ComponentEvents {
77
+ selectionChange: EvSelectionChange;
78
+ }
79
+
73
80
  interface ComboboxProps extends Omit<ComponentProps,"content"> {
74
81
  label?: string;
82
+ name?: string;
83
+ value?: string;
75
84
  labelWidth?: number | string;
76
85
  readonly?: boolean;
86
+ required?: boolean;
77
87
  items: ListItem[];
88
+ selectionChange?: EventCallback<EvSelectionChange>,
78
89
  }
79
90
 
80
91
  @class_ns( "x4" )
81
- export class Combobox extends Component<ComboboxProps> {
92
+ export class Combobox extends Component<ComboboxProps,ComboboxEvents> {
82
93
 
83
- private _dropdown: Dropdown;
84
- private _label: Label;
94
+ private _popup: DropdownList;
95
+ //private _label: Label;
85
96
  private _input: Input;
86
97
  private _button: Button;
87
98
  private _prevent_close = false;
@@ -92,25 +103,53 @@ export class Combobox extends Component<ComboboxProps> {
92
103
 
93
104
  const id = makeUniqueComponentId( );
94
105
 
106
+ this.mapPropEvents( props, "selectionChange" );
107
+
108
+ const readonly = props.readonly===false ? false : true; // by default
109
+
95
110
  this.setContent( [
96
111
  new HBox( { id: "label", content: new Label( { tag: "label", text: props.label, labelFor: id, width: props.labelWidth } ) } ),
97
112
  this._edit = new HBox( { id: "edit", content: [
98
- this._input = new Input( { type: "text", value: "", readonly: props.readonly }),
99
- this._button = new Button( { icon: icon } )
113
+ this._input = new Input( { id, type: "text", value: "", readonly: readonly, required: props.required }),
114
+ this._button = new Button( { icon: icon, tabindex: -1 } )
100
115
  ]} ),
101
116
  ])
102
117
 
103
- this._dropdown = new Dropdown( { items: props.items } );
118
+ if( props.name ) {
119
+ this.setAttribute( "name", props.name );
120
+ }
121
+
122
+ if( props.required ) {
123
+ this.setAttribute( "required", true );
124
+ }
125
+
126
+ this._popup = new DropdownList( { items: props.items } );
127
+ const list = this._popup.getList( );
128
+
129
+ const _select = ( sel: ListboxID ) => {
130
+ const itm = list.getItem(sel);
104
131
 
105
- this._dropdown.on( "selectionChange", ( ev ) => {
106
- const sel = ev.selection as ListItem;
107
- this._input.setValue( sel ? sel.text : "" );
132
+ //TODO: unsafehtml
133
+ //@ts-ignore
134
+ this._input.setValue( itm ? itm.text : "" );
108
135
 
109
136
  if( !this._prevent_close ) {
110
- this._dropdown.show( false );
137
+ this._popup.show( false );
138
+ }
139
+ }
140
+
141
+ this._popup.on( "selectionChange", ( ev ) => {
142
+ const [sel] = ev.selection as ListboxID[];
143
+ if( sel!==undefined ) { // no empty sel
144
+ _select( sel );
145
+ this.fire( "selectionChange", ev );
111
146
  }
112
147
  });
113
148
 
149
+ if( props.value ) {
150
+ _select( props.value );
151
+ }
152
+
114
153
  this._button.addDOMEvent( "click", ( ) => this._on_click( ) );
115
154
  this._input.addDOMEvent( "input", ( ) => this._on_input( ) );
116
155
  this._input.addDOMEvent( "keydown", ( ev ) => this._on_key( ev ) );
@@ -125,17 +164,17 @@ export class Combobox extends Component<ComboboxProps> {
125
164
  switch( ev.key ) {
126
165
  case "Enter":
127
166
  case "Escape": {
128
- this._dropdown.show( false );
167
+ this._popup.show( false );
129
168
  break;
130
169
  }
131
170
 
132
171
  case "ArrowUp":
133
172
  this._prevent_close = true;
134
- if( !this._dropdown.isOpen( ) ) {
173
+ if( !this._popup.isOpen( ) ) {
135
174
  this.showDropDown( );
136
175
  }
137
176
  else {
138
- this._dropdown.getList().navigate( kbNav.prev );
177
+ this._popup.getList().navigate( kbNav.prev );
139
178
  }
140
179
 
141
180
  this._prevent_close = false;
@@ -143,11 +182,11 @@ export class Combobox extends Component<ComboboxProps> {
143
182
 
144
183
  case "ArrowDown":
145
184
  this._prevent_close = true;
146
- if( !this._dropdown.isOpen( ) ) {
185
+ if( !this._popup.isOpen( ) ) {
147
186
  this.showDropDown( );
148
187
  }
149
188
  else {
150
- this._dropdown.getList().navigate( kbNav.next );
189
+ this._popup.getList().navigate( kbNav.next );
151
190
  }
152
191
 
153
192
  this._prevent_close = false;
@@ -163,15 +202,15 @@ export class Combobox extends Component<ComboboxProps> {
163
202
  }
164
203
 
165
204
  private _on_input( ) {
166
- if( !this._dropdown.isOpen( ) ) {
205
+ if( !this._popup.isOpen( ) ) {
167
206
  this.showDropDown( );
168
207
  }
169
208
 
170
- this._dropdown.getList().filter( this._input.getValue( ) );
209
+ this._popup.getList().filter( this._input.getValue( ) );
171
210
  }
172
211
 
173
212
  private _on_focusout( ) {
174
- this._dropdown.show( false );
213
+ this._popup.show( false );
175
214
  }
176
215
 
177
216
  private _on_click( ) {
@@ -184,8 +223,52 @@ export class Combobox extends Component<ComboboxProps> {
184
223
  }
185
224
 
186
225
  const rc = this._edit.getBoundingRect( );
187
- this._dropdown.setStyleValue( "width", rc.width+"px" );
188
- this._dropdown.displayNear( rc, "top left", "bottom left", {x:0,y:6} );
226
+ this._popup.setStyleValue( "minWidth", rc.width+"px" );
227
+ this._popup.displayNear( rc, "top left", "bottom left", {x:0,y:6} );
228
+ }
229
+
230
+ setItems( items: ListItem[] ) {
231
+ this._getList().setItems( items );
232
+ }
233
+
234
+ getValue( ) {
235
+ return this._input.getValue( );
236
+ }
237
+
238
+ setValue( value: string ) {
239
+ this._input.setValue( value );
240
+ }
241
+
242
+ selectItem( index: ListboxID ) {
243
+ this._getList( ).select( index );
244
+ }
245
+
246
+ getSelection( ) {
247
+ const [sel] = this._getList( ).getSelection( );
248
+ return sel;
249
+ }
250
+
251
+ private _getList( ) {
252
+ return this._popup.getList( );
253
+ }
254
+
255
+ /**
256
+ *
257
+ */
258
+
259
+ override queryInterface<T extends IComponentInterface>( name: string ): T {
260
+ if( name=="form-element" ) {
261
+ const i: IFormElement = {
262
+ getRawValue: ( ): any => { return this.getSelection(); },
263
+ setRawValue: ( v: any ) => { this.selectItem(v); },
264
+ isValid: ( ) => { return this._input.isValid(); }
265
+ };
266
+
267
+ //@ts-ignore
268
+ return i as T;
269
+ }
270
+
271
+ return super.queryInterface( name );
189
272
  }
190
273
  }
191
274
 
@@ -8,11 +8,14 @@ export * from "./colorinput/colorinput"
8
8
  export * from "./colorpicker/colorpicker"
9
9
  export * from "./combobox/combobox"
10
10
  export * from "./dialog/dialog"
11
+ export * from "./filedrop/filedrop"
11
12
  export * from "./form/form"
13
+ export * from "./gridview/gridview"
12
14
  export * from "./header/header"
13
15
  export * from "./icon/icon"
14
16
  export * from "./image/image"
15
17
  export * from "./input/input"
18
+ export * from "./keyboard/keyboard"
16
19
  export * from "./label/label"
17
20
  export * from "./link/link"
18
21
  export * from "./listbox/listbox"
@@ -22,7 +25,11 @@ export * from "./notification/notification"
22
25
  export * from "./panel/panel"
23
26
  export * from "./popup/popup"
24
27
  export * from "./progress/progress"
28
+ export * from "./propgrid/propgrid"
29
+ export * from "./radio/radio"
25
30
  export * from "./rating/rating"
31
+ export * from "./tickline/tickline"
32
+ export * from "./select/select"
26
33
  export * from "./sizers/sizer"
27
34
  export * from "./slider/slider"
28
35
  export * from "./switch/switch"