@deviceinsight/ng-ui-components 6.23.0 → 6.25.0

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 (36) hide show
  1. package/lib/cjs/assets/style.css +1 -1
  2. package/lib/cjs/components/input/DateTimeInput.d.ts.map +1 -1
  3. package/lib/cjs/components/input/DateTimeInput.js +35 -5
  4. package/lib/cjs/components/input/__tests__/DateTimeInput.spec.js +21 -0
  5. package/lib/cjs/components/reactable/helpers/ReactableTable.d.ts.map +1 -1
  6. package/lib/cjs/components/reactable/helpers/ReactableTable.js +22 -10
  7. package/lib/cjs/components/upload/FileUpload.d.ts +23 -9
  8. package/lib/cjs/components/upload/FileUpload.d.ts.map +1 -1
  9. package/lib/cjs/components/upload/FileUpload.js +32 -24
  10. package/lib/cjs/components/upload/ImageUpload.d.ts +3 -2
  11. package/lib/cjs/components/upload/ImageUpload.d.ts.map +1 -1
  12. package/lib/cjs/components/upload/ImageUpload.js +13 -6
  13. package/lib/esm/assets/style.css +1 -1
  14. package/lib/esm/components/input/DateTimeInput.d.ts.map +1 -1
  15. package/lib/esm/components/input/DateTimeInput.js +35 -5
  16. package/lib/esm/components/input/__tests__/DateTimeInput.spec.js +22 -1
  17. package/lib/esm/components/reactable/helpers/ReactableTable.d.ts.map +1 -1
  18. package/lib/esm/components/reactable/helpers/ReactableTable.js +22 -10
  19. package/lib/esm/components/upload/FileUpload.d.ts +23 -9
  20. package/lib/esm/components/upload/FileUpload.d.ts.map +1 -1
  21. package/lib/esm/components/upload/FileUpload.js +32 -24
  22. package/lib/esm/components/upload/ImageUpload.d.ts +3 -2
  23. package/lib/esm/components/upload/ImageUpload.d.ts.map +1 -1
  24. package/lib/esm/components/upload/ImageUpload.js +13 -6
  25. package/lib/esm/src/components/input/DateTimeInput.d.ts.map +1 -1
  26. package/lib/esm/src/components/input/DateTimeInput.js +35 -5
  27. package/lib/esm/src/components/input/__tests__/DateTimeInput.spec.js +22 -1
  28. package/lib/esm/src/components/reactable/helpers/ReactableTable.d.ts.map +1 -1
  29. package/lib/esm/src/components/reactable/helpers/ReactableTable.js +22 -10
  30. package/lib/esm/src/components/upload/FileUpload.d.ts +23 -9
  31. package/lib/esm/src/components/upload/FileUpload.d.ts.map +1 -1
  32. package/lib/esm/src/components/upload/FileUpload.js +32 -24
  33. package/lib/esm/src/components/upload/ImageUpload.d.ts +3 -2
  34. package/lib/esm/src/components/upload/ImageUpload.d.ts.map +1 -1
  35. package/lib/esm/src/components/upload/ImageUpload.js +13 -6
  36. package/package.json +24 -24
@@ -74,7 +74,7 @@
74
74
  .di.upload,
75
75
  .di.upload * {transition:all .1s ease;}
76
76
  .di.upload {margin:0; padding:0; width:100%; height:100%; min-height:80px; font-size:16px; border:1px dashed #888; border-radius:4px; overflow:hidden; user-select:none;}
77
- .di.upload {display:flex; align-items:center;}
77
+ .di.upload {display:flex; flex-direction:column; align-items:center;}
78
78
  .di.upload:hover {border-color:#666; background:#f9f9f9;}
79
79
  .di.upload:active {background:#eee;}
80
80
  .di.upload > div {width:100%; height:100%;}
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimeInput.d.ts","sourceRoot":"","sources":["../../../../src/components/input/DateTimeInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAejD,oBAAY,KAAK,GAAG;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,oEAAoE;IACpE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAE7E,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACrC,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,QAAQ,EACR,GAAG,UAAU,EACb,EAAE,KAAK,qBAwDP"}
1
+ {"version":3,"file":"DateTimeInput.d.ts","sourceRoot":"","sources":["../../../../src/components/input/DateTimeInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAwBjD,oBAAY,KAAK,GAAG;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,oEAAoE;IACpE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAE7E,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACrC,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,QAAQ,EACR,GAAG,UAAU,EACb,EAAE,KAAK,qBAgFP"}
@@ -26,10 +26,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
+ const dayjs_1 = __importDefault(require("dayjs"));
29
30
  const react_1 = __importStar(require("react"));
30
31
  const periods_1 = require("../periodpicker/periods");
31
32
  const DateInput_1 = __importDefault(require("./DateInput"));
32
33
  const ValidatedTextInput_1 = __importDefault(require("./ValidatedTextInput"));
34
+ const lodash_1 = require("lodash");
33
35
  const extractTime = (timezone, date) => {
34
36
  try {
35
37
  return (0, periods_1.dayjsTz)(timezone, date).format('HH:mm');
@@ -39,6 +41,15 @@ const extractTime = (timezone, date) => {
39
41
  return '00:00';
40
42
  }
41
43
  };
44
+ const extractDate = (timezone, date) => {
45
+ try {
46
+ return (0, dayjs_1.default)((0, periods_1.dayjsTz)(timezone, date).format('YYYY-MM-DD'));
47
+ }
48
+ catch (error) {
49
+ console.error('DateTimeInput: Error while extracting time from date', error);
50
+ return (0, dayjs_1.default)(new Date());
51
+ }
52
+ };
42
53
  /**
43
54
  * Extends DateInput but also displaying the current time.
44
55
  * Usually the user's locale is used for displaying the correct date format.
@@ -51,17 +62,36 @@ function DateTimeInput({ timestamp, timezone, warning, readOnly = false, onChang
51
62
  }, [timezone, timestamp]);
52
63
  function handleChangeDate(date, fromTextField) {
53
64
  const oldDate = (0, periods_1.dayjsTz)(timezone, timestamp);
54
- onChange((0, periods_1.dayjsTz)(timezone, date).set('hour', oldDate.get('hour')).set('minute', oldDate.get('minute')).valueOf(), fromTextField);
65
+ const dateFix = (0, dayjs_1.default)(date);
66
+ let newDate = (0, periods_1.dayjsTz)(timezone, date)
67
+ .set('day', dateFix.day())
68
+ .set('month', dateFix.month())
69
+ .set('year', dateFix.year())
70
+ .set('hour', (0, lodash_1.toInteger)(oldDate.hour()))
71
+ .set('minute', (0, lodash_1.toInteger)(oldDate.minute()));
72
+ const dstOffset = getLocalDstOffset(newDate);
73
+ newDate = newDate.subtract(dstOffset, 'minutes');
74
+ onChange(newDate.valueOf(), fromTextField);
75
+ }
76
+ function getMaxUtcOffset(year) {
77
+ const jan = new Date(`${year}-01-01`).getTimezoneOffset();
78
+ const jul = new Date(`${year}-07-01`).getTimezoneOffset();
79
+ return Math.min(jan, jul);
80
+ }
81
+ function getLocalDstOffset(newDate) {
82
+ return newDate.toDate().getTimezoneOffset() - getMaxUtcOffset(newDate.year());
55
83
  }
56
84
  function handleChangeTime(time, valid) {
57
85
  if (valid) {
58
86
  const [hours, minutes] = time.split(':');
59
- onChange((0, periods_1.dayjsTz)(timezone, timestamp)
87
+ const date = extractDate(timezone, timestamp);
88
+ const dateTime = (0, periods_1.dayjsTz)(timezone, timestamp)
89
+ .set('date', date.date())
60
90
  .set('hour', parseInt(hours, 10))
61
91
  .set('minute', parseInt(minutes, 10))
62
92
  .set('second', 0)
63
- .set('millisecond', 0)
64
- .valueOf());
93
+ .set('millisecond', 0);
94
+ onChange(dateTime.valueOf());
65
95
  }
66
96
  setTime(time);
67
97
  }
@@ -71,7 +101,7 @@ function DateTimeInput({ timestamp, timezone, warning, readOnly = false, onChang
71
101
  }
72
102
  }
73
103
  return (react_1.default.createElement("span", { className: `di date-time-input ${warning ? 'with-warning' : ''}` },
74
- react_1.default.createElement(DateInput_1.default, { ...otherProps, value: timestamp, onChange: handleChangeDate, readOnly: readOnly }),
104
+ react_1.default.createElement(DateInput_1.default, { ...otherProps, value: extractDate(timezone, timestamp).valueOf(), onChange: handleChangeDate, readOnly: readOnly }),
75
105
  react_1.default.createElement(ValidatedTextInput_1.default, { "data-testid": "time-input", value: timeValue, onChange: handleChangeTime, pattern: /^(([01][0-9])|2[0-3]):[0-5][0-9]$/, required: true, invalidStyle: {
76
106
  borderColor: 'red'
77
107
  }, placeholder: "00:00", className: "time", onBlur: tryFixTime, disabled: readOnly })));
@@ -7,6 +7,7 @@ const react_1 = __importDefault(require("react"));
7
7
  const vitest_1 = require("vitest");
8
8
  const DateTimeInput_1 = __importDefault(require("../DateTimeInput"));
9
9
  const react_2 = require("@testing-library/react");
10
+ const testing_library_1 = require("@storybook/testing-library");
10
11
  (0, vitest_1.describe)('DateTimeInput.js', () => {
11
12
  (0, vitest_1.it)('should update time when timestamp has changed', () => {
12
13
  const { rerender } = (0, react_2.render)(react_1.default.createElement(DateTimeInput_1.default, { timestamp: new Date('2019-02-01T11:11:00').getTime(), onChange: () => { } }));
@@ -15,4 +16,24 @@ const react_2 = require("@testing-library/react");
15
16
  rerender(react_1.default.createElement(DateTimeInput_1.default, { timestamp: new Date('2019-02-02T03:24:00').getTime(), onChange: () => { } }));
16
17
  (0, vitest_1.expect)(timeElement).toHaveDisplayValue('03:24');
17
18
  });
19
+ (0, vitest_1.it)('should display the time and date as timezone date', async () => {
20
+ const { rerender } = (0, react_2.render)(react_1.default.createElement(DateTimeInput_1.default, { timestamp: new Date('2019-02-01T11:11:00Z').getTime(), onChange: () => { }, timezone: "America/Vancouver" }));
21
+ const timeElementUtm = react_2.screen.queryByDisplayValue('11:11');
22
+ (0, vitest_1.expect)(timeElementUtm).not.toBeInTheDocument();
23
+ const timeElement = react_2.screen.queryByDisplayValue('03:11');
24
+ (0, vitest_1.expect)(timeElement).toBeInTheDocument();
25
+ const dateElement = react_2.screen.queryByDisplayValue('01.02.2019');
26
+ (0, vitest_1.expect)(dateElement).toBeInTheDocument();
27
+ rerender(react_1.default.createElement(DateTimeInput_1.default, { timestamp: new Date('2019-02-02T03:24:00Z').getTime(), onChange: () => { }, timezone: "America/Vancouver" }));
28
+ (0, vitest_1.expect)(timeElement).toHaveDisplayValue('19:24');
29
+ (0, vitest_1.expect)(dateElement).toHaveDisplayValue('01.02.2019');
30
+ await (0, react_2.act)(async () => {
31
+ dateElement?.click();
32
+ timeElement?.click();
33
+ testing_library_1.userEvent.clear(timeElement);
34
+ testing_library_1.userEvent.type(timeElement, '10:24');
35
+ });
36
+ (0, vitest_1.expect)(timeElement).toHaveDisplayValue('10:24');
37
+ (0, vitest_1.expect)(dateElement).toHaveDisplayValue('01.02.2019');
38
+ });
18
39
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ReactableTable.d.ts","sourceRoot":"","sources":["../../../../../src/components/reactable/helpers/ReactableTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAQzD,OAAO,EAAC,kBAAkB,EAAE,eAAe,EAAE,uBAAuB,EAAC,MAAM,UAAU,CAAC;AACtF,OAAO,EAAC,QAAQ,EAAE,kBAAkB,EAAE,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAGtF,aAAK,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI;IAC9D,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,aAAa,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,EACxF,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EAAE,MAAM,EACrB,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAwHd"}
1
+ {"version":3,"file":"ReactableTable.d.ts","sourceRoot":"","sources":["../../../../../src/components/reactable/helpers/ReactableTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAQzD,OAAO,EAAC,kBAAkB,EAAE,eAAe,EAAE,uBAAuB,EAAC,MAAM,UAAU,CAAC;AACtF,OAAO,EAAC,QAAQ,EAAE,kBAAkB,EAAE,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAGtF,aAAK,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI;IAC9D,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,aAAa,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,EACxF,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EAAE,MAAM,EACrB,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAmId"}
@@ -38,7 +38,8 @@ function ReactableTable({ columnDefs, uniqueItemKey, paginationSettings, onSort,
38
38
  const containerRef = (0, react_1.useRef)(null);
39
39
  const tableRef = (0, react_1.useRef)(null);
40
40
  const [showScrollingAdvice, setShowScrollingAdvice] = (0, react_1.useState)(false);
41
- const [neverShowScrollingAdvice, setNeverShowScrollingAdvice] = (0, react_1.useState)(false);
41
+ const [neverShowScrollingAdvice, setNeverShowScrollingAdvice] = (0, react_1.useState)(true);
42
+ const [hasInitialized, setHasInitialized] = (0, react_1.useState)(false);
42
43
  const HIDE_SCROLLING_ADVICE_PATH = 'uiConfigurations/nevershowscrollingadvice';
43
44
  const neverShowScrollingAdviceRef = (0, react_1.useRef)(neverShowScrollingAdvice);
44
45
  (0, react_1.useEffect)(() => {
@@ -50,14 +51,25 @@ function ReactableTable({ columnDefs, uniqueItemKey, paginationSettings, onSort,
50
51
  }
51
52
  };
52
53
  (0, react_1.useEffect)(() => {
53
- (0, ng_ui_api_client_1.readAccountObject)(HIDE_SCROLLING_ADVICE_PATH).then((value) => {
54
- const neverShow = value === undefined ? false : value;
55
- setNeverShowScrollingAdvice(neverShow);
56
- neverShowScrollingAdviceRef.current = neverShow;
57
- if (containerRef.current && tableRef.current) {
58
- updateScrollingAdvice();
59
- }
60
- });
54
+ setTimeout(() => {
55
+ (async () => {
56
+ try {
57
+ const value = await (0, ng_ui_api_client_1.readAccountObject)(HIDE_SCROLLING_ADVICE_PATH);
58
+ const neverShow = value === true;
59
+ setNeverShowScrollingAdvice(neverShow);
60
+ neverShowScrollingAdviceRef.current = neverShow;
61
+ if (!neverShow) {
62
+ updateScrollingAdvice();
63
+ }
64
+ }
65
+ catch (error) {
66
+ setNeverShowScrollingAdvice(false);
67
+ neverShowScrollingAdviceRef.current = false;
68
+ updateScrollingAdvice();
69
+ }
70
+ setHasInitialized(true);
71
+ })();
72
+ }, 0);
61
73
  }, []);
62
74
  (0, react_1.useEffect)(() => {
63
75
  updateScrollingAdvice();
@@ -67,7 +79,7 @@ function ReactableTable({ columnDefs, uniqueItemKey, paginationSettings, onSort,
67
79
  const showFilterRow = columnDefs.some((col) => col.filterable);
68
80
  return (react_1.default.createElement(ng_ui_basic_components_1.SpinnerContainer, { show: isLoading },
69
81
  react_1.default.createElement("div", { ref: containerRef, className: "di reactable scroll-x" },
70
- showScrollingAdvice && !isLoading && (react_1.default.createElement(ng_ui_basic_components_1.Modal, { className: "scroll-horizontally-advice", content: react_1.default.createElement("div", null,
82
+ hasInitialized && showScrollingAdvice && !isLoading && (react_1.default.createElement(ng_ui_basic_components_1.Modal, { className: "scroll-horizontally-advice", content: react_1.default.createElement("div", null,
71
83
  react_1.default.createElement(i18n_1.Trans, { i18nKey: "reactable.scrollHorizontally.advice" }, "SHIFT + mouse wheel to scroll horizontally"),
72
84
  react_1.default.createElement("div", { className: "scroll-horizontally-advice-buttons" },
73
85
  react_1.default.createElement(ng_ui_basic_components_1.Button, { primary: true, onClick: async () => {
@@ -10,12 +10,8 @@ export declare type PreviewComponentProps = {
10
10
  export declare type Props = {
11
11
  /** (Optional) string for accepting files */
12
12
  accept?: string;
13
- /** Function, executed when a file gets removed */
14
- onRemoveFile: () => void;
15
13
  /** Optional Function, executed to download the file */
16
- onDownloadFile?: () => void;
17
- /** Function, executed when a file gets selected */
18
- onSelectFile: (file: DropzoneFile) => void;
14
+ onDownloadFile?: (file: DropzoneFile) => void;
19
15
  /** (Optional) function, executed when a file gets dragged into the upload field and accepted */
20
16
  onDropAccepted?: () => void;
21
17
  /** (Optional) function, executed when a file gets dragged into the upload field and rejected */
@@ -32,9 +28,27 @@ export declare type Props = {
32
28
  previewComponent?: React.ComponentType<PreviewComponentProps>;
33
29
  /** (Optional) Maximum upload size */
34
30
  maxSize?: number;
35
- };
31
+ } & ({
32
+ /** (Optional) accept multiple files */
33
+ multiple?: false;
34
+ /** Function, executed when files get added or removed */
35
+ onChange?: (files: DropzoneFile[]) => void;
36
+ /** Function, executed when a file gets removed */
37
+ onRemoveFile: (file: DropzoneFile) => void;
38
+ /** Function, executed when a file gets selected */
39
+ onSelectFile: (file: DropzoneFile) => void;
40
+ } | {
41
+ /** (Optional) accept multiple files */
42
+ multiple: true;
43
+ /** Function, executed when files get added or removed */
44
+ onChange: (files: DropzoneFile[]) => void;
45
+ /** Function, executed when a file gets removed */
46
+ onRemoveFile?: (file: DropzoneFile) => void;
47
+ /** Function, executed when a file gets selected */
48
+ onSelectFile?: (file: DropzoneFile) => void;
49
+ });
36
50
  export declare type State = {
37
- file: DropzoneFile | null | undefined;
51
+ files: DropzoneFile[];
38
52
  };
39
53
  /**
40
54
  * FileUpload enables the possibility to upload files conveniently
@@ -60,8 +74,8 @@ export default class FileUpload extends React.Component<Props, State> {
60
74
  };
61
75
  state: State;
62
76
  handleDrop: (accepted: Array<DropzoneFile>, rejected: Array<DropzoneFile>) => void;
63
- selectFile: (arg0: DropzoneFile) => void;
64
- handleRemoveFile: () => void;
77
+ selectFile: (files: DropzoneFile[]) => void;
78
+ handleRemoveFile: (file: DropzoneFile) => void;
65
79
  render(): React.JSX.Element;
66
80
  }
67
81
  //# sourceMappingURL=FileUpload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FileUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/upload/FileUpload.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,oBAAY,YAAY,GAAG,IAAI,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,oBAAY,qBAAqB,GAAG;IACnC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,oBAAY,KAAK,GAAG;IACnB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kDAAkD;IAClD,YAAY,EAAE,MAAM,IAAI,CAAC;IAEzB,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B,mDAAmD;IACnD,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAE3C,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B,gGAAgG;IAChG,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAEjD,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IAEjC,qDAAqD;IACrD,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAElC,wDAAwD;IACxD,UAAU,CAAC,EAAE,qBAAqB,CAAC;IAEnC,wDAAwD;IACxD,UAAU,CAAC,EAAE,qBAAqB,CAAC;IAEnC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAE9D,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,oBAAY,KAAK,GAAG;IACnB,IAAI,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC;CACtC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;IACpE,MAAM,CAAC,YAAY,EAAE;QACpB,UAAU,EAAE;YACX,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;QACF,QAAQ,EAAE;YACT,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;QACF,SAAS,EAAE;YACV,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;QACF,UAAU,EAAE;YACX,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;KACF,CAiBC;IAEF,KAAK,EAAE,KAAK,CAEV;IAEF,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,IAAI,CAgBhF;IAEF,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAMtC;IAEF,gBAAgB,EAAE,MAAM,IAAI,CAW1B;IAEF,MAAM;CAqEN"}
1
+ {"version":3,"file":"FileUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/upload/FileUpload.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,oBAAY,YAAY,GAAG,IAAI,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,oBAAY,qBAAqB,GAAG;IACnC,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,oBAAY,KAAK,GAAG;IACnB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uDAAuD;IACvD,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAE9C,gGAAgG;IAChG,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B,gGAAgG;IAChG,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAEjD,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IAEjC,qDAAqD;IACrD,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAElC,wDAAwD;IACxD,UAAU,CAAC,EAAE,qBAAqB,CAAC;IAEnC,wDAAwD;IACxD,UAAU,CAAC,EAAE,qBAAqB,CAAC;IAEnC,gEAAgE;IAChE,gBAAgB,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAE9D,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,CACD;IACA,uCAAuC;IACvC,QAAQ,CAAC,EAAE,KAAK,CAAC;IAEjB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAE3C,kDAAkD;IAClD,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAE3C,mDAAmD;IACnD,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAC1C,GACD;IACA,uCAAuC;IACvC,QAAQ,EAAE,IAAI,CAAC;IAEf,yDAAyD;IACzD,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAE1C,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAE5C,mDAAmD;IACnD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CAC3C,CACH,CAAC;AAEF,oBAAY,KAAK,GAAG;IACnB,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;IACpE,MAAM,CAAC,YAAY,EAAE;QACpB,UAAU,EAAE;YACX,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;QACF,QAAQ,EAAE;YACT,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;QACF,SAAS,EAAE;YACV,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;QACF,UAAU,EAAE;YACX,YAAY,EAAE,MAAM,CAAC;YACrB,EAAE,EAAE,MAAM,CAAC;SACX,CAAC;KACF,CAiBC;IAEF,KAAK,EAAE,KAAK,CAEV;IAEF,UAAU,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,IAAI,CAchF;IAEF,UAAU,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,IAAI,CAazC;IAEF,gBAAgB,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAU5C;IAEF,MAAM;CA8EN"}
@@ -38,58 +38,66 @@ class FileUpload extends React.Component {
38
38
  constructor() {
39
39
  super(...arguments);
40
40
  this.state = {
41
- file: null
41
+ files: []
42
42
  };
43
43
  this.handleDrop = (accepted, rejected) => {
44
- if (accepted.length > 1) {
44
+ if (!this.props.multiple && accepted.length > 1) {
45
45
  return;
46
46
  }
47
47
  if (rejected.length > 0) {
48
48
  return;
49
49
  }
50
- const file = accepted[0];
51
50
  /** Prevent console error on <Dropzone /> component */
52
- setTimeout(() => this.selectFile(file), 100);
51
+ setTimeout(() => this.selectFile(accepted), 100);
53
52
  };
54
- this.selectFile = (file) => {
55
- file.preview = URL.createObjectURL(file);
56
- this.setState({
57
- file
53
+ this.selectFile = (files) => {
54
+ const { onSelectFile, onChange } = this.props;
55
+ files.forEach((file) => {
56
+ file.preview = URL.createObjectURL(file);
58
57
  });
59
- this.props.onSelectFile(file);
58
+ const newFiles = [...this.state.files, ...files];
59
+ this.setState({ files: newFiles });
60
+ onChange?.(newFiles);
61
+ if (onSelectFile) {
62
+ files.forEach((file) => {
63
+ onSelectFile(file);
64
+ });
65
+ }
60
66
  };
61
- this.handleRemoveFile = () => {
62
- const { file } = this.state;
63
- const { onRemoveFile } = this.props;
67
+ this.handleRemoveFile = (file) => {
68
+ const { files } = this.state;
64
69
  if (file) {
65
70
  if (file.preview)
66
71
  window.URL.revokeObjectURL(file.preview);
67
- onRemoveFile();
68
- this.setState({
69
- file: null
70
- });
72
+ const newFiles = files.filter((f) => f !== file);
73
+ this.setState({ files: newFiles });
74
+ this.props.onChange?.(newFiles);
75
+ this.props.onRemoveFile?.(file);
71
76
  }
72
77
  };
73
78
  }
74
79
  render() {
75
- const { file } = this.state;
80
+ const { files } = this.state;
76
81
  const { accept, previewComponent: Preview, dropHint, hoverHint, acceptHint, rejectHint,
77
82
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
83
+ onChange,
84
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
78
85
  onRemoveFile, onDownloadFile,
79
86
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
80
- onSelectFile, onDropRejected, onDropAccepted, maxSize, ...otherProps } = this.props;
87
+ onSelectFile, onDropRejected, onDropAccepted, maxSize, multiple, ...otherProps } = this.props;
81
88
  const dropHintOrDefault = dropHint || FileUpload.defaultProps.dropHint;
82
89
  const hoverHintOrDefault = hoverHint || FileUpload.defaultProps.hoverHint;
83
90
  const acceptHintOrDefault = acceptHint || FileUpload.defaultProps.acceptHint;
84
91
  const rejectHintOrDefault = rejectHint || FileUpload.defaultProps.rejectHint;
85
92
  return (React.createElement("div", { ...otherProps, className: (0, classnames_1.default)('di upload', {
86
- clickable: !file,
87
- hasContent: !!file
93
+ clickable: !files.length,
94
+ hasContent: !!files.length
88
95
  }) },
89
- !!file && !!Preview && (
90
- // @ts-ignore
91
- React.createElement(Preview, { file: file, onRemoveFile: this.handleRemoveFile, onDownloadFile: onDownloadFile })),
92
- !file && (React.createElement(react_dropzone_1.default, { accept: accept, multiple: false, style: {
96
+ !!Preview &&
97
+ files.map((file, i) => (React.createElement(Preview, { key: i, file: file, onRemoveFile: () => this.handleRemoveFile(file),
98
+ // @ts-ignore
99
+ onDownloadFile: onDownloadFile && (() => onDownloadFile(file)) }))),
100
+ (multiple || !files.length) && (React.createElement(react_dropzone_1.default, { accept: accept, multiple: multiple ?? false, style: {
93
101
  border: 'none'
94
102
  }, onDrop: this.handleDrop, onDropRejected: onDropRejected, onDropAccepted: onDropAccepted, activeClassName: "active", acceptClassName: "accept", rejectClassName: "reject", maxSize: maxSize || Infinity },
95
103
  React.createElement("div", { className: "drag-drop-text-container" },
@@ -1,12 +1,13 @@
1
1
  import * as React from 'react';
2
- import { Props as FileUploadProps } from './FileUpload';
3
- export declare type Props = FileUploadProps & {
2
+ import { DropzoneFile, Props as FileUploadProps } from './FileUpload';
3
+ export declare type Props = Omit<FileUploadProps, 'multiple'> & {
4
4
  /** (Optional) Url for the image preview */
5
5
  imageUrl: string | null | undefined;
6
6
  imageSize?: 'contain' | 'cover';
7
7
  };
8
8
  declare type ImageUploadState = {
9
9
  dragOverPreview: boolean;
10
+ file: DropzoneFile | null;
10
11
  };
11
12
  /**
12
13
  * ImageUpload enables the possibility to upload images conveniently
@@ -1 +1 @@
1
- {"version":3,"file":"ImageUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/upload/ImageUpload.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAmB,EAAC,KAAK,IAAI,eAAe,EAAC,MAAM,cAAc,CAAC;AA+BlE,oBAAY,KAAK,GAAG,eAAe,GAAG;IACrC,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CAChC,CAAC;AAEF,aAAK,gBAAgB,GAAG;IACvB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC;IAChF,KAAK,EAAE,gBAAgB,CAErB;IAEF,kBAAkB,CAAC,SAAS,EAAE,KAAK,GAAG,IAAI;IAQ1C,cAAc,EAAE,MAAM,IAAI,CAIxB;IAEF,MAAM;CAkBN"}
1
+ {"version":3,"file":"ImageUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/upload/ImageUpload.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAmB,EAAC,YAAY,EAAE,KAAK,IAAI,eAAe,EAAC,MAAM,cAAc,CAAC;AA+BhF,oBAAY,KAAK,GAAG,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG;IACvD,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CAChC,CAAC;AAEF,aAAK,gBAAgB,GAAG;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,gBAAgB,CAAC;IAChF,KAAK,EAAE,gBAAgB,CAGrB;IAEF,kBAAkB,CAAC,SAAS,EAAE,KAAK,GAAG,IAAI;IAQ1C,cAAc,EAAE,MAAM,IAAI,CAIxB;IAEF,MAAM;CA+BN"}
@@ -45,7 +45,8 @@ class ImageUpload extends React.Component {
45
45
  constructor() {
46
46
  super(...arguments);
47
47
  this.state = {
48
- dragOverPreview: false
48
+ dragOverPreview: false,
49
+ file: null
49
50
  };
50
51
  this.handleDragOver = () => {
51
52
  this.setState({
@@ -61,13 +62,19 @@ class ImageUpload extends React.Component {
61
62
  }
62
63
  }
63
64
  render() {
64
- const { accept, imageUrl, imageSize, ...otherProps } = this.props;
65
- const { dragOverPreview } = this.state;
66
- if (imageUrl && !dragOverPreview) {
67
- return (React.createElement(PreviewImage, { url: imageUrl, imageSize: imageSize, onRemoveFile: otherProps.onRemoveFile, onDownloadFile: otherProps.onDownloadFile, onDragOver: this.handleDragOver }));
65
+ const { accept, imageUrl, imageSize, onSelectFile, onRemoveFile, ...otherProps } = this.props;
66
+ const { dragOverPreview, file } = this.state;
67
+ if (imageUrl && !dragOverPreview && file) {
68
+ return (React.createElement(PreviewImage, { url: imageUrl, imageSize: imageSize, onRemoveFile: () => onRemoveFile?.(file), onDownloadFile: () => otherProps.onDownloadFile?.(file), onDragOver: this.handleDragOver }));
68
69
  }
69
70
  else {
70
- return React.createElement(FileUpload_1.default, { ...otherProps, accept: accept || 'image/jpeg, image/png' });
71
+ return (React.createElement(FileUpload_1.default, { ...otherProps, onRemoveFile: (file) => {
72
+ this.setState({ file: null });
73
+ onRemoveFile?.(file);
74
+ }, onSelectFile: (file) => {
75
+ this.setState({ file });
76
+ onSelectFile?.(file);
77
+ }, accept: accept || 'image/jpeg, image/png' }));
71
78
  }
72
79
  }
73
80
  }
@@ -74,7 +74,7 @@
74
74
  .di.upload,
75
75
  .di.upload * {transition:all .1s ease;}
76
76
  .di.upload {margin:0; padding:0; width:100%; height:100%; min-height:80px; font-size:16px; border:1px dashed #888; border-radius:4px; overflow:hidden; user-select:none;}
77
- .di.upload {display:flex; align-items:center;}
77
+ .di.upload {display:flex; flex-direction:column; align-items:center;}
78
78
  .di.upload:hover {border-color:#666; background:#f9f9f9;}
79
79
  .di.upload:active {background:#eee;}
80
80
  .di.upload > div {width:100%; height:100%;}
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimeInput.d.ts","sourceRoot":"","sources":["../../../../src/components/input/DateTimeInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAejD,oBAAY,KAAK,GAAG;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,oEAAoE;IACpE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAE7E,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACrC,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,QAAQ,EACR,GAAG,UAAU,EACb,EAAE,KAAK,qBAwDP"}
1
+ {"version":3,"file":"DateTimeInput.d.ts","sourceRoot":"","sources":["../../../../src/components/input/DateTimeInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAwBjD,oBAAY,KAAK,GAAG;IACnB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAElB,oEAAoE;IACpE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,aAAa,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAE7E,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACrC,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAgB,EAChB,QAAQ,EACR,GAAG,UAAU,EACb,EAAE,KAAK,qBAgFP"}
@@ -1,7 +1,9 @@
1
+ import dayjs from 'dayjs';
1
2
  import React, { useEffect, useState } from 'react';
2
3
  import { dayjsTz } from '../periodpicker/periods';
3
4
  import DateInput from './DateInput';
4
5
  import ValidatedTextInput from './ValidatedTextInput';
6
+ import { toInteger } from 'lodash';
5
7
  const extractTime = (timezone, date) => {
6
8
  try {
7
9
  return dayjsTz(timezone, date).format('HH:mm');
@@ -11,6 +13,15 @@ const extractTime = (timezone, date) => {
11
13
  return '00:00';
12
14
  }
13
15
  };
16
+ const extractDate = (timezone, date) => {
17
+ try {
18
+ return dayjs(dayjsTz(timezone, date).format('YYYY-MM-DD'));
19
+ }
20
+ catch (error) {
21
+ console.error('DateTimeInput: Error while extracting time from date', error);
22
+ return dayjs(new Date());
23
+ }
24
+ };
14
25
  /**
15
26
  * Extends DateInput but also displaying the current time.
16
27
  * Usually the user's locale is used for displaying the correct date format.
@@ -23,17 +34,36 @@ export default function DateTimeInput({ timestamp, timezone, warning, readOnly =
23
34
  }, [timezone, timestamp]);
24
35
  function handleChangeDate(date, fromTextField) {
25
36
  const oldDate = dayjsTz(timezone, timestamp);
26
- onChange(dayjsTz(timezone, date).set('hour', oldDate.get('hour')).set('minute', oldDate.get('minute')).valueOf(), fromTextField);
37
+ const dateFix = dayjs(date);
38
+ let newDate = dayjsTz(timezone, date)
39
+ .set('day', dateFix.day())
40
+ .set('month', dateFix.month())
41
+ .set('year', dateFix.year())
42
+ .set('hour', toInteger(oldDate.hour()))
43
+ .set('minute', toInteger(oldDate.minute()));
44
+ const dstOffset = getLocalDstOffset(newDate);
45
+ newDate = newDate.subtract(dstOffset, 'minutes');
46
+ onChange(newDate.valueOf(), fromTextField);
47
+ }
48
+ function getMaxUtcOffset(year) {
49
+ const jan = new Date(`${year}-01-01`).getTimezoneOffset();
50
+ const jul = new Date(`${year}-07-01`).getTimezoneOffset();
51
+ return Math.min(jan, jul);
52
+ }
53
+ function getLocalDstOffset(newDate) {
54
+ return newDate.toDate().getTimezoneOffset() - getMaxUtcOffset(newDate.year());
27
55
  }
28
56
  function handleChangeTime(time, valid) {
29
57
  if (valid) {
30
58
  const [hours, minutes] = time.split(':');
31
- onChange(dayjsTz(timezone, timestamp)
59
+ const date = extractDate(timezone, timestamp);
60
+ const dateTime = dayjsTz(timezone, timestamp)
61
+ .set('date', date.date())
32
62
  .set('hour', parseInt(hours, 10))
33
63
  .set('minute', parseInt(minutes, 10))
34
64
  .set('second', 0)
35
- .set('millisecond', 0)
36
- .valueOf());
65
+ .set('millisecond', 0);
66
+ onChange(dateTime.valueOf());
37
67
  }
38
68
  setTime(time);
39
69
  }
@@ -43,7 +73,7 @@ export default function DateTimeInput({ timestamp, timezone, warning, readOnly =
43
73
  }
44
74
  }
45
75
  return (React.createElement("span", { className: `di date-time-input ${warning ? 'with-warning' : ''}` },
46
- React.createElement(DateInput, { ...otherProps, value: timestamp, onChange: handleChangeDate, readOnly: readOnly }),
76
+ React.createElement(DateInput, { ...otherProps, value: extractDate(timezone, timestamp).valueOf(), onChange: handleChangeDate, readOnly: readOnly }),
47
77
  React.createElement(ValidatedTextInput, { "data-testid": "time-input", value: timeValue, onChange: handleChangeTime, pattern: /^(([01][0-9])|2[0-3]):[0-5][0-9]$/, required: true, invalidStyle: {
48
78
  borderColor: 'red'
49
79
  }, placeholder: "00:00", className: "time", onBlur: tryFixTime, disabled: readOnly })));
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
2
  import { describe, expect, it } from 'vitest';
3
3
  import DateTimeInput from '../DateTimeInput';
4
- import { render, screen } from '@testing-library/react';
4
+ import { act, render, screen } from '@testing-library/react';
5
+ import { userEvent } from '@storybook/testing-library';
5
6
  describe('DateTimeInput.js', () => {
6
7
  it('should update time when timestamp has changed', () => {
7
8
  const { rerender } = render(React.createElement(DateTimeInput, { timestamp: new Date('2019-02-01T11:11:00').getTime(), onChange: () => { } }));
@@ -10,4 +11,24 @@ describe('DateTimeInput.js', () => {
10
11
  rerender(React.createElement(DateTimeInput, { timestamp: new Date('2019-02-02T03:24:00').getTime(), onChange: () => { } }));
11
12
  expect(timeElement).toHaveDisplayValue('03:24');
12
13
  });
14
+ it('should display the time and date as timezone date', async () => {
15
+ const { rerender } = render(React.createElement(DateTimeInput, { timestamp: new Date('2019-02-01T11:11:00Z').getTime(), onChange: () => { }, timezone: "America/Vancouver" }));
16
+ const timeElementUtm = screen.queryByDisplayValue('11:11');
17
+ expect(timeElementUtm).not.toBeInTheDocument();
18
+ const timeElement = screen.queryByDisplayValue('03:11');
19
+ expect(timeElement).toBeInTheDocument();
20
+ const dateElement = screen.queryByDisplayValue('01.02.2019');
21
+ expect(dateElement).toBeInTheDocument();
22
+ rerender(React.createElement(DateTimeInput, { timestamp: new Date('2019-02-02T03:24:00Z').getTime(), onChange: () => { }, timezone: "America/Vancouver" }));
23
+ expect(timeElement).toHaveDisplayValue('19:24');
24
+ expect(dateElement).toHaveDisplayValue('01.02.2019');
25
+ await act(async () => {
26
+ dateElement?.click();
27
+ timeElement?.click();
28
+ userEvent.clear(timeElement);
29
+ userEvent.type(timeElement, '10:24');
30
+ });
31
+ expect(timeElement).toHaveDisplayValue('10:24');
32
+ expect(dateElement).toHaveDisplayValue('01.02.2019');
33
+ });
13
34
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ReactableTable.d.ts","sourceRoot":"","sources":["../../../../../src/components/reactable/helpers/ReactableTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAQzD,OAAO,EAAC,kBAAkB,EAAE,eAAe,EAAE,uBAAuB,EAAC,MAAM,UAAU,CAAC;AACtF,OAAO,EAAC,QAAQ,EAAE,kBAAkB,EAAE,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAGtF,aAAK,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI;IAC9D,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,aAAa,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,EACxF,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EAAE,MAAM,EACrB,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAwHd"}
1
+ {"version":3,"file":"ReactableTable.d.ts","sourceRoot":"","sources":["../../../../../src/components/reactable/helpers/ReactableTable.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAQzD,OAAO,EAAC,kBAAkB,EAAE,eAAe,EAAE,uBAAuB,EAAC,MAAM,UAAU,CAAC;AACtF,OAAO,EAAC,QAAQ,EAAE,kBAAkB,EAAE,aAAa,EAAC,MAAM,2BAA2B,CAAC;AAGtF,aAAK,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI;IAC9D,UAAU,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACpC,aAAa,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7D,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,CAAC,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,EACxF,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,EAAE,MAAM,EACrB,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAmId"}
@@ -10,7 +10,8 @@ export default function ReactableTable({ columnDefs, uniqueItemKey, paginationSe
10
10
  const containerRef = useRef(null);
11
11
  const tableRef = useRef(null);
12
12
  const [showScrollingAdvice, setShowScrollingAdvice] = useState(false);
13
- const [neverShowScrollingAdvice, setNeverShowScrollingAdvice] = useState(false);
13
+ const [neverShowScrollingAdvice, setNeverShowScrollingAdvice] = useState(true);
14
+ const [hasInitialized, setHasInitialized] = useState(false);
14
15
  const HIDE_SCROLLING_ADVICE_PATH = 'uiConfigurations/nevershowscrollingadvice';
15
16
  const neverShowScrollingAdviceRef = useRef(neverShowScrollingAdvice);
16
17
  useEffect(() => {
@@ -22,14 +23,25 @@ export default function ReactableTable({ columnDefs, uniqueItemKey, paginationSe
22
23
  }
23
24
  };
24
25
  useEffect(() => {
25
- readAccountObject(HIDE_SCROLLING_ADVICE_PATH).then((value) => {
26
- const neverShow = value === undefined ? false : value;
27
- setNeverShowScrollingAdvice(neverShow);
28
- neverShowScrollingAdviceRef.current = neverShow;
29
- if (containerRef.current && tableRef.current) {
30
- updateScrollingAdvice();
31
- }
32
- });
26
+ setTimeout(() => {
27
+ (async () => {
28
+ try {
29
+ const value = await readAccountObject(HIDE_SCROLLING_ADVICE_PATH);
30
+ const neverShow = value === true;
31
+ setNeverShowScrollingAdvice(neverShow);
32
+ neverShowScrollingAdviceRef.current = neverShow;
33
+ if (!neverShow) {
34
+ updateScrollingAdvice();
35
+ }
36
+ }
37
+ catch (error) {
38
+ setNeverShowScrollingAdvice(false);
39
+ neverShowScrollingAdviceRef.current = false;
40
+ updateScrollingAdvice();
41
+ }
42
+ setHasInitialized(true);
43
+ })();
44
+ }, 0);
33
45
  }, []);
34
46
  useEffect(() => {
35
47
  updateScrollingAdvice();
@@ -39,7 +51,7 @@ export default function ReactableTable({ columnDefs, uniqueItemKey, paginationSe
39
51
  const showFilterRow = columnDefs.some((col) => col.filterable);
40
52
  return (React.createElement(SpinnerContainer, { show: isLoading },
41
53
  React.createElement("div", { ref: containerRef, className: "di reactable scroll-x" },
42
- showScrollingAdvice && !isLoading && (React.createElement(Modal, { className: "scroll-horizontally-advice", content: React.createElement("div", null,
54
+ hasInitialized && showScrollingAdvice && !isLoading && (React.createElement(Modal, { className: "scroll-horizontally-advice", content: React.createElement("div", null,
43
55
  React.createElement(Trans, { i18nKey: "reactable.scrollHorizontally.advice" }, "SHIFT + mouse wheel to scroll horizontally"),
44
56
  React.createElement("div", { className: "scroll-horizontally-advice-buttons" },
45
57
  React.createElement(Button, { primary: true, onClick: async () => {