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
@@ -25,7 +25,7 @@ interface DropInfo {
25
25
  }
26
26
 
27
27
  type DropCallback = ( command: 'enter' | 'leave' | 'drag' | 'drop', el: Component, infos: DropInfo ) => void;
28
- type FilterCallback = ( el: Component ) => boolean;
28
+ type FilterCallback = ( el: Component, data: DataTransfer ) => boolean;
29
29
 
30
30
  /**
31
31
  *
@@ -84,7 +84,7 @@ class DragManager {
84
84
  registerDropTarget(el: Component, cb: DropCallback, filterCB?: FilterCallback ) {
85
85
 
86
86
  const dragEnter = (ev: DragEvent) => {
87
- if( filterCB && !filterCB(this.dragSource) ) {
87
+ if( filterCB && !filterCB(this.dragSource,ev.dataTransfer) ) {
88
88
  console.log( 'reject ', el );
89
89
  ev.dataTransfer.dropEffect = 'none';
90
90
  return;
@@ -98,7 +98,7 @@ class DragManager {
98
98
  const dragOver = (ev: DragEvent) => {
99
99
  //console.log( "dragover", ev.target );
100
100
 
101
- if( filterCB && !filterCB(this.dragSource) ) {
101
+ if( filterCB && !filterCB(this.dragSource,ev.dataTransfer) ) {
102
102
  console.log( 'reject ', el );
103
103
  ev.dataTransfer.dropEffect = 'none';
104
104
  return;
@@ -42,7 +42,7 @@ export class CoreElement<E extends EventMap = EventMap> {
42
42
  }
43
43
 
44
44
  private __stopTimer( name: string ) {
45
- const clear = this.#timers.get(name);
45
+ const clear = this.#timers?.get(name);
46
46
  if (clear) { clear(); }
47
47
  }
48
48
 
@@ -84,6 +84,23 @@ export class CoreElement<E extends EventMap = EventMap> {
84
84
  }
85
85
 
86
86
  this.#events.addListener( name, listener );
87
+ return {
88
+ off: ( ) => {
89
+ this.#events.removeListener( name, listener );
90
+ }
91
+ }
92
+ }
93
+
94
+ /**
95
+ * detach
96
+ */
97
+
98
+ off<K extends keyof E>( name: K, listener: ( ev: E[K] ) => void ) {
99
+ console.assert( listener!==undefined && listener!==null );
100
+
101
+ if( this.#events ) {
102
+ this.#events.removeListener( name, listener );
103
+ }
87
104
  }
88
105
 
89
106
  /**
@@ -91,6 +91,34 @@ export class EventSource<E extends EventMap = EventMap > {
91
91
  listeners.push(cb);
92
92
  }
93
93
  }
94
+
95
+ return ( ) => {
96
+ this.removeListener( name, callback );
97
+ }
98
+ }
99
+
100
+ /**
101
+ * stop listening to an event
102
+ * @param eventName - event name
103
+ * @param callback - callback to remove (must be the same as in on )
104
+ */
105
+
106
+ removeListener<K extends keyof E>(name: K, callback: (ev: E[K]) => any) {
107
+
108
+ if (!this._registry ) {
109
+ return;
110
+ }
111
+
112
+ let listeners = this._registry.get(name as string);
113
+ if (!listeners) {
114
+ return;
115
+ }
116
+
117
+ const cb = callback as EventCallback;
118
+ const idx = listeners.indexOf(cb);
119
+ if (idx !== -1) {
120
+ listeners.splice(idx, 1);
121
+ }
94
122
  }
95
123
 
96
124
  fire<K extends keyof E>(name: K, evx: E[K]) {
@@ -97,7 +97,7 @@ export function addTranslation( name: string, ...parts: any[] ) {
97
97
 
98
98
  function _patch( obj: any, by: any ) {
99
99
 
100
- for( let n in by ) {
100
+ for( const n in by ) {
101
101
  const src = by[n];
102
102
  if( typeof src === "string" ) {
103
103
  obj[n] = src;
@@ -303,7 +303,15 @@ let fr = {
303
303
 
304
304
  copy: 'Copier',
305
305
  cut: 'Couper',
306
- paste: 'Coller'
306
+ paste: 'Coller',
307
+
308
+ filedrop: 'Déposez un fichier',
309
+
310
+ keyboard: {
311
+ next: 'Suivant',
312
+ numeric: '123',
313
+ alpha: 'Abc'
314
+ },
307
315
  }
308
316
  };
309
317
 
@@ -359,7 +367,15 @@ let en = {
359
367
 
360
368
  copy: 'Copy',
361
369
  cut: 'Cut',
362
- paste: 'Paste'
370
+ paste: 'Paste',
371
+
372
+ filedrop: 'Drop a file',
373
+
374
+ keyboard: {
375
+ next: 'Next',
376
+ numeric: '123',
377
+ alpha: 'Abc'
378
+ },
363
379
  }
364
380
  };
365
381
 
@@ -0,0 +1,79 @@
1
+ /**
2
+ * ___ ___ __
3
+ * \ \/ / / _
4
+ * \ / /_| |_
5
+ * / \____ _|
6
+ * /__/\__\ |_|.2
7
+ *
8
+ * @file core_react.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
+ * to use you must:
17
+ *
18
+ * 1. add this to your tsconfig.json
19
+ * "compilerOptions": {
20
+ * ...
21
+ * "jsx": "preserve",
22
+ * ...
23
+ * }
24
+ *
25
+ * 2. be sure that esbuild has this:
26
+ * jsxFactory: "x4create_element",
27
+ * loader: { ".ts": "tsx" }
28
+ *
29
+ *
30
+ * after that, all things like that will be ok
31
+ *
32
+ * import { x4_create_element } from "x4react"
33
+ * const xx = <h1>This is a title</h1>
34
+ *
35
+ */
36
+
37
+ import { Component } from './component.js';
38
+ import { Constructor, isString } from './core_tools.js';
39
+
40
+
41
+ /**
42
+ * x4 is reactive ?
43
+ * hard jsx :)
44
+ */
45
+
46
+ export class x4_react {
47
+
48
+ static create_element( tag: string, props: any, ...content: any[] ): Component;
49
+ static create_element<X extends Component>( tag: string | Constructor<X>, props: X["props"], ...content: any[] ) {
50
+
51
+ props = props || {};
52
+
53
+ let el: Component;
54
+
55
+ // --- simple div ------------------------
56
+ if( isString(tag) ) {
57
+ el = new Component( { tag } );
58
+ Object.entries( props )
59
+ .forEach(([name, value]) => {
60
+ if (name.startsWith('on') && name.toLowerCase() in window) {
61
+ el.dom.addEventListener(name.toLowerCase().substring(2), value)
62
+ }
63
+ else {
64
+ el.setAttribute(name, value )
65
+ }
66
+ });
67
+ }
68
+ // --- Component ------------------------
69
+ else {
70
+ el = new tag( props );
71
+ }
72
+
73
+ if( content && content.length ) {
74
+ el.appendContent( content );
75
+ }
76
+
77
+ return el;
78
+ }
79
+ }
@@ -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 { EvError } from './component.js';
17
+ import { EvChange, EvError } from './component.js';
18
18
  import { EventMap, EventSource } from './core_events.js';
19
19
 
20
20
  type RouteHandler = ( params: any, path: string ) => void;
@@ -30,7 +30,7 @@ interface Route {
30
30
  handler: RouteHandler;
31
31
  }
32
32
 
33
- function parseRoute(str: string | RegExp, loose = false): Segment {
33
+ export function parseRoute(str: string | RegExp, loose = false): Segment {
34
34
 
35
35
  if (str instanceof RegExp) {
36
36
  return {
@@ -60,7 +60,7 @@ function parseRoute(str: string | RegExp, loose = false): Segment {
60
60
  const ext = tmp.indexOf('.', 1);
61
61
 
62
62
  keys.push(tmp.substring(1, o >= 0 ? o : ext >= 0 ? ext : tmp.length));
63
- pattern += o >= 0 && ext < 0 ? '(?:/([^\/]+?))?' : '/([^\/]+?)';
63
+ pattern += o >= 0 && ext < 0 ? '(?:/([^/]+?))?' : '/([^/]+?)';
64
64
  if (ext >= 0) {
65
65
  pattern += (o >= 0 ? '?' : '') + '\\' + tmp.substring(ext);
66
66
  }
@@ -72,11 +72,12 @@ function parseRoute(str: string | RegExp, loose = false): Segment {
72
72
 
73
73
  return {
74
74
  keys,
75
- pattern: new RegExp( `^${pattern}${loose ? '(?=$|\/)' : '\/?$'}`, 'i' )
75
+ pattern: new RegExp( `^${pattern}${loose ? '(?=$|/)' : '/?$'}`, 'i' )
76
76
  };
77
77
  }
78
78
 
79
79
  interface RouterEvents extends EventMap {
80
+ change: EvChange;
80
81
  error: EvError;
81
82
  }
82
83
 
@@ -116,7 +117,7 @@ export class Router extends EventSource< RouterEvents > {
116
117
 
117
118
  this.m_routes = [];
118
119
  this.m_useHash = useHash;
119
-
120
+
120
121
  window.addEventListener('popstate', (event) => {
121
122
  const url = this._getLocation( );
122
123
  const found = this._find(url);
@@ -124,6 +125,8 @@ export class Router extends EventSource< RouterEvents > {
124
125
  found.handlers.forEach(h => {
125
126
  h(found.params,url);
126
127
  });
128
+
129
+ this.fire( "change", { value: this._getLocation() } );
127
130
  });
128
131
  }
129
132
 
@@ -140,6 +143,10 @@ export class Router extends EventSource< RouterEvents > {
140
143
  return this.m_useHash ? '/'+document.location.hash.substring(1) : document.location.pathname;
141
144
  }
142
145
 
146
+ /**
147
+ *
148
+ */
149
+
143
150
  navigate( uri: string, notify = true, replace = false ) {
144
151
 
145
152
  if( !uri.startsWith('/') ) {
@@ -152,7 +159,7 @@ export class Router extends EventSource< RouterEvents > {
152
159
  //window.history.pushState({}, '', 'error')
153
160
  console.log( 'route not found: '+uri );
154
161
  this.fire( "error", {code: 404, message: "route not found" } );
155
- return;
162
+ return false;
156
163
  }
157
164
 
158
165
  if( this.m_useHash ) {
@@ -171,12 +178,21 @@ export class Router extends EventSource< RouterEvents > {
171
178
  }
172
179
 
173
180
  if( notify ) {
174
- found.handlers.forEach( h => {
175
- h( found.params, uri );
176
- } );
181
+ //found.handlers.forEach( h => {
182
+ // h( found.params, uri );
183
+ //} );
184
+
185
+ found.handlers[0]( found.params, uri );
177
186
  }
187
+
188
+ this.fire( "change", { value: this._getLocation() } );
189
+ return true;
178
190
  }
179
191
 
192
+ /**
193
+ *
194
+ */
195
+
180
196
  private _find( url: string ): { params: Record<string,any>, handlers: RouteHandler[] } {
181
197
 
182
198
  let matches = [];
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @file core_state.ts
3
+ * @author Etienne Cochard
4
+ * @copyright (c) 2025 R-libre ingenierie, all rights reserved.
5
+ **/
6
+
7
+
8
+ type StateData = boolean | number | string | Date | any;
9
+ type State = Record<string,StateData>;
10
+
11
+ export class StateManager {
12
+
13
+ private _state: StateData;
14
+ private _subscribers: Map<string,any>;
15
+ private _currentTracking: Set<string>;
16
+
17
+ constructor(initialState: StateData ) {
18
+ this._state = initialState ? { ...initialState } : {};
19
+ this._subscribers = new Map();
20
+ this._currentTracking = new Set( );
21
+ }
22
+
23
+ getState( path: string, defaultValue: StateData = null) {
24
+ // Optional tracking for reactivity
25
+ if (this._currentTracking) {
26
+ this._currentTracking.add(path);
27
+ }
28
+ // Fast path-based access
29
+ const parts = path.split('.');
30
+ let current = this._state;
31
+
32
+ for (const part of parts) {
33
+ if (current?.[part] === undefined) {
34
+ return defaultValue;
35
+ }
36
+
37
+ current = current[part];
38
+ }
39
+
40
+ return current;
41
+ }
42
+
43
+ setState(path: string, value: StateData, context: any = {} ) {
44
+ // Update state
45
+ const parts = path.split('.');
46
+ let current = this._state;
47
+
48
+ for (let i = 0; i < parts.length - 1; i++) {
49
+ const part = parts[i];
50
+ if (!current[part] || typeof current[part] !== 'object') {
51
+ current[part] = {};
52
+ }
53
+
54
+ current = current[part];
55
+ }
56
+
57
+ current[parts[parts.length - 1]] = value;
58
+
59
+ // Notify subscribers
60
+ this._notifySubscribers(path, value);
61
+ }
62
+ }
@@ -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 { pascalCase, isString } from './core_tools.js';
17
+ import { isString } from './core_tools.js';
18
18
 
19
19
  export const unitless: Record<string,1> = {
20
20
  animationIterationCount: 1,
@@ -82,8 +82,8 @@ export function isUnitLess( name: string ) {
82
82
 
83
83
  export class Stylesheet {
84
84
 
85
- private m_sheet: CSSStyleSheet;
86
- private m_rules: Map<string, number> = new Map( );
85
+ readonly m_sheet: CSSStyleSheet;
86
+ readonly m_rules: Map<string, number> = new Map( );
87
87
 
88
88
  constructor() {
89
89
 
@@ -91,7 +91,7 @@ export class Stylesheet {
91
91
  for(let i=0; i<document.styleSheets.length; i++) {
92
92
  let sheet = document.styleSheets[i];
93
93
  if(sheet.title === name ) {
94
- return <CSSStyleSheet>sheet;
94
+ return sheet;
95
95
  }
96
96
  }
97
97
  }
@@ -101,7 +101,7 @@ export class Stylesheet {
101
101
  const dom = document.createElement( 'style' );
102
102
  dom.setAttribute('id', 'x4-dynamic-css' );
103
103
  document.head.appendChild(dom);
104
- this.m_sheet = <CSSStyleSheet>dom.sheet
104
+ this.m_sheet = dom.sheet
105
105
  }
106
106
  }
107
107