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
@@ -22,9 +22,10 @@
22
22
  min-width: 10px;
23
23
  height: 10px;
24
24
  overflow: hidden;
25
+ aspect-ratio: 1 / 1;
25
26
 
26
27
  svg {
27
28
  width: 100%;
28
29
  height: 100%;
29
30
  }
30
- }
31
+ }
@@ -48,7 +48,6 @@ class SvgLoader {
48
48
  this.waiters.set( file, [resolve] );
49
49
  this._load( file )
50
50
  .then( ( data: string ) => {
51
- console.timeEnd( file );
52
51
  this.cache.set( file, data );
53
52
  const ww = this.waiters.get( file );
54
53
  ww.forEach( cb => cb(data ) );
@@ -58,7 +57,6 @@ class SvgLoader {
58
57
  }
59
58
 
60
59
  private async _load( file: string ): Promise<string> {
61
- console.time( file );
62
60
  const res = await fetch( file );
63
61
  if( res.ok ) {
64
62
  return res.text( );
@@ -103,6 +101,8 @@ export class Icon extends Component<IconProps> {
103
101
  */
104
102
 
105
103
  setIcon( iconId: string ) {
104
+ this.clearContent( );
105
+
106
106
  if( iconId ) {
107
107
  if( iconId.startsWith('var:') ) {
108
108
  do {
@@ -123,9 +123,10 @@ export class Icon extends Component<IconProps> {
123
123
  else {
124
124
  this.setContent( new Component( { tag: "img", attrs: { src: iconId } } ) );
125
125
  }
126
+
127
+ this.removeClass( "empty" );
126
128
  }
127
129
  else {
128
- this.clearContent( );
129
130
  this.addClass( "empty" );
130
131
  }
131
132
  }
@@ -14,8 +14,15 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
+ :root {
18
+ --image-border-drop-hover: var( --accent-background );
19
+ }
17
20
 
18
- .x-image {
21
+ .x4image {
19
22
  position: relative;
20
23
  background: none;
24
+
25
+ &.hit {
26
+ border-color: var( --image-border-drop-hover ) !important;
27
+ }
21
28
  }
@@ -14,11 +14,24 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { class_ns } from '@core/core_tools.js';
18
- import { Component, ComponentProps } from '../../core/component.js';
17
+ import { class_ns } from '../../core/core_tools';
18
+ import { Component, ComponentEvents, ComponentProps } from '../../core/component';
19
+ import { EventCallback, CoreEvent } from '../../core/core_events.js';
20
+ import { dragManager } from '../../core/core_dragdrop.js';
21
+
22
+ import { EvDropChange, FileDialog } from '../filedrop/filedrop';
23
+ import { Menu } from '../menu/menu';
24
+
25
+
19
26
 
20
27
  import "./image.module.scss"
28
+ import { _tr } from '@core/core_i18n.js';
29
+
21
30
 
31
+ interface ImageEvents extends ComponentEvents {
32
+ change: EvDropChange;
33
+ clear: CoreEvent;
34
+ }
22
35
  export interface ImageProps extends ComponentProps {
23
36
  src: string;
24
37
  fit?: "contain" | "cover" | "fill" | "scale-down";
@@ -26,6 +39,12 @@ export interface ImageProps extends ComponentProps {
26
39
  lazy?: boolean;
27
40
  alt?: string;
28
41
  draggable?: boolean;
42
+
43
+ candrop?: boolean;
44
+ accept?: string; // ex: 'image/*'
45
+
46
+ change?: EventCallback<EvDropChange>;
47
+ clear?: EventCallback<CoreEvent>;
29
48
  }
30
49
 
31
50
  /**
@@ -33,11 +52,11 @@ export interface ImageProps extends ComponentProps {
33
52
  */
34
53
 
35
54
  @class_ns( "x4" )
36
- export class Image extends Component<ImageProps> {
55
+ export class Image<P extends ImageProps = ImageProps, E extends ImageEvents = ImageEvents> extends Component<P,E> {
37
56
 
38
57
  private _img: Component;
39
58
 
40
- constructor( props: ImageProps ) {
59
+ constructor( props: P ) {
41
60
  super( props );
42
61
 
43
62
  this._img = new Component( {
@@ -57,6 +76,63 @@ export class Image extends Component<ImageProps> {
57
76
 
58
77
  this.setContent( this._img );
59
78
  this.setImage( props.src );
79
+
80
+ if( props.candrop ) {
81
+ this.mapPropEvents( props, "change", "clear" );
82
+
83
+ let fileDialog = new FileDialog( {
84
+ accept: props.accept,
85
+ multiple: false,
86
+ callback: ( files ) => {
87
+ this.fire( "change", { files } );
88
+ },
89
+ });
90
+
91
+ this.appendContent( fileDialog );
92
+
93
+ this.addDOMEvent( "click", ( ) => fileDialog.showDialog() );
94
+
95
+ const filterInput = ( _: Component, data: DataTransfer ) => {
96
+ // check that input is of type image
97
+ if( data.items?.length ) {
98
+ const type = data.items[0].type;
99
+ if( /image\/.*/.test(type) ) {
100
+ return true;
101
+ }
102
+ }
103
+
104
+ return false;
105
+ }
106
+
107
+ dragManager.registerDropTarget( this, async ( cmd, el, infos ) => {
108
+ if( cmd=="enter" ) {
109
+ this.addClass( "hit" );
110
+ }
111
+ else if( cmd=='leave' ) {
112
+ this.removeClass( "hit" );
113
+ }
114
+ else if( cmd=='drop' ) {
115
+ if( infos.data.files && infos.data.files.length>0 ) {
116
+ const files = infos.data.files;
117
+ this.fire( "change", { files } );
118
+ }
119
+ }
120
+ }, filterInput );
121
+
122
+ this.addDOMEvent( "contextmenu", ( ev ) => {
123
+ const menu = new Menu( {
124
+ items: [
125
+ { text: _tr.global.cut, click: ( ) => {
126
+ this.fire( "clear", {} );
127
+ } },
128
+ ]
129
+ });
130
+
131
+ menu.displayAt( ev.pageX, ev.pageY );
132
+ ev.stopPropagation( );
133
+ ev.preventDefault( );
134
+ });
135
+ }
60
136
  }
61
137
 
62
138
  /**
@@ -64,6 +140,29 @@ export class Image extends Component<ImageProps> {
64
140
  */
65
141
 
66
142
  setImage( src: string ) {
67
- this._img.setAttribute( "src", src );
143
+ if( src ) {
144
+ this._img.setAttribute( "src", src );
145
+ }
146
+ else {
147
+ this.clear( );
148
+ }
149
+ }
150
+
151
+ /**
152
+ *
153
+ */
154
+
155
+ setBase64( mime: string, base64: string ) {
156
+ this.setImage( "data:"+mime+";base64,"+base64 );
157
+ }
158
+
159
+ /**
160
+ *
161
+ */
162
+
163
+ clear( ) {
164
+ this._img.setAttribute( "src", 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' );
68
165
  }
69
- }
166
+ }
167
+
168
+
@@ -19,6 +19,8 @@
19
19
  --input-sel-color: var( --accent-color );
20
20
  --input-placeholder: var( --disabled-background );
21
21
  --input-error: var( --alert-background );
22
+
23
+ --input-checkbox-color: var( --accent-background );
22
24
  }
23
25
 
24
26
  input.x4input {
@@ -34,17 +36,20 @@ input.x4input {
34
36
 
35
37
  &[type="text"],
36
38
  &[type="password"],
39
+ &[type="date"],
40
+ &[type="number"],
37
41
  &[type="email"] {
38
- padding: 8px 4px;
42
+ padding: 4px 4px;
39
43
  }
40
44
 
41
45
  &[type="checkbox"]:checked,
42
46
  &[type="radio"]:checked {
43
- accent-color: var( --color-80 );
47
+ accent-color: var( --input-checkbox-color );
48
+ padding: 2px;
44
49
  }
45
50
 
46
51
  &[type="range"] {
47
- accent-color: var( --color-60 );
52
+ accent-color: var( --input-checkbox-color );
48
53
  }
49
54
 
50
55
  &::placeholder {
@@ -14,13 +14,21 @@
14
14
  * that can be found in the LICENSE file or at https://opensource.org/licenses/MIT.
15
15
  **/
16
16
 
17
- import { Component, ComponentProps } from '../../core/component';
18
- import { class_ns, IComponentInterface, IFormElement } from '../../core/core_tools.js';
17
+ import { EventCallback } from '@core/core_events.js';
18
+ import { Component, ComponentEvent, ComponentProps, EvChange, EvFocus } from '../../core/component';
19
+ import { class_ns, formatIntlDate, IComponentInterface, IFormElement, isString } from '../../core/core_tools.js';
19
20
 
20
21
  import "./input.module.scss"
21
22
 
22
23
  export interface BaseProps extends ComponentProps {
23
24
  name?: string;
25
+ autofocus?: boolean;
26
+ required?: boolean;
27
+ readonly?: boolean;
28
+ placeholder?: string;
29
+
30
+ focus?: EventCallback<EvFocus>;
31
+ change?: EventCallback<EvChange>;
24
32
  }
25
33
 
26
34
  interface CheckboxProps extends BaseProps {
@@ -31,73 +39,92 @@ interface CheckboxProps extends BaseProps {
31
39
 
32
40
  interface RadioProps extends BaseProps {
33
41
  type: "radio";
34
- value: boolean | number | string;
42
+ value?: boolean | number | string;
35
43
  checked?: boolean;
36
44
  }
37
45
 
38
46
  export interface RangeProps extends BaseProps {
39
47
  type: "range";
40
- value: number;
48
+ value?: number;
41
49
  min: number;
42
50
  max: number;
43
51
  step?: number;
44
52
  }
45
53
 
46
- interface DateProps extends BaseProps {
54
+ export interface FileProps extends BaseProps {
55
+ type: "file";
56
+ accept: string | string[];
57
+ value?: never;
58
+ }
59
+
60
+
61
+ export interface DateProps extends BaseProps {
47
62
  type: "date";
63
+ value?: Date | string;
64
+ }
65
+
66
+ export interface TimeProps extends BaseProps {
67
+ type: "time";
48
68
  readonly?: boolean;
49
69
  required?: boolean;
50
- value: Date | string;
70
+ value?: string;
51
71
  }
52
72
 
53
- interface NumberProps extends BaseProps {
73
+ export interface NumberProps extends BaseProps {
54
74
  type: "number";
55
75
  readonly?: boolean;
56
76
  required?: boolean;
57
- value: number | string;
77
+ value?: number | string;
58
78
  min?: number;
59
79
  max?: number;
60
80
  step?: number;
61
81
  }
62
82
 
63
- interface FileProps extends BaseProps {
64
- type: "file";
65
- accept: string | string[];
66
- }
67
-
68
83
  export interface TextInputProps extends BaseProps {
69
- type: "text" | "email" | "password";
84
+ type?: "text" | "email" | "password";
70
85
  readonly?: boolean;
71
86
  required?: boolean;
72
87
  pattern?: string;
73
- value: string | number;
74
- placeholder?: string;
88
+ value?: string | number;
75
89
  spellcheck?: boolean;
90
+ minlength?: number;
91
+ maxlength?: number;
76
92
  }
77
93
 
78
94
 
79
- export type InputProps = CheckboxProps | RadioProps | TextInputProps | RangeProps | DateProps | NumberProps | FileProps;
95
+ export type InputProps = TextInputProps | CheckboxProps | RadioProps | RangeProps | DateProps | NumberProps | FileProps | TimeProps;
80
96
 
81
97
 
98
+ interface InputEvents extends ComponentEvent {
99
+ focus: EvFocus;
100
+ change: EvChange;
101
+ }
102
+
82
103
 
83
104
  /**
84
105
  *
85
106
  */
86
107
 
87
108
  @class_ns( "x4" )
88
- export class Input extends Component<InputProps> {
109
+ export class Input extends Component<InputProps,InputEvents> {
89
110
  constructor( props: InputProps ) {
90
111
  super( { tag: "input", ...props } );
91
112
 
113
+ this.mapPropEvents( props, "focus", "change" );
114
+
92
115
  this.setAttribute( "type", props.type ?? "text" );
93
116
  this.setAttribute( "name", props.name );
117
+
118
+ if( props.autofocus===true ) {
119
+ this.setAttribute( "autofocus", true );
120
+ }
94
121
 
95
122
  switch( props.type ) {
96
123
  case "checkbox":
97
124
  case "radio": {
98
125
  const ck = this.dom as HTMLInputElement;
99
126
  ck.checked = props.checked;
100
- ck.value = props.value+"";
127
+ ck.value = props.value === undefined ? "" : props.value+"";
101
128
  //this.setAttribute( "checked", props.checked );
102
129
  //this.setAttribute( "value", props.value );
103
130
  break;
@@ -112,12 +139,27 @@ export class Input extends Component<InputProps> {
112
139
  }
113
140
 
114
141
  case "number": {
115
- this.setAttribute( "required", props.required );
116
- this.setAttribute( "readonly", props.readonly );
117
- this.setAttribute( "min", props.min );
118
- this.setAttribute( "max", props.max );
119
- this.setAttribute( "step", props.step );
120
- this.setAttribute( "value", props.value+'' );
142
+ const p = this.props as NumberProps;
143
+
144
+ this.setAttribute( "required", p.required );
145
+ this.setAttribute( "readonly", p.readonly );
146
+ this.setAttribute( "min", p.min );
147
+ this.setAttribute( "max", p.max );
148
+ this.setAttribute( "step", p.step );
149
+ //this.setAttribute( "value", p.value+'' );
150
+ this.setNumValue( isString(p.value) ? parseFloat(p.value) : p.value, -2 );
151
+
152
+ this.addDOMEvent( "wheel", ( e: WheelEvent ) => {
153
+ if( this.hasFocus() ) { // only if has focus
154
+ e.preventDefault( );
155
+ let v = this.getNumValue();
156
+ const delta = e.deltaY < 0 ? 1 : -1;
157
+ v += (p.step ? p.step : 1) * delta;
158
+ this.setNumValue( v, -2 );
159
+
160
+ this.dom.dispatchEvent(new Event('input'));
161
+ }
162
+ }, );
121
163
  break;
122
164
  }
123
165
 
@@ -126,9 +168,9 @@ export class Input extends Component<InputProps> {
126
168
 
127
169
  let v = props.value;
128
170
  if( v instanceof Date ) {
129
- //this.setAttribute( "value", formatDate( v, "Y-M-D" ) );
171
+ this.setAttribute( "value", formatIntlDate( v, "Y-M-D" ) );
130
172
  }
131
- else {
173
+ else if( props.value!==null && props.value!==undefined ) {
132
174
  this.setAttribute( "value", v );
133
175
  }
134
176
 
@@ -148,6 +190,14 @@ export class Input extends Component<InputProps> {
148
190
  break;
149
191
  }
150
192
 
193
+ case "time": {
194
+ this.setAttribute( "required", props.required );
195
+ if( props.value!==null && props.value!==undefined ) {
196
+ this.setAttribute( "value", props.value );
197
+ }
198
+ break;
199
+ }
200
+
151
201
  default: {
152
202
  this.setAttribute( "required", props.required );
153
203
  this.setAttribute( "readonly", props.readonly );
@@ -168,9 +218,48 @@ export class Input extends Component<InputProps> {
168
218
  this.setAttribute( "spellcheck", false );
169
219
  }
170
220
 
221
+ if( props.minlength!==undefined ) {
222
+ this.setAttribute( "minlength", props.minlength );
223
+ }
224
+
225
+ if( props.maxlength!==undefined ) {
226
+ this.setAttribute( "maxlength", props.maxlength );
227
+ }
228
+
171
229
  break;
172
230
  }
173
231
  }
232
+
233
+ this.addDOMEvent( "blur", ( e ) => { this.on_focus(e,true);} );
234
+ this.addDOMEvent( "focus", ( e ) => { this.on_focus(e,false);} );
235
+ this.addDOMEvent( "input", ( e ) => { this.on_change(e as InputEvent); });
236
+ }
237
+
238
+ /**
239
+ *
240
+ */
241
+
242
+ private on_focus( ev: FocusEvent, focus_out: boolean ) {
243
+ const event: EvFocus = { focus_out }
244
+ this.fire( "focus", event );
245
+
246
+ if( event.defaultPrevented ) {
247
+ ev.preventDefault( );
248
+ }
249
+ }
250
+
251
+ /**
252
+ *
253
+ */
254
+
255
+ private on_change( ev: InputEvent ) {
256
+
257
+ const event: EvChange = { value: this.getValue() };
258
+ this.fire( "change", event );
259
+
260
+ if( event.defaultPrevented ) {
261
+ ev.preventDefault( );
262
+ }
174
263
  }
175
264
 
176
265
  /**
@@ -195,19 +284,60 @@ export class Input extends Component<InputProps> {
195
284
  * @returns
196
285
  */
197
286
 
198
- public getNumValue( ) {
199
- return parseFloat( this.getValue() );
287
+ public getNumValue( defNan?: number ) {
288
+ const v = parseFloat( this.getValue() );
289
+ if( isNaN(v) && defNan!==undefined ) {
290
+ return defNan;
291
+ }
292
+ return v;
200
293
  }
201
294
 
202
295
  /**
203
296
  *
204
297
  * @param value
298
+ * @param ndec number of decimals or -1 for auto, -2 as prop.step
299
+ *
205
300
  */
206
301
 
207
- public setNumValue( value: number ) {
302
+ public setNumValue( value: number, ndec = -1 ) {
303
+
304
+ if( ndec==-2 && this.props.type=='number' ) {
305
+ const p = this.props as NumberProps;
306
+
307
+ if( p.step<1 ) {
308
+ let ndec = -Math.floor(Math.log10(p.step ?? 1) );
309
+ return this.setValue( value.toFixed(ndec) );
310
+ }
311
+ else if( p.step>1 ) {
312
+ return this.setValue( value.toFixed() );
313
+ }
314
+ }
315
+ else if( ndec>=0 ) {
316
+ return this.setValue( value.toFixed(ndec) );
317
+ }
318
+
208
319
  this.setValue( value+"" );
209
320
  }
210
321
 
322
+ /**
323
+ * @return the checked value
324
+ */
325
+
326
+ public getCheck() {
327
+ const d = this.dom as HTMLInputElement;
328
+ return d.checked;
329
+ }
330
+
331
+ /**
332
+ * change the checked value
333
+ * @param {boolean} ck new checked value
334
+ */
335
+
336
+ public setCheck(ck: boolean) {
337
+ const d = this.dom as HTMLInputElement;
338
+ d.checked = ck;
339
+ }
340
+
211
341
  /**
212
342
  *
213
343
  */
@@ -250,6 +380,22 @@ export class Input extends Component<InputProps> {
250
380
  };
251
381
  }
252
382
 
383
+ /**
384
+ *
385
+ */
386
+
387
+ public isValid( ) {
388
+
389
+ if( (this.props as any).required ) {
390
+ const v = this.getValue( );
391
+ if( v==="" ) {
392
+ return false;
393
+ }
394
+ }
395
+
396
+ return true;
397
+ }
398
+
253
399
  /**
254
400
  *
255
401
  */
@@ -258,7 +404,8 @@ export class Input extends Component<InputProps> {
258
404
  if( name=="form-element" ) {
259
405
  const i: IFormElement = {
260
406
  getRawValue: ( ): any => { return this.getValue(); },
261
- setRawValue: ( v: any ) => { this.setValue(v); }
407
+ setRawValue: ( v: any ) => { this.setValue(v); },
408
+ isValid: ( ) => { return this.isValid(); }
262
409
  };
263
410
 
264
411
  //@ts-ignore
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" fill="currentColor"><!--!Font Awesome Free 6.7.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2 160 448c0 17.7 14.3 32 32 32s32-14.3 32-32l0-306.7L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" fill="currentColor"><!--!Font Awesome Free 6.7.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M576 128c0-35.3-28.7-64-64-64L205.3 64c-17 0-33.3 6.7-45.3 18.7L9.4 233.4c-6 6-9.4 14.1-9.4 22.6s3.4 16.6 9.4 22.6L160 429.3c12 12 28.3 18.7 45.3 18.7L512 448c35.3 0 64-28.7 64-64l0-256zM271 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" fill="currentColor"><!--!Font Awesome Free 6.7.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zm151 118.3C226 97.7 269.5 80 320 80c65.2 0 118.8 29.6 159.9 67.7C518.4 183.5 545 226 558.6 256c-12.6 28-36.6 66.8-70.9 100.9l-53.8-42.2c9.1-17.6 14.2-37.5 14.2-58.7c0-70.7-57.3-128-128-128c-32.2 0-61.7 11.9-84.2 31.5l-46.1-36.1zM394.9 284.2l-81.5-63.9c4.2-8.5 6.6-18.2 6.6-28.3c0-5.5-.7-10.9-2-16c.7 0 1.3 0 2 0c44.2 0 80 35.8 80 80c0 9.9-1.8 19.4-5.1 28.2zm9.4 130.3C378.8 425.4 350.7 432 320 432c-65.2 0-118.8-29.6-159.9-67.7C121.6 328.5 95 286 81.4 256c8.3-18.4 21.5-41.5 39.4-64.8L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5l-41.9-33zM192 256c0 70.7 57.3 128 128 128c13.3 0 26.1-2 38.2-5.8L302 334c-23.5-5.4-43.1-21.2-53.7-42.3l-56.1-44.2c-.2 2.8-.3 5.6-.3 8.5z"/></svg>