@gpa-gemstone/react-forms 1.1.84 → 1.1.86

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.
package/lib/DatePicker.js CHANGED
@@ -44,6 +44,11 @@ var gpa_symbols_1 = require("@gpa-gemstone/gpa-symbols");
44
44
  * Component that allows a user to pick a date or datetime.
45
45
  */
46
46
  function DateTimePicker(props) {
47
+ var inputRef = React.useRef(null);
48
+ var width = (0, helper_functions_1.useGetContainerPosition)(inputRef).width;
49
+ var _a = React.useState(false), isTextOverflowing = _a[0], setIsTextOverflowing = _a[1];
50
+ var _b = React.useState(false), isInputHovered = _b[0], setIsInputHovered = _b[1];
51
+ var overflowGUID = React.useState((0, helper_functions_1.CreateGuid)())[0];
47
52
  // Formats for displaying dates in the input box and storing in the record.
48
53
  var boxFormat = getBoxFormat(props.Type, props.Accuracy);
49
54
  var recordFormat = props.Format !== undefined ? props.Format : "YYYY-MM-DD" + (props.Type === undefined || props.Type === 'date' ? "" : "[T]HH:mm:ss.SSS[Z]");
@@ -51,15 +56,15 @@ function DateTimePicker(props) {
51
56
  var parse = function (r) { return moment(props.Record[props.Field], recordFormat); };
52
57
  // State and ref declarations.
53
58
  var divRef = React.useRef(null);
54
- var guid = React.useState((0, helper_functions_1.CreateGuid)())[0];
55
- var _a = React.useState(false), showHelp = _a[0], setShowHelp = _a[1];
59
+ var helpGuid = React.useState((0, helper_functions_1.CreateGuid)())[0];
60
+ var _c = React.useState(false), showHelp = _c[0], setShowHelp = _c[1];
56
61
  // Adds a buffer between the outside props and what the box is reading to prevent box overwriting every render with a keystroke
57
- var _b = React.useState(parse(props.Record).format(boxFormat)), boxRecord = _b[0], setBoxRecord = _b[1];
58
- var _c = React.useState(parse(props.Record)), pickerRecord = _c[0], setPickerRecord = _c[1];
59
- var _d = React.useState(""), feedbackMessage = _d[0], setFeedbackMessage = _d[1];
60
- var _e = React.useState(false), showOverlay = _e[0], setShowOverlay = _e[1];
61
- var _f = React.useState(0), top = _f[0], setTop = _f[1];
62
- var _g = React.useState(0), left = _g[0], setLeft = _g[1];
62
+ var _d = React.useState(parse(props.Record).format(boxFormat)), boxRecord = _d[0], setBoxRecord = _d[1];
63
+ var _e = React.useState(parse(props.Record)), pickerRecord = _e[0], setPickerRecord = _e[1];
64
+ var _f = React.useState(""), feedbackMessage = _f[0], setFeedbackMessage = _f[1];
65
+ var _g = React.useState(false), showOverlay = _g[0], setShowOverlay = _g[1];
66
+ var _h = React.useState(0), top = _h[0], setTop = _h[1];
67
+ var _j = React.useState(0), left = _j[0], setLeft = _j[1];
63
68
  var allowNull = React.useMemo(function () { var _a; return (_a = props.AllowEmpty) !== null && _a !== void 0 ? _a : false; }, [props.AllowEmpty]);
64
69
  React.useEffect(function () {
65
70
  if (props.Record[props.Field] !== null) {
@@ -128,35 +133,6 @@ function DateTimePicker(props) {
128
133
  }
129
134
  }
130
135
  }
131
- function getBoxFormat(type, accuracy) {
132
- var dateTime = type !== null && type !== void 0 ? type : 'date';
133
- var timeUnit = accuracy !== null && accuracy !== void 0 ? accuracy : 'second';
134
- if (dateTime === 'time') {
135
- if (timeUnit === 'minute') {
136
- return "HH:mm";
137
- }
138
- else if (timeUnit === 'second') {
139
- return "HH:mm:ss";
140
- }
141
- else {
142
- return "HH:mm:ss.SSS";
143
- }
144
- }
145
- else if (dateTime === 'datetime-local') {
146
- if (timeUnit === 'minute') {
147
- return "YYYY-MM-DD[T]HH:mm";
148
- }
149
- else if (timeUnit === 'second') {
150
- return "YYYY-MM-DD[T]HH:mm:ss";
151
- }
152
- else {
153
- return "YYYY-MM-DD[T]HH:mm:ss.SSS";
154
- }
155
- }
156
- else {
157
- return "YYYY-MM-DD";
158
- }
159
- }
160
136
  function getFeedbackMessage() {
161
137
  if (feedbackMessage.length != 0) {
162
138
  return feedbackMessage;
@@ -214,23 +190,80 @@ function DateTimePicker(props) {
214
190
  }
215
191
  setBoxRecord(value);
216
192
  }
193
+ React.useEffect(function () {
194
+ if (inputRef.current == null)
195
+ return;
196
+ var inputWidth = getInputWidth(inputRef.current, boxRecord, step);
197
+ setIsTextOverflowing(inputWidth > width);
198
+ }, [width, boxRecord, step]);
217
199
  return (React.createElement("div", { className: "form-group", ref: divRef },
218
200
  showHelpIcon || showLabel ?
219
201
  React.createElement("label", { className: "d-flex align-items-center" },
220
202
  React.createElement("span", null, showLabel ? label : ''),
221
- showHelpIcon && (React.createElement("span", { className: "ml-2 d-flex align-items-center", onMouseEnter: function () { return setShowHelp(true); }, onMouseLeave: function () { return setShowHelp(false); }, "data-tooltip": guid },
203
+ showHelpIcon && (React.createElement("span", { className: "ml-2 d-flex align-items-center", onMouseEnter: function () { return setShowHelp(true); }, onMouseLeave: function () { return setShowHelp(false); }, "data-tooltip": helpGuid },
222
204
  React.createElement(gpa_symbols_1.ReactIcons.QuestionMark, { Color: "var(--info)", Size: 20 }))))
223
205
  : null,
224
206
  showHelpIcon ?
225
- React.createElement(ToolTip_1.default, { Show: showHelp, Target: guid, Class: "info", Position: "bottom" }, props.Help)
207
+ React.createElement(ToolTip_1.default, { Show: showHelp, Target: helpGuid, Class: "info", Position: "bottom" }, props.Help)
226
208
  : null,
227
209
  React.createElement("input", { className: "gpa-gemstone-datetime form-control ".concat(IsValid() ? '' : 'is-invalid'), type: props.Type === undefined ? 'date' : props.Type, onChange: function (evt) {
228
210
  valueChange(evt.target.value);
229
- }, onFocus: function () { setShowOverlay(true); }, value: boxRecord, disabled: props.Disabled === undefined ? false : props.Disabled, onClick: function (e) { e.preventDefault(); }, step: step }),
211
+ }, onFocus: function () { setShowOverlay(true); }, value: boxRecord, disabled: props.Disabled === undefined ? false : props.Disabled, onClick: function (e) { e.preventDefault(); }, step: step, ref: inputRef, "data-tooltip": overflowGUID, onMouseOver: function () { return setIsInputHovered(true); }, onMouseOut: function () { return setIsInputHovered(false); } }),
230
212
  React.createElement("div", { className: "invalid-feedback" }, getFeedbackMessage()),
213
+ React.createElement(ToolTip_1.default, { Show: isTextOverflowing && isInputHovered, Target: overflowGUID }, props.Format != null ? moment(boxRecord).format(props.Format) : boxRecord),
231
214
  React.createElement(DateTimePopup_1.default, { Setter: function (d) {
232
215
  setPickerAndRecord(d);
233
216
  if (props.Type === 'date')
234
217
  setShowOverlay(false);
235
218
  }, Show: showOverlay, DateTime: pickerRecord, Valid: props.Valid(props.Field), Top: top, Center: left, Type: props.Type === undefined ? 'date' : props.Type, Accuracy: props.Accuracy })));
236
219
  }
220
+ function getBoxFormat(type, accuracy) {
221
+ var dateTime = type !== null && type !== void 0 ? type : 'date';
222
+ var timeUnit = accuracy !== null && accuracy !== void 0 ? accuracy : 'second';
223
+ if (dateTime === 'time') {
224
+ if (timeUnit === 'minute') {
225
+ return "HH:mm";
226
+ }
227
+ else if (timeUnit === 'second') {
228
+ return "HH:mm:ss";
229
+ }
230
+ else {
231
+ return "HH:mm:ss.SSS";
232
+ }
233
+ }
234
+ else if (dateTime === 'datetime-local') {
235
+ if (timeUnit === 'minute') {
236
+ return "YYYY-MM-DD[T]HH:mm";
237
+ }
238
+ else if (timeUnit === 'second') {
239
+ return "YYYY-MM-DD[T]HH:mm:ss";
240
+ }
241
+ else {
242
+ return "YYYY-MM-DD[T]HH:mm:ss.SSS";
243
+ }
244
+ }
245
+ else {
246
+ return "YYYY-MM-DD";
247
+ }
248
+ }
249
+ var getInputWidth = function (inputRef, currentValue, currentStep) {
250
+ var computedStyle = window.getComputedStyle(inputRef);
251
+ var dummyInput = document.createElement('input');
252
+ dummyInput.type = inputRef.type;
253
+ dummyInput.value = currentValue;
254
+ dummyInput.step = currentStep;
255
+ dummyInput.style.font = computedStyle.font;
256
+ dummyInput.style.fontSize = computedStyle.fontSize;
257
+ dummyInput.style.fontFamily = computedStyle.fontFamily;
258
+ dummyInput.style.fontWeight = computedStyle.fontWeight;
259
+ dummyInput.style.letterSpacing = computedStyle.letterSpacing;
260
+ dummyInput.style.whiteSpace = 'nowrap';
261
+ // Position it off-screen and hide it so it doesn't affect layout
262
+ dummyInput.style.position = 'absolute';
263
+ dummyInput.style.visibility = 'hidden';
264
+ document.body.appendChild(dummyInput);
265
+ var width = dummyInput.getBoundingClientRect().width;
266
+ // Clean up
267
+ document.body.removeChild(dummyInput);
268
+ return width;
269
+ };
package/lib/FileUpload.js CHANGED
@@ -71,14 +71,14 @@ var FileUpload = function (props) {
71
71
  React.createElement(gpa_symbols_1.ReactIcons.CircledX, { Color: 'red' })))),
72
72
  isFileUpload ?
73
73
  React.createElement(React.Fragment, null,
74
- React.createElement("div", { className: 'row align-items-center justify-content-center', style: { border: '2px dashed var(--secondary)' } },
74
+ React.createElement("div", { className: 'row align-items-center justify-content-center', style: { border: '2px dashed var(--secondary)', borderRadius: '0.5em' } },
75
75
  React.createElement("div", { className: 'col-auto' },
76
76
  "File Name: ", fileName !== null && fileName !== void 0 ? fileName : ''),
77
77
  React.createElement("div", { className: 'col-auto' },
78
78
  "File Size: ",
79
79
  formatFileSize(fileSize))))
80
80
  :
81
- React.createElement("div", { className: 'row', onDragOver: handleDragOver, onDrop: handleDrop, style: { border: '2px dashed var(--secondary)' } },
81
+ React.createElement("div", { className: 'row', onDragOver: handleDragOver, onDrop: handleDrop, style: { border: '2px dashed var(--secondary)', borderRadius: '0.5em' } },
82
82
  React.createElement("div", { className: 'col-12 pt-3 pb-3 d-flex justify-content-center align-items-center' },
83
83
  React.createElement(gpa_symbols_1.ReactIcons.Image, { Size: 100 }),
84
84
  React.createElement("span", null, "Drag and Drop")))));
@@ -12,11 +12,11 @@ interface IProps<T> extends Gemstone.TSX.Interfaces.IBaseFormProps<T> {
12
12
  */
13
13
  AllowCustom?: boolean;
14
14
  /**
15
- * Function to perform a search and return a promise with a list of IOption and an optional callback
15
+ * Function to perform a search and return a promiselike object with a list of IOption and an optional callback
16
16
  * @param search - Search string
17
- * @returns {[promise: Promise<IOption[]>, callback?: () => void]}
17
+ * @returns {[promise: PromiseLike<IOption[]>, callback?: () => void]}
18
18
  */
19
- Search: (search: string) => [Promise<IOption[]>, () => void];
19
+ Search: (search: string) => [PromiseLike<IOption[]>, () => void];
20
20
  /**
21
21
  * CSS styles to apply to the form group
22
22
  * @type {React.CSSProperties}
@@ -21,17 +21,6 @@
21
21
  // Generated original version of source code.
22
22
  //
23
23
  // ******************************************************************************************************
24
- var __assign = (this && this.__assign) || function () {
25
- __assign = Object.assign || function(t) {
26
- for (var s, i = 1, n = arguments.length; i < n; i++) {
27
- s = arguments[i];
28
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
29
- t[p] = s[p];
30
- }
31
- return t;
32
- };
33
- return __assign.apply(this, arguments);
34
- };
35
24
  Object.defineProperty(exports, "__esModule", { value: true });
36
25
  exports.default = SearchableSelect;
37
26
  var React = require("react");
@@ -58,54 +47,57 @@ function SearchableSelect(props) {
58
47
  return callback;
59
48
  }
60
49
  }, [props.GetLabel]);
50
+ // Call props.Search every 500ms to avoid hammering the server while typing
61
51
  React.useEffect(function () {
62
52
  setLoading(true);
63
- var _a = props.Search(search), handle = _a[0], callback = _a[1];
64
- handle.then(function (d) {
65
- setResults(d.map(function (o) { return ({ Value: o.Value, Element: o.Label }); }));
66
- setLoading(false);
67
- }).catch(function () { return setLoading(false); });
68
- return callback;
53
+ var searchHandle;
54
+ var searchCallback;
55
+ var timeoutHandle = setTimeout(function () {
56
+ var _a;
57
+ _a = props.Search(search), searchHandle = _a[0], searchCallback = _a[1];
58
+ searchHandle.then(function (d) {
59
+ setResults(d.map(function (o) { return ({ Value: o.Value, Element: o.Label }); }));
60
+ setLoading(false);
61
+ }, function () {
62
+ setLoading(false);
63
+ });
64
+ }, 500);
65
+ return function () {
66
+ if (searchCallback != null)
67
+ searchCallback();
68
+ if (timeoutHandle != null)
69
+ clearTimeout(timeoutHandle);
70
+ };
69
71
  }, [search]);
70
- var handleOnBlur = React.useCallback(function () {
71
- setSearch(label);
72
- }, [label]);
72
+ var update = React.useCallback(function (record, selectedOption) {
73
+ var _a, _b;
74
+ var stringVal = (_b = (_a = record[props.Field]) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : '';
75
+ var newLabel = stringVal;
76
+ if (!React.isValidElement(selectedOption.Element))
77
+ newLabel = selectedOption.Element;
78
+ setLabel(newLabel);
79
+ props.Setter(record);
80
+ setSearch(newLabel);
81
+ }, [props.Setter, props.Field, label]);
73
82
  var options = React.useMemo(function () {
74
83
  var _a, _b;
75
84
  var ops = [];
76
85
  ops.push({
77
86
  Value: props.Record[props.Field],
78
87
  Element: React.createElement("div", { className: 'input-group' },
79
- React.createElement("input", { type: "text", className: "form-control", value: search, onChange: function (d) { return setSearch(d.target.value); }, onBlur: handleOnBlur, disabled: (_a = props.Disabled) !== null && _a !== void 0 ? _a : false }),
88
+ React.createElement("input", { type: "text", className: "form-control", value: search, onChange: function (d) { return setSearch(d.target.value); }, onBlur: function () { return setSearch(label); }, onClick: function (evt) { evt.preventDefault(); evt.stopPropagation(); }, disabled: (_a = props.Disabled) !== null && _a !== void 0 ? _a : false }),
80
89
  loading ?
81
90
  React.createElement("div", { className: "input-group-append" },
82
91
  React.createElement("span", { className: "input-group-text" },
83
92
  React.createElement(gpa_symbols_1.ReactIcons.SpiningIcon, null)))
84
93
  : null)
85
94
  });
86
- if (!((_b = props.AllowCustom) !== null && _b !== void 0 ? _b : false))
87
- ops.push({ Value: 'search-' + props.Record[props.Field], Element: label });
88
- else
89
- ops.push({ Value: search, Element: search });
95
+ if ((_b = props.AllowCustom) !== null && _b !== void 0 ? _b : false)
96
+ -ops.push({ Value: search, Element: React.createElement(React.Fragment, null,
97
+ search,
98
+ " (Entered Value)") });
90
99
  ops.push.apply(ops, results.filter(function (f) { return f.Value !== search && f.Value !== props.Record[props.Field]; }));
91
100
  return ops;
92
- }, [search, props.Record[props.Field], results, props.Disabled, loading, label, props.AllowCustom, handleOnBlur]);
93
- var update = React.useCallback(function (record, selectedOption) {
94
- var _a;
95
- var _b, _c;
96
- var stringVal = (_c = (_b = record[props.Field]) === null || _b === void 0 ? void 0 : _b.toString()) !== null && _c !== void 0 ? _c : '';
97
- var newLabel = stringVal;
98
- if (!React.isValidElement(selectedOption.Element))
99
- newLabel = selectedOption.Element;
100
- setLabel(newLabel);
101
- if (stringVal.startsWith('search-')) {
102
- var value = stringVal.replace('search-', '');
103
- props.Setter(__assign(__assign({}, record), (_a = {}, _a[props.Field] = value, _a)));
104
- setSearch(newLabel !== null && newLabel !== void 0 ? newLabel : value);
105
- return;
106
- }
107
- props.Setter(record);
108
- setSearch(newLabel);
109
- }, [props.Setter, props.Field, label]);
101
+ }, [search, props.Record[props.Field], results, props.Disabled, loading, label]);
110
102
  return React.createElement(StylableSelect_1.default, { Record: props.Record, Field: props.Field, Setter: update, Label: props.Label, Disabled: props.Disabled, Help: props.Help, Style: props.Style, Options: options, BtnStyle: props.BtnStyle });
111
103
  }
@@ -121,7 +121,7 @@ function StylableSelect(props) {
121
121
  var showLabel = props.Label !== "";
122
122
  var showHelpIcon = props.Help !== undefined;
123
123
  var label = props.Label === undefined ? props.Field : props.Label;
124
- return (React.createElement("div", { ref: stylableSelect, style: { position: 'relative', display: 'inline-block', width: 'inherit' } },
124
+ return (React.createElement("div", { ref: stylableSelect, className: "form-group", style: { position: 'relative', display: 'inline-block', width: 'inherit' } },
125
125
  showHelpIcon || showLabel ?
126
126
  React.createElement("label", { className: "d-flex align-items-center" },
127
127
  React.createElement("span", null, showLabel ? label : ''),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gpa-gemstone/react-forms",
3
- "version": "1.1.84",
3
+ "version": "1.1.86",
4
4
  "description": "React Form modules for gpa webapps",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -47,7 +47,7 @@
47
47
  "dependencies": {
48
48
  "@gpa-gemstone/application-typings": "0.0.83",
49
49
  "@gpa-gemstone/gpa-symbols": "0.0.49",
50
- "@gpa-gemstone/helper-functions": "0.0.38",
50
+ "@gpa-gemstone/helper-functions": "0.0.39",
51
51
  "@types/react": "^17.0.14",
52
52
  "@types/styled-components": "^5.1.11",
53
53
  "lodash": "^4.17.21",