@jobber/components 4.72.0 → 4.73.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.
@@ -13,11 +13,11 @@ var useOnKeyDown = require('@jobber/hooks/useOnKeyDown');
13
13
  var Text = require('../Text-259af966.js');
14
14
  var Icon = require('../Icon-405a216c.js');
15
15
  var Heading = require('../Heading-1e8e4bd3.js');
16
- var InputText = require('../InputText-e2d4ac19.js');
16
+ var InputText = require('../InputText-9e61365c.js');
17
17
  require('../Typography-c45bf216.js');
18
18
  require('@jobber/design');
19
19
  require('../getAtlantisConfig-0f3e8af2.js');
20
- require('../FormField-a332b2a6.js');
20
+ require('../FormField-b0e74d32.js');
21
21
  require('uuid');
22
22
  require('react-hook-form');
23
23
  require('@jobber/hooks/useShowClear');
@@ -29,7 +29,7 @@ var Combobox = require('../Combobox-95b3c413.js');
29
29
  var Chip = require('../Chip-c91fd6c8.js');
30
30
  var Icon = require('../Icon-405a216c.js');
31
31
  var debounce = require('lodash/debounce');
32
- var InputText = require('../InputText-e2d4ac19.js');
32
+ var InputText = require('../InputText-9e61365c.js');
33
33
  var Spinner = require('../Spinner-9d8fc7ff.js');
34
34
  var Typography = require('../Typography-c45bf216.js');
35
35
  require('../Content-2ca1ffe1.js');
@@ -40,7 +40,7 @@ require('react-hook-form');
40
40
  require('@jobber/hooks/useAssert');
41
41
  require('../Avatar-76a799fa.js');
42
42
  require('color');
43
- require('../FormField-a332b2a6.js');
43
+ require('../FormField-b0e74d32.js');
44
44
  require('@jobber/hooks/useShowClear');
45
45
  require('../InputValidation-a7a737f9.js');
46
46
 
@@ -9,11 +9,11 @@ var jobberHooks = require('@jobber/hooks/useResizeObserver');
9
9
  var styleInject_es = require('../style-inject.es-9d2f5f4e.js');
10
10
  var Glimmer = require('../Glimmer-cfa92a88.js');
11
11
  var tslib_es6 = require('../tslib.es6-5b8768b7.js');
12
- var Option = require('../Option-e5274cd8.js');
12
+ var Option = require('../Option-b715f6b4.js');
13
13
  var Button = require('../Button-b73a5e01.js');
14
14
  var Text = require('../Text-259af966.js');
15
15
  require('../Content-2ca1ffe1.js');
16
- require('../FormField-a332b2a6.js');
16
+ require('../FormField-b0e74d32.js');
17
17
  require('uuid');
18
18
  require('react-hook-form');
19
19
  require('@jobber/hooks/useShowClear');
@@ -147,6 +147,7 @@ export interface FormFieldProps extends CommonFormFieldProps {
147
147
  * Blur callback.
148
148
  */
149
149
  onBlur?(): void;
150
+ onKeyUp?(event: React.KeyboardEvent<HTMLInputElement>): void;
150
151
  /**
151
152
  * Exclusively for textareas. Specifies the visible height of a textarea.
152
153
  */
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var FormField = require('../FormField-a332b2a6.js');
5
+ var FormField = require('../FormField-b0e74d32.js');
6
6
  require('../tslib.es6-5b8768b7.js');
7
7
  require('react');
8
8
  require('uuid');
@@ -146,7 +146,7 @@ function FormFieldPostFix({ variation }) {
146
146
  /*eslint max-statements: ["error", 13]*/
147
147
  function FormField(props) {
148
148
  var _a, _b;
149
- const { actionsRef, autocomplete = true, children, defaultValue, description, disabled, inputRef, inline, keyboard, max, maxLength, min, name, readonly, rows, loading, type = "text", validations, value, onChange, onEnter, onFocus, onBlur, onValidation, clearable = "never", } = props;
149
+ const { actionsRef, autocomplete = true, children, defaultValue, description, disabled, inputRef, inline, keyboard, max, maxLength, min, name, readonly, rows, loading, type = "text", validations, value, onChange, onEnter, onFocus, onBlur, onValidation, onKeyUp, clearable = "never", } = props;
150
150
  const { control, formState: { errors }, setValue, watch, } = reactHookForm.useFormContext() != undefined
151
151
  ? reactHookForm.useFormContext()
152
152
  : // If there isn't a Form Context being provided, get a form for this field.
@@ -188,7 +188,7 @@ function FormField(props) {
188
188
  return (React__default["default"].createElement("textarea", Object.assign({}, textFieldProps, { rows: rows, ref: inputRef })));
189
189
  default:
190
190
  return (React__default["default"].createElement(React__default["default"].Fragment, null,
191
- React__default["default"].createElement("input", Object.assign({}, textFieldProps, { autoComplete: setAutocomplete(autocomplete), type: type, maxLength: maxLength, max: max, min: min, ref: inputRef })),
191
+ React__default["default"].createElement("input", Object.assign({}, textFieldProps, { autoComplete: setAutocomplete(autocomplete), type: type, maxLength: maxLength, max: max, min: min, ref: inputRef, onKeyUp: onKeyUp })),
192
192
  loading && React__default["default"].createElement(FormFieldPostFix, { variation: "spinner" }),
193
193
  children));
194
194
  }
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var omit = require('lodash/omit');
6
6
  var React = require('react');
7
- var FormField = require('../FormField-a332b2a6.js');
7
+ var FormField = require('../FormField-b0e74d32.js');
8
8
  var DatePicker = require('../DatePicker-64c5ab1a.js');
9
9
  require('../tslib.es6-5b8768b7.js');
10
10
  require('uuid');
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
- var FormField = require('../FormField-a332b2a6.js');
6
+ var FormField = require('../FormField-b0e74d32.js');
7
7
  require('../tslib.es6-5b8768b7.js');
8
8
  require('uuid');
9
9
  require('react-hook-form');
@@ -2,9 +2,9 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var InputNumber = require('../InputNumber-3f5d3f8d.js');
5
+ var InputNumber = require('../InputNumber-79da1cdc.js');
6
6
  require('react');
7
- require('../FormField-a332b2a6.js');
7
+ require('../FormField-b0e74d32.js');
8
8
  require('../tslib.es6-5b8768b7.js');
9
9
  require('uuid');
10
10
  require('react-hook-form');
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var FormField = require('./FormField-a332b2a6.js');
4
+ var FormField = require('./FormField-b0e74d32.js');
5
5
 
6
6
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
7
7
 
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
- var FormField = require('../FormField-a332b2a6.js');
6
+ var FormField = require('../FormField-b0e74d32.js');
7
7
  require('../tslib.es6-5b8768b7.js');
8
8
  require('uuid');
9
9
  require('react-hook-form');
@@ -6,7 +6,7 @@ var tslib_es6 = require('../tslib.es6-5b8768b7.js');
6
6
  var React = require('react');
7
7
  var reactHookForm = require('react-hook-form');
8
8
  var styleInject_es = require('../style-inject.es-9d2f5f4e.js');
9
- var FormField = require('../FormField-a332b2a6.js');
9
+ var FormField = require('../FormField-b0e74d32.js');
10
10
  require('uuid');
11
11
  require('classnames');
12
12
  require('@jobber/hooks/useShowClear');
@@ -2,9 +2,9 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var InputText = require('../InputText-e2d4ac19.js');
5
+ var InputText = require('../InputText-9e61365c.js');
6
6
  require('react');
7
- require('../FormField-a332b2a6.js');
7
+ require('../FormField-b0e74d32.js');
8
8
  require('../tslib.es6-5b8768b7.js');
9
9
  require('uuid');
10
10
  require('react-hook-form');
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var FormField = require('./FormField-a332b2a6.js');
4
+ var FormField = require('./FormField-b0e74d32.js');
5
5
 
6
6
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
7
7
 
@@ -0,0 +1,8 @@
1
+ import { InputTimeProps } from "../InputTimeProps";
2
+ interface UseTimePredictProps extends Pick<InputTimeProps, "value"> {
3
+ readonly handleChange: (value: string) => void;
4
+ }
5
+ export declare function useTimePredict({ value, handleChange }: UseTimePredictProps): {
6
+ setTypedTime: import("react").Dispatch<import("react").SetStateAction<string>>;
7
+ };
8
+ export {};
@@ -6,7 +6,7 @@ var tslib_es6 = require('../tslib.es6-5b8768b7.js');
6
6
  var React = require('react');
7
7
  var debounce = require('lodash/debounce');
8
8
  var temporal = require('@std-proposal/temporal');
9
- var FormField = require('../FormField-a332b2a6.js');
9
+ var FormField = require('../FormField-b0e74d32.js');
10
10
  require('uuid');
11
11
  require('react-hook-form');
12
12
  require('../style-inject.es-9d2f5f4e.js');
@@ -786,18 +786,173 @@ function InputTimeSafari(_a) {
786
786
  }
787
787
  }
788
788
 
789
+ const DEBOUNCE_TIME = 300;
790
+ function useTimePredict({ value, handleChange }) {
791
+ const IS_12_HOUR_FORMAT = React.useRef(Intl.DateTimeFormat(navigator.language, {
792
+ hour: "numeric",
793
+ }).resolvedOptions().hour12);
794
+ const [typedTime, setTypedTime] = React.useState("");
795
+ const predictTime = React.useCallback(debounce__default["default"](() => {
796
+ if (value)
797
+ return;
798
+ handleChange(predictHours(typedTime, IS_12_HOUR_FORMAT.current));
799
+ }, DEBOUNCE_TIME), [typedTime, value, handleChange]);
800
+ /**
801
+ * Predict the hour when user types a number
802
+ */
803
+ React.useEffect(() => {
804
+ /**
805
+ * Don't try to predict if the user types 0 as the user would almost always
806
+ * type another number after 0.
807
+ */
808
+ if (typedTime && typedTime !== "0") {
809
+ predictTime();
810
+ if ((IS_12_HOUR_FORMAT && typedTime !== "1") || typedTime.length === 2) {
811
+ // Immediately predict the hour
812
+ predictTime.flush();
813
+ }
814
+ }
815
+ return predictTime.cancel;
816
+ }, [typedTime]);
817
+ /**
818
+ * Reset typed time when the value changed
819
+ */
820
+ React.useEffect(() => {
821
+ setTypedTime("");
822
+ }, [value]);
823
+ return {
824
+ setTypedTime,
825
+ };
826
+ }
827
+ function predictHours(time, is12HourFormat = false) {
828
+ const today = new Date();
829
+ const currentHour = today.getHours();
830
+ const parsedTime = parseInt(time, 10);
831
+ let predictedTime;
832
+ if (is12HourFormat) {
833
+ predictedTime = predict12Hours(parsedTime, currentHour);
834
+ }
835
+ else {
836
+ predictedTime = predict24Hours(time, parsedTime, currentHour);
837
+ }
838
+ return formatHour(predictedTime);
839
+ }
840
+ function predict12Hours(parsedTime, currentHour) {
841
+ /**
842
+ * We need to predict what the user wants when they type 1 since it could be
843
+ * 10, 11, 12, or 1.
844
+ *
845
+ * If the current hour is over 12PM, we can skip this and go to the next logic.
846
+ */
847
+ if (parsedTime === 1 && currentHour < 12) {
848
+ if (currentHour < 10) {
849
+ return 10;
850
+ }
851
+ else {
852
+ return currentHour + 1;
853
+ }
854
+ }
855
+ /**
856
+ * Typing 1-5 predicts that the user want that exact hour on the afternoon.
857
+ */
858
+ if (parsedTime <= 5) {
859
+ return parsedTime + 12;
860
+ }
861
+ /**
862
+ * Typing 13-15 predicts that the user want the 2nd number as the minute interval.
863
+ */
864
+ if (parsedTime > 12 && parsedTime <= 15) {
865
+ const timeArray = parsedTime.toString().split("").map(Number); // 13 -> [1, 3]
866
+ const convertToHoursAndMinutes = timeArray.map((time, i) => {
867
+ if (i === 0)
868
+ return time + 12; // 1 -> 13 as 1PM
869
+ if (i === 1)
870
+ return time * 10; // 3 -> 30 as 30 minutes
871
+ });
872
+ return Number(convertToHoursAndMinutes.join("")); // [13, 30] -> 1330
873
+ }
874
+ /**
875
+ * Anything after 5 will be predicted to be set as AM.
876
+ */
877
+ return parsedTime;
878
+ }
879
+ function predict24Hours(time, parsedTime, currentHour) {
880
+ /**
881
+ * Typing 1 could be predicted from 10 to 19.
882
+ * Typing 01 skips this logic and sets the time to 01:00.
883
+ */
884
+ if (parsedTime === 1 && time !== "01") {
885
+ if (currentHour < 10 || currentHour > 19) {
886
+ return 10;
887
+ }
888
+ else {
889
+ return currentHour + 1;
890
+ }
891
+ }
892
+ /**
893
+ * Typing 2 could be predicted from 20 to 24.
894
+ * Typing 02 skips this logic and sets the time to 02:00.
895
+ */
896
+ if (parsedTime === 2 && time !== "02") {
897
+ if (currentHour < 20) {
898
+ return 20;
899
+ }
900
+ else {
901
+ return currentHour + 1;
902
+ }
903
+ }
904
+ /**
905
+ * Typing 24 or 00 is set to midnight. This ensures the time doesn't get set
906
+ * to 24 as that would be invalid.
907
+ */
908
+ if (parsedTime === 24 || time === "00") {
909
+ return 0;
910
+ }
911
+ return parsedTime;
912
+ }
913
+ function formatHour(time) {
914
+ if (time > 99) {
915
+ const splitTime = time.toString().split("");
916
+ if (splitTime.length === 3)
917
+ splitTime.unshift("0"); // 130 -> 0130
918
+ splitTime.splice(2, 0, ":"); // 0130 -> 01:30
919
+ return splitTime.join("");
920
+ }
921
+ if (time < 10) {
922
+ return `0${time}:00`;
923
+ }
924
+ return `${time}:00`;
925
+ }
926
+
789
927
  function InputTime(_a) {
790
928
  var { defaultValue, value, onChange } = _a, params = tslib_es6.__rest(_a, ["defaultValue", "value", "onChange"]);
791
- const handleChange = (newValue) => {
792
- onChange && onChange(htmlTimeToCivilTime(newValue));
793
- };
929
+ const ref = React.useRef(null);
930
+ const { setTypedTime } = useTimePredict({ value, handleChange });
794
931
  if (supportsTime) {
795
932
  const fieldProps = Object.assign(Object.assign(Object.assign({ onChange: handleChange }, (defaultValue && { defaultValue: civilTimeToHTMLTime(defaultValue) })), (!defaultValue && { value: civilTimeToHTMLTime(value) })), params);
796
- return React__default["default"].createElement(FormField.FormField, Object.assign({ type: "time" }, fieldProps));
933
+ return (React__default["default"].createElement(FormField.FormField, Object.assign({ inputRef: ref, type: "time" }, fieldProps, { onBlur: handleBlur, onKeyUp: e => {
934
+ var _a;
935
+ (_a = fieldProps.onKeyUp) === null || _a === void 0 ? void 0 : _a.call(fieldProps, e);
936
+ !isNaN(parseInt(e.key, 10)) && setTypedTime(prev => prev + e.key);
937
+ } })));
797
938
  }
798
939
  else {
799
940
  return (React__default["default"].createElement(InputTimeSafari, Object.assign({ defaultValue: defaultValue, value: value, onChange: onChange }, params)));
800
941
  }
942
+ function handleChange(newValue) {
943
+ onChange === null || onChange === void 0 ? void 0 : onChange(htmlTimeToCivilTime(newValue));
944
+ }
945
+ function handleBlur() {
946
+ var _a;
947
+ (_a = params.onBlur) === null || _a === void 0 ? void 0 : _a.call(params);
948
+ // Time inputs doesn't clear the typed value when it's invalid. This should
949
+ // force it to reset the input value when the typed value is invalid.
950
+ if (ref.current) {
951
+ if (!ref.current.checkValidity()) {
952
+ ref.current.value = "";
953
+ }
954
+ }
955
+ }
801
956
  }
802
957
 
803
958
  exports.InputTime = InputTime;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var FormField = require('./FormField-a332b2a6.js');
4
+ var FormField = require('./FormField-b0e74d32.js');
5
5
 
6
6
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
7
7
 
@@ -9,11 +9,11 @@ var RadioGroup = require('../RadioGroup-ca7a5978.js');
9
9
  var Text = require('../Text-259af966.js');
10
10
  require('classnames');
11
11
  require('../Typography-c45bf216.js');
12
- var Option = require('../Option-e5274cd8.js');
13
- var InputNumber = require('../InputNumber-3f5d3f8d.js');
12
+ var Option = require('../Option-b715f6b4.js');
13
+ var InputNumber = require('../InputNumber-79da1cdc.js');
14
14
  var InputGroup = require('../InputGroup-8d4fd4eb.js');
15
15
  var Content = require('../Content-2ca1ffe1.js');
16
- require('../FormField-a332b2a6.js');
16
+ require('../FormField-b0e74d32.js');
17
17
  require('../tslib.es6-5b8768b7.js');
18
18
  require('react-hook-form');
19
19
  require('@jobber/hooks/useShowClear');
@@ -2,9 +2,9 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var Option = require('../Option-e5274cd8.js');
5
+ var Option = require('../Option-b715f6b4.js');
6
6
  require('react');
7
- require('../FormField-a332b2a6.js');
7
+ require('../FormField-b0e74d32.js');
8
8
  require('../tslib.es6-5b8768b7.js');
9
9
  require('uuid');
10
10
  require('react-hook-form');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "4.72.0",
3
+ "version": "4.73.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -83,5 +83,5 @@
83
83
  "> 1%",
84
84
  "IE 10"
85
85
  ],
86
- "gitHead": "58a975b16f769405c26ebad6b5b8d8e699edbd04"
86
+ "gitHead": "b061db3b30964bb70e042fc5c40444b2e42484fe"
87
87
  }