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
@@ -14,7 +14,7 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { isArray, UnsafeHtml, isNumber, Rect, Constructor, class_ns, x4_class_ns_sym } from './core_tools';
17
+ import { isArray, UnsafeHtml, isNumber, Rect, Constructor, class_ns, x4_class_ns_sym, IRect } from './core_tools';
18
18
  import { CoreElement } from './core_element';
19
19
  import { ariaValues, unitless } from './core_styles';
20
20
  import { CoreEvent, EventMap } from './core_events';
@@ -25,6 +25,7 @@ interface RefType<T extends Component> {
25
25
  }
26
26
 
27
27
  type ComponentAttributes = Record<string,string|number|boolean>;
28
+ type CreateComponentCallBack = ( attrs: Record<string,string> ) => ComponentContent;
28
29
 
29
30
  const FRAGMENT = Symbol( "fragment" );
30
31
  const COMPONENT = Symbol( "component" );
@@ -41,14 +42,18 @@ const RE_NUMBER = /^-?\d+(\.\d*)?$/;
41
42
  * to your class to avoid autogenerated css class names conflicts
42
43
  */
43
44
 
44
- function genClassNames( x: any ) {
45
+ function genClassNames( x: any ): string[] {
45
46
 
46
- let classes = [];
47
+ const classes = [];
47
48
  let self = Object.getPrototypeOf(x);
48
49
 
50
+ if( self.constructor==Component ) {
51
+ return ["x4-comp"];
52
+ }
53
+
49
54
  while (self && self.constructor !== Component ) {
50
55
  const clsname:string = self.constructor.name;
51
- const clsns: string = self.constructor.hasOwnProperty(x4_class_ns_sym) ? self.constructor[x4_class_ns_sym] : "";
56
+ const clsns: string = Object.prototype.hasOwnProperty.call(self.constructor,x4_class_ns_sym) ? self.constructor[x4_class_ns_sym] : "";
52
57
  classes.push( clsns+clsname.toLowerCase() );
53
58
  self = Object.getPrototypeOf(self);
54
59
  }
@@ -60,7 +65,7 @@ function genClassNames( x: any ) {
60
65
  *
61
66
  */
62
67
 
63
- export type ComponentContent = Component | string | UnsafeHtml | number | boolean | Component[];
68
+ export type ComponentContent = Component | Component[] | string | string[] | UnsafeHtml| UnsafeHtml[] | number | boolean;
64
69
 
65
70
  let gen_id = 1000;
66
71
 
@@ -89,6 +94,7 @@ export interface ComponentProps {
89
94
  height?: string | number;
90
95
  disabled?: true,
91
96
  hidden?: true,
97
+ flex?: boolean | number;
92
98
 
93
99
  tooltip?: string;
94
100
 
@@ -129,7 +135,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
129
135
  readonly props: P;
130
136
  protected readonly clsprefix: string; // internal class name prefix (x4 internal)
131
137
 
132
- private store: Map<string|Symbol,any>;
138
+ #store: Map<string|symbol,any>;
133
139
 
134
140
  constructor( props: P ) {
135
141
  super( );
@@ -159,6 +165,15 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
159
165
  this.show( false );
160
166
  }
161
167
 
168
+ if( props.flex===true ) {
169
+ this.addClass( "x4flex" );
170
+ }
171
+ else if( props.flex!==undefined ) {
172
+ this.setStyle( {
173
+ "flexGrow": props.flex+""
174
+ });
175
+ }
176
+
162
177
  if( props.id!==undefined ) {
163
178
  this.setAttribute( "id", props.id );
164
179
  }
@@ -220,8 +235,9 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
220
235
 
221
236
  addClass( cls: string ) {
222
237
  if( !cls ) return;
223
-
238
+
224
239
  if( cls.indexOf(' ')>=0 ) {
240
+ cls = cls.trim( );
225
241
  const ccs = cls.split( " " );
226
242
  this.dom.classList.add(...ccs);
227
243
  }
@@ -231,11 +247,16 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
231
247
  }
232
248
 
233
249
  /**
234
- *
250
+ * special case: '*' mean clear class list
235
251
  */
236
252
 
237
253
  removeClass( cls: string ) {
238
254
  if( !cls ) return;
255
+
256
+ if( cls=='*' ) {
257
+ this.dom.classList.value = "";
258
+ return;
259
+ }
239
260
 
240
261
  if( cls.indexOf(' ')>=0 ) {
241
262
  const ccs = cls.split( " " );
@@ -283,9 +304,10 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
283
304
  *
284
305
  */
285
306
 
286
- setClass( cls: string, set: boolean = true ) {
307
+ setClass( cls: string, set: boolean = true ) : this {
287
308
  if( set ) this.addClass(cls);
288
309
  else this.removeClass( cls );
310
+ return this;
289
311
  }
290
312
 
291
313
  // :: ATTRIBUTES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@@ -294,12 +316,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
294
316
  * attributes
295
317
  */
296
318
 
297
- setAttributes( attrs: ComponentAttributes ) {
298
-
319
+ setAttributes( attrs: ComponentAttributes ): this {
299
320
  for( const name in attrs ) {
300
- const value = attrs[name];
301
- this.setAttribute( name, value );
321
+ this.setAttribute( name, attrs[name] );
302
322
  }
323
+ return this;
303
324
  }
304
325
 
305
326
  /**
@@ -331,6 +352,18 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
331
352
  return this.getAttribute( "data-"+name );
332
353
  }
333
354
 
355
+ /**
356
+ * @returns undefined if not a number
357
+ */
358
+ getIntData( name: string ) : number {
359
+ const v = parseInt( this.getAttribute( "data-"+name ) );
360
+ if( Number.isFinite(v) ) {
361
+ return v;
362
+ }
363
+
364
+ return undefined;
365
+ }
366
+
334
367
  /**
335
368
  *
336
369
  */
@@ -343,17 +376,17 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
343
376
  * idem as setData but onot on dom, you can store anything
344
377
  */
345
378
 
346
- setInternalData( name: string|Symbol, value: any ): this {
347
- if( !this.store ) {
348
- this.store = new Map( );
379
+ setInternalData( name: string|symbol, value: any ): this {
380
+ if( !this.#store ) {
381
+ this.#store = new Map( );
349
382
  }
350
383
 
351
- this.store.set( name, value );
384
+ this.#store.set( name, value );
352
385
  return this;
353
386
  }
354
387
 
355
- getInternalData( name: string|Symbol ): any {
356
- return this.store?.get(name);
388
+ getInternalData( name: string|symbol ): any {
389
+ return this.#store?.get(name);
357
390
  }
358
391
 
359
392
 
@@ -387,7 +420,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
387
420
  protected mapPropEvents<N extends keyof E>(props: P, ...elements: N[] ) {
388
421
  const p = props as any;
389
422
  elements.forEach( n => {
390
- if (p.hasOwnProperty(n) ) {
423
+ if (Object.prototype.hasOwnProperty.call(p,n) && p[n]) {
391
424
  this.on( n, p[n] );
392
425
  }
393
426
  });
@@ -465,17 +498,15 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
465
498
 
466
499
  prependContent( content: ComponentContent ) {
467
500
  const d = this.dom;
468
-
469
501
  const set = ( c: Component | string | UnsafeHtml | number | boolean ) => {
470
502
  if (c instanceof Component ) {
471
- d.insertBefore( d.firstChild, c.dom );
503
+ d.insertAdjacentElement( 'afterbegin', c.dom );
472
504
  }
473
505
  else if( c instanceof UnsafeHtml) {
474
- d.insertAdjacentHTML( 'beforebegin', c.toString() );
506
+ d.insertAdjacentHTML( 'afterbegin', c.toString() );
475
507
  }
476
508
  else if (typeof c === "string" || typeof c === "number") {
477
- const tnode = document.createTextNode(c.toString());
478
- d.insertBefore( d.firstChild, tnode );
509
+ d.insertAdjacentText( 'afterbegin', c.toString() );
479
510
  }
480
511
  else {
481
512
  console.warn("Unknown type to append: ", c);
@@ -512,7 +543,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
512
543
  queryAll( selector: string ): Component[] {
513
544
  const all = this.dom.querySelectorAll( selector );
514
545
  const rc = new Array( all.length );
515
- all.forEach( (x,i) => rc[i]=componentFromDOM(x) );
546
+ all.forEach( (x,i) => rc[i]=wrapDOM(x as HTMLElement) );
516
547
  return rc;
517
548
  }
518
549
 
@@ -525,6 +556,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
525
556
  return componentFromDOM<T>(r);
526
557
  }
527
558
 
559
+
528
560
  // :: STYLES ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
529
561
 
530
562
 
@@ -657,8 +689,13 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
657
689
  *
658
690
  */
659
691
 
660
- focus( ) {
692
+ focus( ): this {
661
693
  (this.dom as HTMLElement).focus( );
694
+ return this;
695
+ }
696
+
697
+ hasFocus( ) {
698
+ return document.activeElement==this.dom;
662
699
  }
663
700
 
664
701
  /**
@@ -681,40 +718,49 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
681
718
  *
682
719
  */
683
720
 
684
- show( vis = true ) {
721
+ show( vis = true ): this {
685
722
  this.setClass( 'x4hidden', !vis );
723
+ return this;
686
724
  }
687
725
 
688
726
  /**
689
727
  *
690
728
  */
691
729
 
692
- hide( ) {
730
+ hide( ): this {
693
731
  this.show( false );
732
+ return this;
694
733
  }
695
734
 
696
735
  /**
697
736
  * enable or disable a component (all sub HTMLElement will be also disabled)
698
737
  */
699
738
 
700
- enable( ena = true ) {
701
- this.setAttribute( "disabled", !ena );
739
+ enable( ena = true ): this {
740
+ this.setAttribute( "disabled", !ena ? 'true' : null );
741
+
742
+ if( this.dom instanceof HTMLInputElement || this.dom instanceof HTMLButtonElement ) {
743
+ this.dom.disabled = !ena;
744
+ }
702
745
 
703
746
  // propagate diable state to all input children
704
747
  const nodes = this.enumChildNodes( true );
705
748
  nodes.forEach( x => {
706
- if( x instanceof HTMLInputElement ) {
749
+ if( x instanceof HTMLInputElement || x instanceof HTMLButtonElement ) {
707
750
  x.disabled = !ena;
708
751
  }
709
752
  });
753
+
754
+ return this;
710
755
  }
711
756
 
712
757
  /**
713
758
  *
714
759
  */
715
760
 
716
- disable( ) {
761
+ disable( ): this {
717
762
  this.enable( false );
763
+ return this;
718
764
  }
719
765
 
720
766
  /**
@@ -749,10 +795,17 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
749
795
  */
750
796
 
751
797
  parentElement<T extends Component>( cls?: Constructor<T> ): T {
752
- let p = this.dom;
798
+ return Component.parentElement<T>( this.dom, cls );
799
+ }
800
+
801
+ /**
802
+ * search for parent that match the given contructor
803
+ */
804
+
805
+ static parentElement<T extends Component>( dom: Node, cls?: Constructor<T> ): T {
753
806
 
754
- while( p.parentElement ) {
755
- const cp = componentFromDOM( p.parentElement );
807
+ while( dom.parentElement ) {
808
+ const cp = componentFromDOM( dom.parentElement );
756
809
  if( !cls ) {
757
810
  return cp as T;
758
811
  }
@@ -761,7 +814,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
761
814
  return cp;
762
815
  }
763
816
 
764
- p = p.parentElement;
817
+ dom = dom.parentElement;
765
818
  }
766
819
 
767
820
  return null;
@@ -793,7 +846,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
793
846
 
794
847
  enumChildComponents( recursive: boolean ) {
795
848
 
796
- let children: Component[] = [];
849
+ const children: Component[] = [];
797
850
 
798
851
  const nodes = this.enumChildNodes( recursive );
799
852
  nodes.forEach( ( c: Node ) => {
@@ -811,7 +864,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
811
864
  */
812
865
 
813
866
  enumChildNodes( recursive: boolean ) {
814
- let children: Node[] = Array.from( recursive ? this.dom.querySelectorAll( '*' ) : this.dom.children );
867
+ const children: Node[] = Array.from( recursive ? this.dom.querySelectorAll( '*' ) : this.dom.children );
815
868
  return children;
816
869
  }
817
870
 
@@ -830,7 +883,7 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
830
883
  * called by the compiler when a jsx element is seen
831
884
  */
832
885
 
833
- static createElement( clsOrTag: string | ComponentConstructor | Symbol | Function, attrs: any, ...children: Component[] ): Component | Component[] {
886
+ static createElement( clsOrTag: string | ComponentConstructor | symbol | CreateComponentCallBack, attrs: any, ...children: Component[] ): Component | Component[] {
834
887
 
835
888
  let comp: Component;
836
889
 
@@ -875,7 +928,11 @@ export class Component<P extends ComponentProps = ComponentProps, E extends Comp
875
928
  // :: SPECIALS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
876
929
 
877
930
  /**
931
+ * system interfaces:
932
+ * "form-element"
933
+ * "tab-handler"
878
934
  *
935
+ * each app can create it's own interface
879
936
  */
880
937
 
881
938
  queryInterface<T>( name: string ): T {
@@ -923,6 +980,13 @@ export class Flex extends Component {
923
980
  }
924
981
  }
925
982
 
983
+ // just a spacer element that push other
984
+ export class Space extends Component {
985
+ constructor( width?: number|string, cls?: string ) {
986
+ super( { width, cls } )
987
+ }
988
+ }
989
+
926
990
 
927
991
  // :: HIGH LEVEL BASIC EVENTS ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
928
992
 
@@ -945,6 +1009,14 @@ export interface EvChange extends ComponentEvent {
945
1009
  readonly value: any;
946
1010
  }
947
1011
 
1012
+ /**
1013
+ * Focus event
1014
+ */
1015
+
1016
+ export interface EvFocus extends ComponentEvent {
1017
+ readonly focus_out: boolean;
1018
+ }
1019
+
948
1020
  /**
949
1021
  * Selection Event
950
1022
  * value is the new selection or null
@@ -955,6 +1027,7 @@ interface ISelection {
955
1027
 
956
1028
  export interface EvSelectionChange extends ComponentEvent {
957
1029
  readonly selection: ISelection;
1030
+ readonly empty: boolean;
958
1031
  }
959
1032
 
960
1033
 
@@ -14,31 +14,252 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { Component } from './component.js';
17
+ import { Component, componentFromDOM } from './component.js';
18
18
  import { CoreElement } from './core_element.js';
19
- import { EventMap } from './core_events';
19
+ import { CoreEvent, EventMap } from './core_events';
20
+ import { getFocusableElements, ITabHandler } from './core_tools.js';
20
21
 
22
+ const socket_sent = Symbol( 'socket' );
23
+
24
+
25
+ export interface EvMessage extends CoreEvent {
26
+ msg: string;
27
+ params: any;
28
+ }
21
29
 
22
30
  export interface ApplicationEvents extends EventMap {
31
+ global: EvMessage;
32
+ message: EvMessage;
23
33
  }
24
34
 
25
35
  // signleton
26
36
  let main_app: Application = null;
27
37
 
38
+
39
+
40
+ class Process {
41
+
42
+ /**
43
+ * can be use to see if we have some tactile input
44
+ * @returns max touch point count
45
+ */
46
+
47
+ getMaxTouchPoints( ) {
48
+ return navigator.maxTouchPoints;
49
+ }
50
+ }
51
+
52
+
53
+
28
54
  export class Application<E extends ApplicationEvents = ApplicationEvents> extends CoreElement<E> {
29
55
 
56
+ private env = new Map<string,any>( );
57
+ private mainview: Component;
58
+
59
+ static readonly process = new Process( );
60
+
30
61
  constructor( ) {
31
62
  super( );
32
63
 
33
64
  console.assert( main_app==null, "Application must be a singleton." );
65
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
34
66
  main_app = this;
35
67
  }
36
68
 
37
69
  setMainView( view: Component ) {
70
+ this.mainview = view;
38
71
  document.body.appendChild( view.dom );
72
+ this._setupKeyboard( );
39
73
  }
40
74
 
41
75
  static instance<P extends Application = Application>( ): P {
42
76
  return main_app as P;
43
77
  }
78
+
79
+ /**
80
+ *
81
+ */
82
+
83
+ getMainView( ) {
84
+ return this.mainview;
85
+ }
86
+
87
+ /**
88
+ *
89
+ */
90
+
91
+ setEnv( name: string, value: any ) {
92
+ this.env.set( name, value );
93
+ }
94
+
95
+ /**
96
+ *
97
+ */
98
+
99
+ getEnv( name: string, def_value?: any ) {
100
+ return this.env.get( name ) ?? def_value;
101
+ }
102
+
103
+ /**
104
+ * small shortcut for Application.instance().fire( "global", ... );
105
+ */
106
+
107
+ static fireGlobal( msg: string, params?: any ) {
108
+ Application.instance().fire( "global", { msg, params } );
109
+ }
110
+
111
+ /**
112
+ *
113
+ */
114
+
115
+ private _setupKeyboard( ) {
116
+
117
+ document.addEventListener( "keydown", (ev) => {
118
+ if( ev.key=="Tab" || ev.key=="Enter" ) {
119
+ if( this.focusNext( !ev.shiftKey ) ) {
120
+ ev.preventDefault( );
121
+ }
122
+ }
123
+ } );
124
+ }
125
+
126
+ focusNext( next: boolean ) {
127
+ let act = document.activeElement;
128
+ let topmost: HTMLElement;
129
+
130
+ while( act!=document.body ) {
131
+ const comp = componentFromDOM(act);
132
+ const ifx = comp.queryInterface( "tab-handler") as ITabHandler;
133
+
134
+ if( ifx ) {
135
+ return ifx.focusNext( next );
136
+ }
137
+
138
+ if( act.classList.contains("x4box") ) { // todo: that is too dirty
139
+ topmost = act as HTMLElement;
140
+ }
141
+
142
+ act = act.parentElement;
143
+ }
144
+
145
+ if( topmost ) {
146
+ const focusable = getFocusableElements( topmost );
147
+ if( !focusable.length ) {
148
+ return true;
149
+ }
150
+ else {
151
+ const first = focusable[0];
152
+ const last = focusable[focusable.length - 1];
153
+
154
+ let newf: HTMLElement;
155
+ if (!next && document.activeElement === first) {
156
+ newf = last as HTMLElement;
157
+ }
158
+ else if (next && document.activeElement === last) {
159
+ newf = first as HTMLElement;
160
+ }
161
+
162
+ if( newf ) {
163
+ newf.focus();
164
+ return true;
165
+ }
166
+ }
167
+ }
168
+
169
+ return false;
170
+ }
171
+
172
+
173
+ /**
174
+ *
175
+ */
176
+
177
+ setupSocketMessaging( path?: string, looseCallback?: ( ) => void ) {
178
+
179
+ const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
180
+ const address = path ? protocol+path : `${protocol}${window.location.hostname}:${window.location.port}/ws`;
181
+
182
+ let opened = 0;
183
+ let msg_socket:WebSocket = null;
184
+
185
+ // we trap all 'global' messages send via application
186
+ // then we send them on websocket
187
+
188
+ this.on( 'global', ( e: EvMessage ) => {
189
+ if( Object.prototype.hasOwnProperty.call( e, socket_sent) ) {
190
+ return;
191
+ }
192
+
193
+ if( msg_socket ) {
194
+ msg_socket.send( JSON.stringify( {
195
+ msg: e.msg,
196
+ params: e.params,
197
+ } ) );
198
+ }
199
+ });
200
+
201
+ msg_socket = new WebSocket(address, 'messaging' );
202
+
203
+ msg_socket.onopen = ( ) => {
204
+ console.log( 'websocket opened' );
205
+ opened = 1;
206
+ }
207
+
208
+ // receive a message
209
+ msg_socket.onmessage = ( e ) => {
210
+ if( e.data!='ping' ) {
211
+ const message = JSON.parse(e.data);
212
+ message[socket_sent] = true;
213
+ this.fire( 'global', message );
214
+ }
215
+ }
216
+
217
+ // loose socket
218
+ msg_socket.onclose = ( ev ) => {
219
+ console.log( 'websocket closed:', ev );
220
+ msg_socket = null;
221
+
222
+ if( opened ) {
223
+ looseCallback( );
224
+ opened = 0;
225
+ }
226
+ }
227
+
228
+ //msg_socket.onerror = (ev )=> {
229
+ // console.log( 'websocket error:', ev );
230
+ //}
231
+ }
232
+
233
+ /**
234
+ * get a local storage value
235
+ * @param name name of the value
236
+ * @returns the value (string) or undefined
237
+ */
238
+
239
+ getStorage( name: string ) : string {
240
+ return localStorage.getItem( name );
241
+ }
242
+
243
+ getStorageJSON( name: string ) : any {
244
+ try {
245
+ return JSON.parse( localStorage.getItem( name ) );
246
+ }
247
+ catch( e ) {
248
+ return undefined;
249
+ }
250
+ }
251
+
252
+ /**
253
+ * change a loclastorage value
254
+ * @param name name of the value
255
+ * @param value the value to store
256
+ */
257
+
258
+ setStorage( name: string, value: string | number ) {
259
+ localStorage.setItem( name, value+'' );
260
+ }
261
+
262
+ setStorageJSON( name: string, value: any ) {
263
+ localStorage.setItem( name, JSON.stringify( value ) );
264
+ }
44
265
  }
@@ -178,7 +178,7 @@ export class Color {
178
178
 
179
179
 
180
180
  setRgb( r: number, g: number, b: number, a: number ): this {
181
- this.rgb = [clamp(r,0,255),clamp(g,0,255),clamp(b,0,255),clamp(a,0,1)];
181
+ this.rgb = [clamp(r|0,0,255),clamp(g|0,0,255),clamp(b|0,0,255),clamp(a,0,1)];
182
182
  return this;
183
183
  }
184
184
 
@@ -189,7 +189,7 @@ export class Color {
189
189
 
190
190
  toHexString( ): string {
191
191
  const _ = this.rgb;
192
- return _[3]==1 ? `#(${hx(_[0])},${hx(_[1])},${hx(_[2])})` : `rgba(${hx(_[0])},${hx(_[1])},${hx(_[2])},${hx(_[3]*255)})`
192
+ return _[3]==1 ? `#${hx(_[0])}${hx(_[1])}${hx(_[2])}` : `#${hx(_[0])}${hx(_[1])}${hx(_[2])}${(hx((_[3]*255)|0))}`
193
193
  }
194
194
 
195
195
  toRgb( ): Rgb {