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
@@ -27,7 +27,7 @@ export function isString(val: any): val is string {
27
27
  * @returns true if object is a number
28
28
  */
29
29
 
30
- export function isNumber( v: any ): v is number {
30
+ export function isNumber(v: any): v is number {
31
31
  return typeof v === 'number' && isFinite(v);
32
32
  }
33
33
 
@@ -63,22 +63,29 @@ export type Constructor<P> = {
63
63
  */
64
64
 
65
65
  export class UnsafeHtml extends String {
66
- constructor( value: string ) {
67
- super( value );
66
+ constructor(value: string) {
67
+ super(value);
68
68
  }
69
69
  }
70
70
 
71
- export function unsafeHtml( x: string ): UnsafeHtml {
72
- return new UnsafeHtml( x );
71
+ export function unsafeHtml(x: string): UnsafeHtml {
72
+ return new UnsafeHtml(x);
73
+ }
74
+
75
+ export function unsafe(strings: TemplateStringsArray, ...values: any[]): UnsafeHtml {
76
+ const result = strings.reduce((acc, str, i) => {
77
+ return acc + str + (values[i] || '');
78
+ }, '');
79
+ return unsafeHtml(result);
73
80
  }
74
81
 
75
82
  /**
76
83
  *
77
84
  */
78
85
 
79
- export function clamp<T>( v: T, min: T, max: T ) : T {
80
- if( v<min ) { return min; }
81
- if( v>max ) { return max; }
86
+ export function clamp<T>(v: T, min: T, max: T): T {
87
+ if (v < min) { return min; }
88
+ if (v > max) { return max; }
82
89
  return v;
83
90
  }
84
91
 
@@ -89,9 +96,9 @@ export function clamp<T>( v: T, min: T, max: T ) : T {
89
96
 
90
97
  export interface IRect {
91
98
  left: number;
92
- top: number;
93
- height: number;
94
- width: number;
99
+ top: number;
100
+ height: number;
101
+ width: number;
95
102
  }
96
103
 
97
104
  /**
@@ -104,35 +111,81 @@ export class Rect implements IRect {
104
111
  height: number;
105
112
  width: number;
106
113
 
107
- constructor( );
108
- constructor( l: number, t: number, w: number, h: number );
109
- constructor( l: Rect );
110
- constructor( l?: number | IRect, t?: number, w?: number, h?: number ) {
111
- if( l!==undefined ) {
112
- if( isNumber( l ) ) {
114
+ constructor();
115
+ constructor(l: number, t: number, w: number, h: number);
116
+ constructor(l: Rect);
117
+ constructor(l?: number | IRect, t?: number, w?: number, h?: number) {
118
+ if (l !== undefined) {
119
+ if (isNumber(l)) {
113
120
  this.left = l;
114
121
  this.top = t;
115
122
  this.width = w;
116
123
  this.height = h;
117
124
  }
118
125
  else {
119
- Object.assign( this, l );
126
+ Object.assign(this, l);
120
127
  }
121
128
  }
122
129
  }
123
-
124
- get right( ) {
125
- return this.left+this.width;
130
+
131
+ get right() {
132
+ return this.left + this.width;
133
+ }
134
+
135
+ get bottom() {
136
+ return this.top + this.height;
126
137
  }
127
138
 
128
- get bottom( ) {
129
- return this.top+this.height;
139
+ contains(pt: Point): boolean;
140
+ contains(rc: Rect): boolean;
141
+ contains(arg: any): boolean {
142
+ if (arg instanceof Rect) {
143
+ return arg.left >= this.left && arg.right <= this.right && arg.top >= this.top && arg.bottom <= this.bottom;
144
+ }
145
+ else {
146
+ return arg.x >= this.left && arg.x < this.right && arg.y >= this.top && arg.y < this.bottom;
147
+ }
130
148
  }
149
+
150
+ touches(rc: Rect): boolean {
151
+ if (this.left > rc.right || this.right < rc.left || this.top > rc.bottom || this.bottom < rc.top) {
152
+ return false;
153
+ }
154
+
155
+ return true;
156
+ }
157
+
158
+ normalize(): this {
159
+ let w = this.width,
160
+ h = this.height;
161
+
162
+ if (w < 0) {
163
+ this.left += w;
164
+ this.width = -w;
165
+ }
166
+
167
+ if (h < 0) {
168
+ this.top += h;
169
+ this.height = -h;
170
+ }
171
+
172
+ return this;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * generic size
178
+ */
179
+
180
+ export interface Size {
181
+ w: number;
182
+ h: number;
131
183
  }
132
184
 
133
185
 
134
186
  /**
135
- * generic Point
187
+ * generic Point
188
+ * TODO: IPoint
136
189
  */
137
190
 
138
191
  export interface Point {
@@ -140,8 +193,58 @@ export interface Point {
140
193
  y: number;
141
194
  }
142
195
 
196
+
143
197
  /**
144
- *
198
+ * generic Size
199
+ * TODO: ISize
200
+ */
201
+
202
+ export interface Size {
203
+ w: number;
204
+ h: number;
205
+ }
206
+
207
+ /**
208
+ * center one rect inside another
209
+ */
210
+
211
+
212
+ export function centerRect(innerRect: IRect, outerRect: IRect, margin: number = 0): IRect {
213
+
214
+ const owidth = outerRect.width - 2 * margin;
215
+ const oheight = outerRect.height - 2 * margin;
216
+
217
+ const ratio = innerRect.width / innerRect.height;
218
+
219
+ let nwidth = owidth;
220
+ let nheight = owidth / ratio;
221
+
222
+ if (nheight > oheight) {
223
+ nheight = oheight;
224
+ nwidth = oheight * ratio;
225
+ }
226
+
227
+ const newLeft = outerRect.left + (outerRect.width - nwidth) / 2;
228
+ const newTop = outerRect.top + (outerRect.height - nheight) / 2;
229
+
230
+ return { left: newLeft, top: newTop, width: nwidth, height: nheight };
231
+ }
232
+
233
+
234
+
235
+
236
+
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+
246
+ /**
247
+ * @see queryInterface
145
248
  */
146
249
 
147
250
  export interface IComponentInterface {
@@ -149,8 +252,19 @@ export interface IComponentInterface {
149
252
 
150
253
  // form-element
151
254
  export interface IFormElement extends IComponentInterface {
152
- getRawValue( ): any;
153
- setRawValue( v: any ): void;
255
+ getRawValue(): any;
256
+ setRawValue(v: any): void;
257
+ isValid(): boolean;
258
+ }
259
+
260
+ // tab-handler
261
+ export interface ITabHandler extends IComponentInterface {
262
+ focusNext(next: boolean): boolean; // return true to stop event
263
+ }
264
+
265
+ // tip-handler
266
+ export interface ITipHandler extends IComponentInterface {
267
+ getTip(): string;
154
268
  }
155
269
 
156
270
  /**
@@ -161,8 +275,8 @@ interface Features {
161
275
  eyedropper: 1,
162
276
  }
163
277
 
164
- export function isFeatureAvailable( name: keyof Features ): boolean {
165
- switch( name ) {
278
+ export function isFeatureAvailable(name: keyof Features): boolean {
279
+ switch (name) {
166
280
  case "eyedropper": return "EyeDropper" in window;
167
281
  }
168
282
 
@@ -170,31 +284,31 @@ export function isFeatureAvailable( name: keyof Features ): boolean {
170
284
  }
171
285
 
172
286
  export class Timer {
173
-
174
- protected _timers: Map<string,any>;
175
-
287
+
288
+ protected _timers: Map<string, any>;
289
+
176
290
  /**
177
291
  *
178
292
  */
179
293
 
180
- setTimeout( name: string, time: number, callback: Function ) {
181
- if( !this._timers ) {
182
- this._timers = new Map( );
294
+ setTimeout(name: string, time: number, callback: Function) {
295
+ if (!this._timers) {
296
+ this._timers = new Map();
183
297
  }
184
298
  else {
185
- this.clearTimeout( name );
299
+ this.clearTimeout(name);
186
300
  }
187
301
 
188
- const tm = setTimeout( callback, time );
189
- this._timers.set( name, tm );
302
+ const tm = setTimeout(callback, time);
303
+ this._timers.set(name, tm);
190
304
 
191
305
  return tm;
192
306
  }
193
307
 
194
- clearTimeout( name: string ) {
195
- if( this._timers && this._timers.has(name) ) {
196
- clearTimeout( this._timers.get(name) );
197
- this._timers.delete( name );
308
+ clearTimeout(name: string) {
309
+ if (this._timers && this._timers.has(name)) {
310
+ clearTimeout(this._timers.get(name));
311
+ this._timers.delete(name);
198
312
  }
199
313
  }
200
314
 
@@ -202,31 +316,31 @@ export class Timer {
202
316
  *
203
317
  */
204
318
 
205
- setInterval( name: string, time: number, callback: Function ) {
206
- if( !this._timers ) {
207
- this._timers = new Map( );
319
+ setInterval(name: string, time: number, callback: Function) {
320
+ if (!this._timers) {
321
+ this._timers = new Map();
208
322
  }
209
323
  else {
210
- this.clearInterval( name );
324
+ this.clearInterval(name);
211
325
  }
212
326
 
213
- const tm = setInterval( callback, time );
214
- this._timers.set( name, tm );
327
+ const tm = setInterval(callback, time);
328
+ this._timers.set(name, tm);
215
329
 
216
330
  return tm;
217
331
  }
218
332
 
219
- clearInterval( name: string ) {
220
- if( this._timers && this._timers.has(name) ) {
221
- clearInterval( this._timers.get(name) );
222
- this._timers.delete( name );
333
+ clearInterval(name: string) {
334
+ if (this._timers && this._timers.has(name)) {
335
+ clearInterval(this._timers.get(name));
336
+ this._timers.delete(name);
223
337
  }
224
338
  }
225
339
 
226
- clearAllTimeouts( ) {
227
- this._timers?.forEach( t => {
228
- clearTimeout( t );
229
- } );
340
+ clearAllTimeouts() {
341
+ this._timers?.forEach(t => {
342
+ clearTimeout(t);
343
+ });
230
344
 
231
345
  this._timers = null;
232
346
  }
@@ -236,8 +350,12 @@ export class Timer {
236
350
  *
237
351
  */
238
352
 
239
- export function asap( callback: ( ) => void ) {
240
- return requestAnimationFrame( callback );
353
+ export function asap(callback: () => void) {
354
+ return requestAnimationFrame(callback);
355
+ }
356
+
357
+ export function oneshot(callback: () => void, ms = 0) {
358
+ return setTimeout(callback, ms);
241
359
  }
242
360
 
243
361
 
@@ -279,7 +397,7 @@ export function pad(what: any, size: number, ch: string = '0') {
279
397
  * console.log( sprintf( 'here is arg 1 {1} and arg 0 {0}', 'argument 0', 'argument 1' ) )
280
398
  */
281
399
 
282
- export function sprintf( format: string, ...args:any[] ) {
400
+ export function sprintf(format: string, ...args: any[]) {
283
401
  return format.replace(/{(\d+)}/g, function (match, index) {
284
402
  return typeof args[index] != 'undefined' ? args[index] : match;
285
403
  });
@@ -307,11 +425,11 @@ export function pascalCase(string: string): string {
307
425
  return result.replace(/ /g, '-');
308
426
  }
309
427
 
310
- export function camelCase( text: string ) {
311
- let result = text.toLowerCase( );
312
- result = result.replace( /[^a-zA-Z0-9]+(.)/g, (m,chr) => {
428
+ export function camelCase(text: string) {
429
+ let result = text.toLowerCase();
430
+ result = result.replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => {
313
431
  return chr.toUpperCase();
314
- } );
432
+ });
315
433
  return result;
316
434
  }
317
435
 
@@ -351,7 +469,7 @@ export function date_format(date: Date, options?: any): string {
351
469
 
352
470
  export function date_diff(date1: Date, date2: Date, options?: any): string {
353
471
 
354
- var dt = (date1.getTime() - date2.getTime()) / 1000;
472
+ let dt = (date1.getTime() - date2.getTime()) / 1000;
355
473
 
356
474
  // seconds
357
475
  let sec = dt;
@@ -426,18 +544,25 @@ export function date_calc_weeknum(date: Date): number {
426
544
  * @param value - string date to parse
427
545
  * @param fmts - format list - i18 tranlation by default
428
546
  * allowed format specifiers:
429
- * d or D: date (1 or 2 digits)
430
- * m or M: month (1 or 2 digits)
431
- * y or Y: year (2 or 4 digits)
432
- * h or H: hours (1 or 2 digits)
433
- * i or I: minutes (1 or 2 digits)
434
- * s or S: seconds (1 or 2 digits)
547
+ * d: date (1 or 2 digits)
548
+ * D: date (2 digits)
549
+ * m: month (1 or 2 digits)
550
+ * M: month (2 digits)
551
+ * y: year (2 to 4 digits)
552
+ * Y: year (2 digits)
553
+ * YY: year (4 digits)
554
+ * h: hours (1 or 2 digits)
555
+ * H: hours (2 digits)
556
+ * i: minutes (1 or 2 digits)
557
+ * I: minutes (2 digits)
558
+ * s: seconds (1 or 2 digits)
559
+ * S: seconds (2 digits)
435
560
  * <space>: 1 or more spaces
436
561
  * any other char: <0 or more spaces><the char><0 or more spaces>
437
562
  * each specifiers is separated from other by a pipe (|)
438
563
  * more specific at first
439
564
  * @example
440
- * 'd/m/y|d m Y|dmy|y-m-d h:i:s|y-m-d'
565
+ * 'd/m/y|d m Y|dmy|y-m-d h:i:s|y-m-d|YY-M-D'
441
566
  */
442
567
 
443
568
  export function parseIntlDate(value: string, fmts: string = _tr.global.date_input_formats): Date {
@@ -449,26 +574,51 @@ export function parseIntlDate(value: string, fmts: string = _tr.global.date_inpu
449
574
  //review: add hours, minutes, seconds
450
575
 
451
576
  let smatch = '';
452
- for (let c of fmatch) {
577
+ for (let i = 0; i < fmatch.length; i++) {
578
+ const c = fmatch[i];
453
579
 
454
- if (c == 'd' || c == 'D') {
580
+ if (c == 'd') {
455
581
  smatch += '(?<day>\\d{1,2})';
456
582
  }
457
- else if (c == 'm' || c == 'M') {
583
+ else if (c == 'D') {
584
+ smatch += '(?<day>\\d{2})';
585
+ }
586
+ else if (c == 'm') {
458
587
  smatch += '(?<month>\\d{1,2})';
459
588
  }
460
- else if (c == 'y' || c == 'Y') {
589
+ else if (c == 'M') {
590
+ smatch += '(?<month>\\d{2})';
591
+ }
592
+ else if (c == 'y') {
461
593
  smatch += '(?<year>\\d{1,4})';
462
594
  }
463
- else if (c == 'h' || c == 'H') {
595
+ else if (c == 'Y') {
596
+ if (fmatch[i + 1] == 'Y') {
597
+ smatch += '(?<year>\\d{4})';
598
+ i++;
599
+ }
600
+ else {
601
+ smatch += '(?<year>\\d{2})';
602
+ }
603
+ }
604
+ else if (c == 'h') {
464
605
  smatch += '(?<hour>\\d{1,2})';
465
606
  }
466
- else if (c == 'i' || c == 'I') {
607
+ else if (c == 'H') {
608
+ smatch += '(?<hour>\\d{2})';
609
+ }
610
+ else if (c == 'i') {
467
611
  smatch += '(?<min>\\d{1,2})';
468
612
  }
469
- else if (c == 's' || c == 'S') {
613
+ else if (c == 'I') {
614
+ smatch += '(?<min>\\d{2})';
615
+ }
616
+ else if (c == 's') {
470
617
  smatch += '(?<sec>\\d{1,2})';
471
618
  }
619
+ else if (c == 'S') {
620
+ smatch += '(?<sec>\\d{2})';
621
+ }
472
622
  else if (c == ' ') {
473
623
  smatch += '\\s+';
474
624
  }
@@ -482,11 +632,11 @@ export function parseIntlDate(value: string, fmts: string = _tr.global.date_inpu
482
632
  let match = rematch.exec(value);
483
633
 
484
634
  if (match) {
485
- const now = new Date( );
635
+ const now = new Date();
486
636
 
487
637
  let d = parseInt(match.groups.day ?? '1');
488
638
  let m = parseInt(match.groups.month ?? '1');
489
- let y = parseInt(match.groups.year ?? now.getFullYear()+'');
639
+ let y = parseInt(match.groups.year ?? now.getFullYear() + '');
490
640
  let h = parseInt(match.groups.hour ?? '0');
491
641
  let i = parseInt(match.groups.min ?? '0');
492
642
  let s = parseInt(match.groups.sec ?? '0');
@@ -673,16 +823,84 @@ export function calcAge(birth: Date, ref?: Date) {
673
823
 
674
824
  // :: MISC ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
675
825
 
676
- export function beep( ) {
677
- const snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
678
- snd.play();
826
+ export function beep() {
827
+ const snd = new Audio("data:audio/wav;base64,//uQRAAAAWMSLwUIYAAsYkXgoQwAEaYLWfkWgAI0wWs/ItAAAGDgYtAgAyN+QWaAAihwMWm4G8QQRDiMcCBcH3Cc+CDv/7xA4Tvh9Rz/y8QADBwMWgQAZG/ILNAARQ4GLTcDeIIIhxGOBAuD7hOfBB3/94gcJ3w+o5/5eIAIAAAVwWgQAVQ2ORaIQwEMAJiDg95G4nQL7mQVWI6GwRcfsZAcsKkJvxgxEjzFUgfHoSQ9Qq7KNwqHwuB13MA4a1q/DmBrHgPcmjiGoh//EwC5nGPEmS4RcfkVKOhJf+WOgoxJclFz3kgn//dBA+ya1GhurNn8zb//9NNutNuhz31f////9vt///z+IdAEAAAK4LQIAKobHItEIYCGAExBwe8jcToF9zIKrEdDYIuP2MgOWFSE34wYiR5iqQPj0JIeoVdlG4VD4XA67mAcNa1fhzA1jwHuTRxDUQ//iYBczjHiTJcIuPyKlHQkv/LHQUYkuSi57yQT//uggfZNajQ3Vmz+Zt//+mm3Wm3Q576v////+32///5/EOgAAADVghQAAAAA//uQZAUAB1WI0PZugAAAAAoQwAAAEk3nRd2qAAAAACiDgAAAAAAABCqEEQRLCgwpBGMlJkIz8jKhGvj4k6jzRnqasNKIeoh5gI7BJaC1A1AoNBjJgbyApVS4IDlZgDU5WUAxEKDNmmALHzZp0Fkz1FMTmGFl1FMEyodIavcCAUHDWrKAIA4aa2oCgILEBupZgHvAhEBcZ6joQBxS76AgccrFlczBvKLC0QI2cBoCFvfTDAo7eoOQInqDPBtvrDEZBNYN5xwNwxQRfw8ZQ5wQVLvO8OYU+mHvFLlDh05Mdg7BT6YrRPpCBznMB2r//xKJjyyOh+cImr2/4doscwD6neZjuZR4AgAABYAAAABy1xcdQtxYBYYZdifkUDgzzXaXn98Z0oi9ILU5mBjFANmRwlVJ3/6jYDAmxaiDG3/6xjQQCCKkRb/6kg/wW+kSJ5//rLobkLSiKmqP/0ikJuDaSaSf/6JiLYLEYnW/+kXg1WRVJL/9EmQ1YZIsv/6Qzwy5qk7/+tEU0nkls3/zIUMPKNX/6yZLf+kFgAfgGyLFAUwY//uQZAUABcd5UiNPVXAAAApAAAAAE0VZQKw9ISAAACgAAAAAVQIygIElVrFkBS+Jhi+EAuu+lKAkYUEIsmEAEoMeDmCETMvfSHTGkF5RWH7kz/ESHWPAq/kcCRhqBtMdokPdM7vil7RG98A2sc7zO6ZvTdM7pmOUAZTnJW+NXxqmd41dqJ6mLTXxrPpnV8avaIf5SvL7pndPvPpndJR9Kuu8fePvuiuhorgWjp7Mf/PRjxcFCPDkW31srioCExivv9lcwKEaHsf/7ow2Fl1T/9RkXgEhYElAoCLFtMArxwivDJJ+bR1HTKJdlEoTELCIqgEwVGSQ+hIm0NbK8WXcTEI0UPoa2NbG4y2K00JEWbZavJXkYaqo9CRHS55FcZTjKEk3NKoCYUnSQ0rWxrZbFKbKIhOKPZe1cJKzZSaQrIyULHDZmV5K4xySsDRKWOruanGtjLJXFEmwaIbDLX0hIPBUQPVFVkQkDoUNfSoDgQGKPekoxeGzA4DUvnn4bxzcZrtJyipKfPNy5w+9lnXwgqsiyHNeSVpemw4bWb9psYeq//uQZBoABQt4yMVxYAIAAAkQoAAAHvYpL5m6AAgAACXDAAAAD59jblTirQe9upFsmZbpMudy7Lz1X1DYsxOOSWpfPqNX2WqktK0DMvuGwlbNj44TleLPQ+Gsfb+GOWOKJoIrWb3cIMeeON6lz2umTqMXV8Mj30yWPpjoSa9ujK8SyeJP5y5mOW1D6hvLepeveEAEDo0mgCRClOEgANv3B9a6fikgUSu/DmAMATrGx7nng5p5iimPNZsfQLYB2sDLIkzRKZOHGAaUyDcpFBSLG9MCQALgAIgQs2YunOszLSAyQYPVC2YdGGeHD2dTdJk1pAHGAWDjnkcLKFymS3RQZTInzySoBwMG0QueC3gMsCEYxUqlrcxK6k1LQQcsmyYeQPdC2YfuGPASCBkcVMQQqpVJshui1tkXQJQV0OXGAZMXSOEEBRirXbVRQW7ugq7IM7rPWSZyDlM3IuNEkxzCOJ0ny2ThNkyRai1b6ev//3dzNGzNb//4uAvHT5sURcZCFcuKLhOFs8mLAAEAt4UWAAIABAAAAAB4qbHo0tIjVkUU//uQZAwABfSFz3ZqQAAAAAngwAAAE1HjMp2qAAAAACZDgAAAD5UkTE1UgZEUExqYynN1qZvqIOREEFmBcJQkwdxiFtw0qEOkGYfRDifBui9MQg4QAHAqWtAWHoCxu1Yf4VfWLPIM2mHDFsbQEVGwyqQoQcwnfHeIkNt9YnkiaS1oizycqJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
828
+ snd.play();
679
829
  }
680
830
 
831
+ let sb_width_cache = -1;
832
+
833
+ /**
834
+ * compute scrollbar size
835
+ */
836
+
837
+ export function getScrollbarSize() {
838
+
839
+ if (sb_width_cache < 0) {
840
+ let outerDiv = document.createElement('div');
841
+ outerDiv.style.cssText = 'overflow:auto;position:absolute;top:0;width:100px;height:100px';
842
+
843
+ let innerDiv = document.createElement('div');
844
+ innerDiv.style.width = '200px';
845
+ innerDiv.style.height = '200px';
846
+
847
+ outerDiv.appendChild(innerDiv);
848
+ document.body.appendChild(outerDiv);
681
849
 
682
- export const x4_class_ns_sym = Symbol( "class-ns" );
850
+ sb_width_cache = outerDiv.offsetWidth - outerDiv.clientWidth;
851
+ document.body.removeChild(outerDiv);
852
+ }
853
+
854
+ return sb_width_cache;
855
+ }
856
+
857
+ /**
858
+ *
859
+ */
683
860
 
684
- export function class_ns( ns: string ) {
685
- return function (constructor: Function) {
861
+ export const x4_class_ns_sym = Symbol("class-ns");
862
+ export function class_ns(ns: string) {
863
+ return function (constructor: Function) {
686
864
  (constructor as any)[x4_class_ns_sym] = ns;
687
865
  }
688
- }
866
+ }
867
+
868
+ /**
869
+ *
870
+ */
871
+
872
+ export function setWaitCursor(wait: boolean) {
873
+ document.body.style.cursor = wait ? "wait" : "default";
874
+ }
875
+
876
+ /**
877
+ * return the focusable elements from a given node
878
+ */
879
+
880
+ export function getFocusableElements(root: Element) {
881
+ const els = [
882
+ 'button:not([tabindex="-1"]):not([disabled])',
883
+ '[href]',
884
+ 'input:not([disabled])',
885
+ 'select:not([disabled])',
886
+ 'textarea:not([disabled])',
887
+ '[tabindex]:not([tabindex="-1"])'
888
+ ]
889
+
890
+ const focusable = Array.from(root.querySelectorAll(els.join(',')));
891
+ return focusable.filter(x => (x as HTMLElement).offsetParent != null); // check visibility
892
+ }
893
+
894
+ /**
895
+ *
896
+ */
897
+
898
+ export enum kbNav {
899
+ first,
900
+ prev,
901
+ pgdn,
902
+ pgup,
903
+ next,
904
+ last,
905
+ }
906
+
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file tsx.d.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
+ export { }
18
+
19
+ declare global {
20
+ namespace JSX {
21
+ interface IntrinsicElements {
22
+ [ name: string ]: any;
23
+ }
24
+ }
25
+ }