5htp-core 0.2.1 → 0.2.2

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 (68) hide show
  1. package/package.json +10 -3
  2. package/src/client/app/index.ts +2 -2
  3. package/src/client/assets/css/components/card.less +0 -3
  4. package/src/client/assets/css/components/other.less +2 -4
  5. package/src/client/assets/css/components/table.less +1 -2
  6. package/src/client/assets/css/components.less +4 -0
  7. package/src/client/assets/css/core.less +0 -1
  8. package/src/client/assets/css/theme.less +2 -2
  9. package/src/client/assets/css/utils/medias.less +21 -0
  10. package/src/client/components/Card/index.tsx +8 -5
  11. package/src/client/components/Dialog/index.less +3 -3
  12. package/src/client/components/Row/index.less +2 -0
  13. package/src/client/components/Row/index.tsx +44 -10
  14. package/src/client/components/Video/index.less +39 -0
  15. package/src/client/components/Video/index.tsx +69 -0
  16. package/src/client/components/containers/Popover/index.tsx +2 -2
  17. package/src/client/components/data/Time.tsx +1 -1
  18. package/src/client/components/data/progressbar/circular/index.tsx +1 -1
  19. package/src/client/components/index.ts +24 -8
  20. package/src/client/components/input/BaseV2/index.tsx +0 -1
  21. package/src/client/components/{input/BaseV2/index.less → inputv3/base.less} +1 -1
  22. package/src/client/components/inputv3/base.tsx +73 -0
  23. package/src/client/components/{input/UploadImage → inputv3/file}/Bouton.tsx +0 -0
  24. package/src/client/components/inputv3/file/FileToUpload.ts +34 -0
  25. package/src/client/components/inputv3/file/index.less +59 -0
  26. package/src/client/components/inputv3/file/index.tsx +157 -0
  27. package/src/client/components/{input → inputv3/string}/index.tsx +41 -27
  28. package/src/client/pages/bug.tsx +3 -4
  29. package/src/client/services/router/index.tsx +0 -1
  30. package/src/client/services/router/request/api.ts +20 -12
  31. package/src/client/services/router/request/multipart.ts +27 -0
  32. package/src/common/data/chaines/greetings.ts +1 -1
  33. package/src/common/data/dates.ts +1 -1
  34. package/src/common/data/input/validate.ts +0 -9
  35. package/src/common/data/markdown.ts +1 -1
  36. package/src/common/errors/index.ts +16 -12
  37. package/src/common/router/request/api.ts +11 -3
  38. package/src/common/validation/schema.ts +21 -20
  39. package/src/common/validation/validators.ts +3 -6
  40. package/src/server/app/commands.ts +149 -0
  41. package/src/server/app/index.ts +23 -4
  42. package/src/server/app/service.ts +4 -0
  43. package/src/server/services/cache/commands.ts +41 -0
  44. package/src/server/services/cache/index.ts +102 -34
  45. package/src/server/services/console/index.ts +1 -1
  46. package/src/server/services/database/connection.ts +38 -22
  47. package/src/server/services/database/datatypes.ts +51 -12
  48. package/src/server/services/database/index.ts +133 -40
  49. package/src/server/services/database/metas.ts +63 -37
  50. package/src/server/services/database/repository.ts +26 -0
  51. package/src/server/services/email/index.ts +102 -42
  52. package/src/server/services/fetch/index.ts +110 -0
  53. package/src/server/services/router/http/multipart.ts +70 -41
  54. package/src/server/services/router/index.ts +35 -4
  55. package/src/server/services/router/request/index.ts +8 -6
  56. package/src/server/services/schema/index.ts +4 -11
  57. package/src/server/services/schema/request.ts +16 -7
  58. package/src/server/services/schema/router.ts +6 -2
  59. package/src/server/{services_old → services/security/encrypt}/aes.ts +33 -14
  60. package/src/server/services/users/index.ts +3 -3
  61. package/src/server/services/users/router/index.ts +0 -2
  62. package/src/types/global/utils.d.ts +11 -1
  63. package/tsconfig.common.json +3 -0
  64. package/src/client/components/input/Textarea.tsx +0 -57
  65. package/src/client/components/input/Upload.tsx +0 -5
  66. package/src/client/components/input/UploadImage/index.less +0 -93
  67. package/src/client/components/input/UploadImage/index.tsx +0 -220
  68. package/src/common/data/file.ts +0 -25
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.2.1",
4
+ "version": "0.2.2",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -35,6 +35,7 @@
35
35
  "express-fileupload": "^1.2.1",
36
36
  "express-static-gzip": "^2.1.1",
37
37
  "fast-safe-stringify": "^2.1.1",
38
+ "formattor": "^0.0.2",
38
39
  "fs-extra": "^10.1.0",
39
40
  "google-auth-library": "^7.11.0",
40
41
  "got": "^11.8.3",
@@ -52,10 +53,12 @@
52
53
  "locale": "^0.1.0",
53
54
  "markdown-it": "^13.0.1",
54
55
  "md5": "^2.3.0",
56
+ "mime-types": "^2.1.35",
55
57
  "module-alias": "^2.2.2",
56
58
  "morgan": "^1.10.0",
57
59
  "mysql2": "^2.3.0",
58
60
  "nodemailer": "^6.6.3",
61
+ "object-sizeof": "^1.6.3",
59
62
  "path-to-regexp": "^6.2.0",
60
63
  "picomatch": "^2.3.1",
61
64
  "preact": "^10.5.15",
@@ -73,17 +76,21 @@
73
76
  "uuid-by-string": "^3.0.4",
74
77
  "validator": "^13.7.0",
75
78
  "ws": "^8.2.2",
76
- "yaml": "^1.10.2"
79
+ "yaml": "^1.10.2",
80
+ "yargs-parser": "^21.1.1"
77
81
  },
78
82
  "devDependencies": {
79
83
  "@types/cookie": "^0.4.1",
80
84
  "@types/express": "^4.17.13",
81
85
  "@types/fs-extra": "^9.0.12",
86
+ "@types/markdown-it": "^12.2.3",
87
+ "@types/mime-types": "^2.1.1",
82
88
  "@types/node": "^16.9.1",
83
89
  "@types/nodemailer": "^6.4.4",
84
90
  "@types/universal-analytics": "^0.4.5",
85
91
  "@types/webpack-env": "^1.16.2",
86
92
  "@types/ws": "^7.4.7",
87
- "babel-plugin-glob-import": "^0.0.3"
93
+ "@types/yargs-parser": "^21.0.0",
94
+ "babel-plugin-glob-import": "^0.0.6-2"
88
95
  }
89
96
  }
@@ -8,7 +8,7 @@ if (typeof window === 'undefined')
8
8
  window.dev && require('preact/debug');
9
9
 
10
10
  // Core
11
- import { Erreur } from '@common/errors';
11
+ import { CoreError } from '@common/errors';
12
12
  import type { Layout } from '@common/router';
13
13
  import { createDialog } from '@client/components/Dialog/Manager';
14
14
 
@@ -102,7 +102,7 @@ export default abstract class Application {
102
102
  })
103
103
  }
104
104
 
105
- public handleError( error: Erreur | Error, httpCode?: number ) {
105
+ public handleError( error: CoreError | Error, httpCode?: number ) {
106
106
 
107
107
  /*console.error(`[api] Network error:`, e);
108
108
  context.toast.error("Please check your internet connection and try again.", undefined, null, { autohide: false });*/
@@ -3,9 +3,6 @@
3
3
  ----------------------------------*/
4
4
  @import (reference) "../theme.less";
5
5
 
6
- @cardPadding: @spacing * 1.5;
7
- @cardPaddingLong: @spacing * 2;
8
-
9
6
  /*----------------------------------
10
7
  - COMPONENTS
11
8
  ----------------------------------*/
@@ -20,13 +20,11 @@
20
20
 
21
21
  line-height: 1.5;
22
22
  font-weight: 600;
23
+ text-align: left;
23
24
 
24
- padding: 0px @spacing;
25
+ padding: 0.4em @spacing;
25
26
 
26
27
  background: var(--cBgAccent);
27
-
28
- height: 2em;
29
- line-height: 2em;
30
28
  }
31
29
 
32
30
  .bg-cover {
@@ -17,11 +17,10 @@ table {
17
17
  td, th {
18
18
 
19
19
  padding: 1em 1em;
20
- text-align: center;
20
+ text-align: left;
21
21
 
22
22
  &:first-child {
23
23
  padding-left: 2em;
24
- text-align: left;
25
24
  }
26
25
 
27
26
  &:last-child:not(:first-child) {
@@ -4,7 +4,10 @@
4
4
  @import './text/icons.less';
5
5
  @import './text/titres.less';
6
6
 
7
+ // TODO: move all less files to component folder
8
+
7
9
  // Components
10
+ @import '@client/components/Video/index.less';
8
11
  @import './components/input.less';
9
12
  @import './components/button.less';
10
13
  @import './components/lists.less';
@@ -18,6 +21,7 @@
18
21
  // Les classes utilitaires override les classes de composant
19
22
  @import './utils/borders.less';
20
23
  @import './utils/layouts.less';
24
+ @import './utils/medias.less';
21
25
 
22
26
  .white-card() {
23
27
  background: white;
@@ -1,5 +1,4 @@
1
1
  // Utils
2
- @import './utils/medias.less';
3
2
  @import './utils/sizing.less';
4
3
  @import './utils/spacing.less';
5
4
  @import (reference) "./theme.less";
@@ -41,9 +41,9 @@
41
41
  // Childrens
42
42
  & when (@apply = true) {
43
43
  background: var(--cBg);
44
- .input {
44
+ /*.input.text {
45
45
  border: if(@bg = #ffffff, solid 2px var(--cLine), none);
46
- }
46
+ }*/
47
47
  }
48
48
 
49
49
  .overlay {
@@ -41,6 +41,27 @@ img {
41
41
  background-size: cover;
42
42
  background-repeat: no-repeat;
43
43
  background-position: center;
44
+
45
+ &.colorize {
46
+ position: relative;
47
+
48
+ &::after {
49
+ content: ' ';
50
+ display: block;
51
+ background-color: inherit;
52
+ opacity: 0.5;
53
+ border-radius: inherit;
54
+
55
+ position: absolute;
56
+ top: 0; right: 0; bottom: 0; left: 0;
57
+ z-index: 1;
58
+ }
59
+
60
+ > * {
61
+ z-index: 2;
62
+ position: relative;
63
+ }
64
+ }
44
65
  }
45
66
 
46
67
  img.img {
@@ -24,7 +24,7 @@ type TMeta = {
24
24
  }
25
25
 
26
26
  export type Props = {
27
- title: string,
27
+ title: ComponentChild,
28
28
  link?: string,
29
29
  cover?: {
30
30
  color?: string,
@@ -32,14 +32,15 @@ export type Props = {
32
32
  title?: string,
33
33
  logo?: ComponentChild
34
34
  },
35
- metas: TMeta[],
35
+ metas?: TMeta[],
36
36
  class?: string,
37
+ footer?: ComponentChild
37
38
  }
38
39
 
39
40
  /*----------------------------------
40
41
  - COMPONENT
41
42
  ----------------------------------*/
42
- export default ({ title, link, cover, metas, class: className = '' }: Props) => {
43
+ export default ({ title, link, cover, metas, class: className = '', footer }: Props) => {
43
44
 
44
45
  if (link)
45
46
  className += ' clickable';
@@ -49,8 +50,8 @@ export default ({ title, link, cover, metas, class: className = '' }: Props) =>
49
50
  <article class={"card col " + className}>
50
51
 
51
52
  {cover && (
52
- <header class="bg img row al-left cover pdb-1" style={{
53
- backgroundColor: cover.color,
53
+ <header class="bg img colorize row al-left cover pdb-1" style={{
54
+ backgroundColor: '#' + cover.color,
54
55
  backgroundImage: cover.image
55
56
  ? 'url(' + cover.image + ')'
56
57
  : undefined
@@ -87,6 +88,8 @@ export default ({ title, link, cover, metas, class: className = '' }: Props) =>
87
88
  ))}
88
89
  </ul>
89
90
  )}
91
+
92
+ {footer}
90
93
 
91
94
  </article>
92
95
  )
@@ -13,7 +13,7 @@
13
13
 
14
14
  &,
15
15
  > .modal {
16
- position: absolute;
16
+ position: fixed;
17
17
  top: 0px;
18
18
  left: 0px;
19
19
  right: 0px;
@@ -82,8 +82,8 @@
82
82
  gap: @spacing;
83
83
  z-index: @modal-zindex;
84
84
 
85
- background: fade(#000, 30%);
86
- backdrop-filter: blur(50px) saturate(2);
85
+ background: fade(#fff, 20%);
86
+ backdrop-filter: blur(30px) saturate(2);
87
87
  border-radius: @radius;
88
88
 
89
89
  // Desktop = vertically center the modal
@@ -9,8 +9,10 @@
9
9
  overflow: hidden;
10
10
  position: relative;
11
11
  left: 0;
12
+ z-index: 0;
12
13
 
13
14
  > .row {
15
+ transition: left .2s ease-out;
14
16
  justify-content: flex-start;
15
17
  padding: 0 @spacing;
16
18
  }
@@ -17,18 +17,24 @@ import './index.less';
17
17
  ----------------------------------*/
18
18
 
19
19
  export type Props = {
20
- children: ComponentChild
20
+ children: ComponentChild,
21
+ elevator?: React.HTMLAttributes<HTMLDivElement>
21
22
  }
22
23
 
23
24
  /*----------------------------------
24
25
  - COMPONENT
25
26
  ----------------------------------*/
26
- export default ({ children }: Props) => {
27
+ export default ({ children, elevator = {} }: Props) => {
27
28
 
28
29
  const containerRef = React.useRef<HTMLDivElement>();
29
- const [leftPos, setLeftPos] = React.useState<number>(0);
30
+ const [containerHeight, setContainerHeight] = React.useState<number>(undefined);
31
+ const [scroll, setScroll] = React.useState({
32
+ pos: 0,
33
+ left: false,
34
+ right: true
35
+ });
30
36
 
31
- const moveTo = (sens: number) => {
37
+ const moveTo = (direction: number) => {
32
38
 
33
39
  const container = containerRef.current;
34
40
  if (container === null)
@@ -41,25 +47,53 @@ export default ({ children }: Props) => {
41
47
  const containerWidth = container.getBoundingClientRect().width;
42
48
  const rowWidth = row.getBoundingClientRect().width;
43
49
 
44
- console.log({ containerWidth, rowWidth });
50
+ setScroll( curPos => {
51
+
52
+ const newPos = {
53
+ pos: curPos.pos + (-1 * direction * containerWidth),
54
+ left: true,
55
+ right: true
56
+ };
57
+
58
+ // Scroll Left limit
59
+ const leftPosLim = 0 - rowWidth + containerWidth;
60
+ if (newPos.pos < leftPosLim) {
61
+ newPos.pos = leftPosLim;
62
+ newPos.right = false;
63
+ }
64
+
65
+ // Scroll Left limit
66
+ if (newPos.pos > 0) {
67
+ newPos.pos = 0;
68
+ newPos.left = false;
69
+ }
70
+
71
+ return newPos;
72
+ });
45
73
 
46
74
  }
47
75
 
48
76
  React.useEffect(() => {
49
77
 
50
78
  // If row oveflow, show horizontal arroxs
51
- console.log({ containerRef });
52
-
79
+ setContainerHeight( containerRef.current.getBoundingClientRect().height );
53
80
 
54
81
  }, []);
55
82
 
56
83
  return (
57
- <div class="scrollable-row stopLeft">
84
+ <div class={"scrollable-row" + (scroll.left ? '' : ' stopLeft') + (scroll.right ? '' : ' stopRight')}>
58
85
 
59
86
  <Button class="left" shape="pill" icon="arrow-left" onClick={() => moveTo(-1)} />
60
87
 
61
- <div class="container" ref={containerRef}>
62
- <div class="row" style={{ left: leftPos + 'px' }}>
88
+ <div class="container" ref={containerRef} style={{
89
+ height: containerHeight ? containerHeight + 'px' : undefined
90
+ }}>
91
+ <div {...elevator} class={"row " + (elevator.class || '')} style={{
92
+ left: scroll.pos + 'px',
93
+ position: containerHeight === undefined
94
+ ? 'relative'
95
+ : 'absolute'
96
+ }}>
63
97
  {children}
64
98
  </div>
65
99
  </div>
@@ -0,0 +1,39 @@
1
+ .video {
2
+ .build-theme-bg(#000, #fff);
3
+
4
+ position: relative;
5
+ text-shadow: 0 0 10px fade(#000, 20%);
6
+ border-radius: @radius;
7
+
8
+ --cTxtDiscret: fade(#fff, 40%)
9
+ --cTxtDesc: fade(#fff, 60%);
10
+ --cTxtBase: fade(#fff, 80%);
11
+ --cTxtImportant: fade(#fff, 100%);
12
+ --cTxtAccent: fade(#fff, 20%);
13
+
14
+ &.light {
15
+ --cTxtDiscret: fade(#000, 40%)
16
+ --cTxtDesc: fade(#000, 60%);
17
+ --cTxtBase: fade(#000, 80%);
18
+ --cTxtImportant: fade(#000, 100%);
19
+ --cTxtAccent: fade(#000, 20%);
20
+ }
21
+
22
+ > img.preview,
23
+ > .actions {
24
+ position: absolute;
25
+ top: 0;
26
+ left: 0;
27
+ width: 100%;
28
+ height: 100%;
29
+ border-radius: inherit;
30
+ }
31
+
32
+ > img.preview {
33
+ object-fit: cover;
34
+ }
35
+
36
+ > .actions {
37
+
38
+ }
39
+ }
@@ -0,0 +1,69 @@
1
+ /*----------------------------------
2
+ - DEPS
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import { ComponentChild } from 'preact';
8
+
9
+ // Core
10
+ import Button from '../button';
11
+
12
+ /*----------------------------------
13
+ - TYPES
14
+ ----------------------------------*/
15
+
16
+ export type Config = {
17
+ src: string,
18
+ previewImg: string,
19
+ color?: string
20
+ }
21
+
22
+ /*----------------------------------
23
+ - COMPONENT
24
+ ----------------------------------*/
25
+ export default ({ src, previewImg, color = '000000' }: Config) => {
26
+
27
+ /*----------------------------------
28
+ - INIT
29
+ ----------------------------------*/
30
+
31
+ const [state, setState] = React.useState<'inactive'|'loading'|'paused'|'playing'>('inactive');
32
+
33
+ /*----------------------------------
34
+ - ACTIONS
35
+ ----------------------------------*/
36
+
37
+ const play = () => {
38
+ setState('loading');
39
+ }
40
+
41
+ const VideoPlayer = 'video';
42
+
43
+ /*----------------------------------
44
+ - RENDER
45
+ ----------------------------------*/
46
+ return (
47
+ <section class={"video h-4 " + state}>
48
+
49
+ {(state === 'inactive' || state === 'loading') ? (
50
+ <img class="preview" src={previewImg} />
51
+ ) : (
52
+ <VideoPlayer src={src} />
53
+ )}
54
+
55
+ <div class="actions col al-center" style={{
56
+ backgroundColor: '#' + color + 'aa'
57
+ }}>
58
+ {(state === 'inactive' || state === 'paused') ? (
59
+ <Button icon="play" shape="pill" onClick={play} />
60
+ ) : state === 'loading' ? (
61
+ <i src="spin" />
62
+ ) : state === 'playing' ? (
63
+ <Button icon="pause" shape="pill" onClick={play} />
64
+ ) : null}
65
+ </div>
66
+
67
+ </section>
68
+ )
69
+ }
@@ -154,12 +154,12 @@ export default (props: Props) => {
154
154
  ? bouton([menu.data], [menu.index])
155
155
  : bouton(menu.data, menu.index)
156
156
  ) : {})}
157
- icone={icone}
157
+ icon={icone}
158
158
  onClick={onClick && (() => multi
159
159
  ? onClick([menu.data], [menu.index])
160
160
  : onClick(menu.data, menu.index)
161
161
  )}
162
- lien={lien && lien(menu.data, menu.index)}
162
+ link={lien && lien(menu.data, menu.index)}
163
163
  forme="lien"
164
164
  >
165
165
  {label}
@@ -22,7 +22,7 @@ import { timeSince } from '@common/data/dates';
22
22
  - COMPOSANT
23
23
  ----------------------------------*/
24
24
  export default ({ since }: {
25
- since: Date
25
+ since: Parameters<typeof timeSince>[0]
26
26
  }) => {
27
27
 
28
28
  const [text, setDisplay] = React.useState(timeSince(since));
@@ -19,7 +19,7 @@ import {
19
19
  - TYPES
20
20
  ----------------------------------*/
21
21
 
22
- import { TTailleComposant } from '@client/components/_base/types';
22
+ //import { TTailleComposant } from '@client/components/_base/types';
23
23
 
24
24
  type TEtape = {
25
25
  val: number,
@@ -1,18 +1,34 @@
1
+
2
+ export { Link } from '../services/router/components/Link';
1
3
  export { default as Button } from './button';
2
- export { default as Row } from './row';
3
- export { default as Card } from './card';
4
+
5
+ // Containers
6
+ export { default as Card } from './Card';
7
+ export { default as Popover } from './containers/Popover';
4
8
  export { default as Table } from './Table';
5
- export { default as Select } from './Select';
6
- export { default as Amount } from './Amount';
7
- export { default as Logo } from './Logo';
9
+ export { default as Row } from './Row';
10
+
11
+ // Media
12
+ export { default as Logo } from './logo';
13
+ export { default as Video } from './Video';
8
14
 
9
- export { default as Input } from './input';
10
- export { default as Textarea } from './input/Textarea';
15
+ // Input
11
16
  export { default as Number } from './input/Number';
12
17
  export { default as Slider } from './input/Slider';
13
- export { default as Upload } from './input/Upload';
14
18
  export { default as Radio } from './input/Radio';
15
19
 
20
+ // Data
21
+ export { default as Amount } from './Amount';
22
+ export { default as Time } from './data/Time';
23
+ export { default as SpinText } from './data/spintext';
24
+ export { default as Progressbar } from './data/progressbar';
25
+ export { default as CircularProgressbar } from './data/progressbar/circular';
26
+
27
+ // Input V3
28
+ export { default as Select } from './Select';
29
+ export { default as String } from './inputv3/string';
30
+ export { default as File } from './inputv3/file';
31
+
16
32
  // TOD: fix popover component
17
33
  //export { default as Date } from './input/Date';
18
34
  //export { default as Periode } from './input/Periode';
@@ -70,4 +70,3 @@ export function useInput<TValue>(
70
70
  /*----------------------------------
71
71
  - COMPONENT
72
72
  ----------------------------------*/
73
- import './index.less';
@@ -58,7 +58,7 @@
58
58
  label {
59
59
  height: 100%;
60
60
  font-size: 1em;
61
- color: var(--cTxtImportant);
61
+ //color: var(--cTxtImportant);
62
62
  }
63
63
  }
64
64
 
@@ -0,0 +1,73 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import { ComponentChild } from 'preact';
8
+
9
+ // Core libs
10
+ import { useState } from '@client/hooks';
11
+
12
+ /*----------------------------------
13
+ - TYPES
14
+ ----------------------------------*/
15
+
16
+ export type InputBaseProps<TValue> = {
17
+ value: TValue,
18
+ title: string, // Now mandatory
19
+ onChange?: (newValue: TValue) => void,
20
+ }
21
+
22
+ export type TInputState<TValue> = {
23
+ value: TValue,
24
+ fieldProps: {[key: string]: any},
25
+ valueSource: 'internal'|'external',
26
+ focus: boolean,
27
+ }
28
+
29
+ /*----------------------------------
30
+ - HOOKS
31
+ ----------------------------------*/
32
+ export function useInput<TValue>(
33
+ { value: externalValue, onChange }: InputBaseProps<TValue>,
34
+ defaultValue: TValue,
35
+ ): [
36
+ state: TInputState<TValue>,
37
+ setValue: (value: TValue) => void,
38
+ commitValue: () => void,
39
+ setState: (state: Partial<TInputState<TValue>>) => void,
40
+ ] {
41
+
42
+ const [state, setState] = useState<TInputState<TValue>>({
43
+ value: externalValue !== undefined ? externalValue : defaultValue,
44
+ valueSource: 'external',
45
+ fieldProps: {},
46
+ focus: false
47
+ });
48
+
49
+ const setValue = (value: TValue) => setState({ value, valueSource: 'internal' });
50
+
51
+ const commitValue = () => {
52
+ console.log(`[input] Commit value:`, state.value);
53
+ if (onChange !== undefined)
54
+ onChange(state.value);
55
+ }
56
+
57
+ // External value change
58
+ React.useEffect(() => {
59
+
60
+ if (externalValue !== undefined && externalValue !== state.value) {
61
+ console.log("External value change", externalValue);
62
+ setState({ value: externalValue, valueSource: 'external' })
63
+ }
64
+
65
+ }, [externalValue]);
66
+
67
+ return [state, setValue, commitValue, setState]
68
+ }
69
+
70
+ /*----------------------------------
71
+ - COMPONENT
72
+ ----------------------------------*/
73
+ import './base.less';
@@ -0,0 +1,34 @@
1
+ // Normalize file between browser and nodejs side
2
+ export default class FileToUpload {
3
+
4
+ public name: string;
5
+ public size: number;
6
+ public type: string;
7
+
8
+ public data: File;
9
+
10
+ // Retrieved on backend only
11
+ public md5?: string;
12
+ public ext?: string;
13
+
14
+ public constructor(opts: {
15
+ name: string,
16
+ size: number,
17
+ type: string,
18
+
19
+ data: File,
20
+
21
+ md5?: string,
22
+ ext?: string,
23
+ }) {
24
+
25
+ this.name = opts.name;
26
+ this.size = opts.size;
27
+ this.type = opts.type;
28
+
29
+ this.data = opts.data;
30
+
31
+ this.md5 = opts.md5;
32
+ this.ext = opts.ext;
33
+ }
34
+ }