@trackunit/react-form-components 0.1.1 → 0.1.3

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 (45) hide show
  1. package/index.cjs.js +281 -57
  2. package/index.esm.js +282 -59
  3. package/package.json +1 -1
  4. package/src/components/EmailInput/EmailInput.d.ts +1 -1
  5. package/src/components/PhoneInput/PhoneInputValidationUtils.d.ts +4 -0
  6. package/src/translation.d.ts +2 -2
  7. package/src/utilities/ColorFieldValidationUtils.d.ts +5 -0
  8. package/src/utilities/EmailFieldValidationUtils.d.ts +5 -0
  9. package/src/utilities/NumberFieldValidationUtils.d.ts +6 -0
  10. package/src/utilities/UrlFieldValidationUtils.d.ts +5 -0
  11. package/src/utilities/typeUtils.d.ts +12 -0
  12. package/translation.cjs.js +12 -1
  13. package/translation.cjs10.js +12 -1
  14. package/translation.cjs11.js +12 -1
  15. package/translation.cjs12.js +12 -1
  16. package/translation.cjs13.js +12 -1
  17. package/translation.cjs14.js +12 -1
  18. package/translation.cjs15.js +12 -1
  19. package/translation.cjs16.js +12 -1
  20. package/translation.cjs17.js +12 -1
  21. package/translation.cjs2.js +12 -1
  22. package/translation.cjs3.js +12 -1
  23. package/translation.cjs4.js +12 -1
  24. package/translation.cjs5.js +12 -1
  25. package/translation.cjs6.js +12 -1
  26. package/translation.cjs7.js +12 -1
  27. package/translation.cjs8.js +12 -1
  28. package/translation.cjs9.js +12 -1
  29. package/translation.esm.js +12 -1
  30. package/translation.esm10.js +12 -1
  31. package/translation.esm11.js +12 -1
  32. package/translation.esm12.js +12 -1
  33. package/translation.esm13.js +12 -1
  34. package/translation.esm14.js +12 -1
  35. package/translation.esm15.js +12 -1
  36. package/translation.esm16.js +12 -1
  37. package/translation.esm17.js +12 -1
  38. package/translation.esm2.js +12 -1
  39. package/translation.esm3.js +12 -1
  40. package/translation.esm4.js +12 -1
  41. package/translation.esm5.js +12 -1
  42. package/translation.esm6.js +12 -1
  43. package/translation.esm7.js +12 -1
  44. package/translation.esm8.js +12 -1
  45. package/translation.esm9.js +12 -1
package/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { registerTranslations, useNamespaceTranslation, NamespaceTrans } from '@trackunit/i18n-library-translation';
2
+ import { useNamespaceTranslation, registerTranslations, NamespaceTrans } from '@trackunit/i18n-library-translation';
3
3
  import { IconButton, Icon, Tooltip, Heading, Text, MenuItem, Tag, Spinner, useIsFirstRender } from '@trackunit/react-components';
4
4
  import { useCopyToClipboard } from 'react-use';
5
5
  import { cvaMerge } from '@trackunit/css-class-variance-utilities';
@@ -20,10 +20,19 @@ import { z } from 'zod';
20
20
 
21
21
  var defaultTranslations = {
22
22
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
23
+ "colorField.error.INVALID_HEX_CODE": "Please enter a valid HEX code",
24
+ "colorField.error.REQUIRED": "This field is required",
23
25
  "dropzone.input.title": "Drag-and-drop file input",
24
26
  "dropzone.label.default": "<clickable>Browse</clickable> or drag files here...",
27
+ "emailField.error.INVALID_EMAIL": "Please enter a valid email address",
28
+ "emailField.error.REQUIRED": "The email address is required",
25
29
  "field.notEditable.tooltip": "This field is not editable",
26
30
  "field.required.asterisk.tooltip": "This field is required",
31
+ "numberField.error.GREATER_THAN": "Value must be greater than or equal to {{min}}",
32
+ "numberField.error.INVALID_NUMBER": "Please enter a valid number",
33
+ "numberField.error.LESS_THAN": "Value must be less than or equal to {{max}}",
34
+ "numberField.error.NOT_IN_BETWEEN": "Must be between {{min}} and {{max}}",
35
+ "numberField.error.REQUIRED": "This field is required",
27
36
  "phoneField.error.INVALID_COUNTRY": "The country code is not valid",
28
37
  "phoneField.error.INVALID_LENGTH": "The phone number is not valid",
29
38
  "phoneField.error.INVALID_NUMBER": "The phone number is not valid",
@@ -32,7 +41,9 @@ var defaultTranslations = {
32
41
  "phoneField.error.REQUIRED_COUNTRY": "The country code is required",
33
42
  "phoneField.error.TOO_LONG": "The phone number is too long",
34
43
  "phoneField.error.TOO_SHORT": "The phone number is too short",
35
- "phoneField.error.undefined": ""
44
+ "phoneField.error.undefined": "",
45
+ "urlField.error.INVALID_URL": "Please enter a valid URL",
46
+ "urlField.error.REQUIRED": "The URL is required"
36
47
  };
37
48
 
38
49
  /** The translation namespace for this library */
@@ -611,6 +622,39 @@ const CheckboxField = forwardRef(({ label, id, tip, helpText, helpAddon, isInval
611
622
  });
612
623
  CheckboxField.displayName = "CheckboxField";
613
624
 
625
+ /**
626
+ *
627
+ * @param inputValue - value to check if it is a string
628
+ * @returns {boolean} - true if value is a string
629
+ */
630
+ const isString = (inputValue) => {
631
+ return typeof inputValue === "string";
632
+ };
633
+ /**
634
+ *
635
+ * @param inputValue - value to check if it is a number
636
+ * @returns {boolean} - true if value is a number
637
+ */
638
+ const isNumber = (inputValue) => {
639
+ return typeof inputValue === "number";
640
+ };
641
+
642
+ /**
643
+ * Validates a url
644
+ */
645
+ const validateColorCode = (colorCode, required) => {
646
+ if (!colorCode && !required) {
647
+ return undefined;
648
+ }
649
+ if (!colorCode && required) {
650
+ return "REQUIRED";
651
+ }
652
+ if (colorCode && isString(colorCode) && isValidHEXColor(colorCode)) {
653
+ return undefined;
654
+ }
655
+ return "INVALID_HEX_CODE";
656
+ };
657
+
614
658
  /**
615
659
  * Validates if the given value is a valid hex color.
616
660
  *
@@ -626,25 +670,34 @@ const isValidHEXColor = (value) => {
626
670
  * ColorField validates that user enters a valid color address.
627
671
  *
628
672
  */
629
- const ColorField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value: propValue, onChange, isInvalid = false, ...rest }, ref) => {
673
+ const ColorField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value: propValue, onChange, isInvalid = false, onBlur, ...rest }, ref) => {
630
674
  const htmlForId = useMemo(() => (id ? id : "colorField-" + v4()), [id]);
631
675
  const innerRef = React__default.useRef(null);
632
676
  React__default.useImperativeHandle(ref, () => innerRef.current, []);
677
+ const [t] = useTranslation();
633
678
  // Internal state for color value
634
- const [value, setValue] = useState(propValue || defaultValue || "");
679
+ const [innerValue, setInnerValue] = useState(propValue || defaultValue || "");
680
+ const [renderAsInvalid, setRenderAsInvalid] = useState(!!errorMessage || (innerValue && typeof innerValue === "string" && !isValidHEXColor(innerValue)) || isInvalid);
681
+ const errorType = useMemo(() => validateColorCode(innerValue, rest.required), [rest.required, innerValue]);
682
+ const error = useMemo(() => (errorType ? t(`colorField.error.${errorType}`) : errorMessage), [errorType, errorMessage, t]);
683
+ const handleBlur = useCallback(event => {
684
+ const newValue = event.target.value;
685
+ setInnerValue(newValue);
686
+ setRenderAsInvalid(!!errorType);
687
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
688
+ }, [errorType, onBlur]);
635
689
  const handleChange = useCallback((event) => {
636
690
  const newValue = event.target.value;
637
- setValue(newValue);
691
+ setInnerValue(newValue);
638
692
  if (onChange) {
639
693
  onChange(event);
640
694
  }
641
695
  }, [onChange]);
642
- const renderAsInvalid = !!errorMessage || (value && typeof value === "string" && !isValidHEXColor(value)) || isInvalid;
643
- return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsxs("div", { className: cvaInput({
696
+ return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsxs("div", { className: cvaInput({
644
697
  disabled: false,
645
698
  invalid: false,
646
699
  className,
647
- }), "data-testid": dataTestId ? `${dataTestId}-container` : undefined, children: [jsx("input", { "aria-labelledby": htmlForId + "-label", className: "ml-2 h-[30px] w-[40px] self-center rounded-full bg-inherit", "data-testid": dataTestId, defaultValue: defaultValue, id: htmlForId, onChange: handleChange, ref: innerRef, type: "color", value: value }), jsx("input", { "aria-labelledby": htmlForId + "-label-text", className: cvaInputField({ disabled: false }), "data-testid": dataTestId ? `${dataTestId}-textField` : undefined, onChange: handleChange, type: "text", value: value }), jsx(IconButton, { className: "mr-1 self-center", icon: jsx(Icon, { name: "Pencil", type: "outline" }), onClick: () => {
700
+ }), "data-testid": dataTestId ? `${dataTestId}-container` : undefined, children: [jsx("input", { "aria-labelledby": htmlForId + "-label", className: "ml-2 h-[30px] w-[40px] self-center rounded-full bg-inherit", "data-testid": dataTestId, defaultValue: defaultValue, id: htmlForId, onBlur: handleBlur, onChange: handleChange, ref: innerRef, type: "color", value: innerValue }), jsx("input", { "aria-labelledby": htmlForId + "-label-text", className: cvaInputField({ disabled: false }), "data-testid": dataTestId ? `${dataTestId}-textField` : undefined, onBlur: handleBlur, onChange: handleChange, type: "text", value: innerValue }), jsx(IconButton, { className: "mr-1 self-center", icon: jsx(Icon, { name: "Pencil", type: "outline" }), onClick: () => {
648
701
  if (innerRef.current) {
649
702
  innerRef.current.click();
650
703
  }
@@ -805,6 +858,22 @@ const validateEmailAddress = (email) => {
805
858
  return EMAIL_REGEX.test(email);
806
859
  };
807
860
 
861
+ /**
862
+ * Validates a email id
863
+ */
864
+ const validateEmailId = (emailId, required) => {
865
+ if (!emailId && !required) {
866
+ return undefined;
867
+ }
868
+ if (!emailId && required) {
869
+ return "REQUIRED";
870
+ }
871
+ if (emailId && isString(emailId) && validateEmailAddress(emailId)) {
872
+ return undefined;
873
+ }
874
+ return "INVALID_EMAIL";
875
+ };
876
+
808
877
  /**
809
878
  * A Email Input component is used for input of the type Email.
810
879
  *
@@ -835,22 +904,82 @@ EmailInput.displayName = "EmailInput";
835
904
  * EmailField validates that user enters a valid email address.
836
905
  *
837
906
  */
838
- const EmailField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value, disabled, onChange, isInvalid = false, ...rest }, ref) => {
907
+ const EmailField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, value, disabled, onChange, onBlur, isInvalid = false, ...rest }, ref) => {
839
908
  const htmlForId = id ? id : "emailField-" + v4();
840
- // Type guard to check if value is a string
841
- function isString(inputValue) {
842
- return typeof inputValue === "string";
843
- }
844
- const renderAsInvalid = !!errorMessage || (value && isString(value) && !validateEmailAddress(value)) || isInvalid;
909
+ const [t] = useTranslation();
910
+ const [innerValue, setInnerValue] = useState(() => {
911
+ var _a;
912
+ return (_a = ((value === null || value === void 0 ? void 0 : value.toString()) || (defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()))) !== null && _a !== void 0 ? _a : "";
913
+ });
914
+ const [renderAsInvalid, setRenderAsInvalid] = useState(!!errorMessage || (value && isString(value) && !validateEmailAddress(value)) || isInvalid);
915
+ const errorType = useMemo(() => validateEmailId(innerValue !== null && innerValue !== void 0 ? innerValue : "", rest.required), [rest.required, innerValue]);
916
+ const error = useMemo(() => (errorType ? t(`emailField.error.${errorType}`) : errorMessage), [errorType, errorMessage, t]);
917
+ const handleBlur = useCallback(event => {
918
+ const newValue = event.target.value;
919
+ setInnerValue(newValue);
920
+ setRenderAsInvalid(!!errorType);
921
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
922
+ }, [errorType, onBlur]);
845
923
  const handleChange = useCallback((event) => {
924
+ setInnerValue(event.target.value);
846
925
  if (onChange) {
847
926
  onChange(event);
848
927
  }
849
928
  }, [onChange]);
850
- return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(EmailInput, { "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, disabled: disabled, id: htmlForId, isInvalid: renderAsInvalid, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
929
+ return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(EmailInput, { "aria-labelledby": htmlForId + "-label", defaultValue: defaultValue, disabled: disabled, id: htmlForId, isInvalid: renderAsInvalid, onBlur: handleBlur, onChange: handleChange, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
851
930
  });
852
931
  EmailField.displayName = "EmailField";
853
932
 
933
+ const isNumberValid = (number) => {
934
+ if (!isNaN(+number) === false) {
935
+ return false;
936
+ }
937
+ if (typeof number === "number") {
938
+ return true;
939
+ }
940
+ return /^(?=.)([+-]?([0-9]*)(\.([0-9]+))?)$/.test(number);
941
+ };
942
+ /**
943
+ * Validates a number
944
+ */
945
+ const validateNumber = (number, required = false, min, max) => {
946
+ const parsedNumber = Number(number);
947
+ const minValue = typeof min === "string" ? parseFloat(min) : min;
948
+ const maxValue = typeof max === "string" ? parseFloat(max) : max;
949
+ if (number === undefined) {
950
+ return undefined;
951
+ }
952
+ // if the value is a string eg:'test'
953
+ if (number && !isNaN(+number) === false) {
954
+ return "INVALID_NUMBER";
955
+ }
956
+ // if the value is empty and not required
957
+ if (!Number.isNaN(parsedNumber) && !parsedNumber && !required && !min && !max) {
958
+ return undefined;
959
+ }
960
+ // if the value is empty and required
961
+ if (!Number.isNaN(parsedNumber) && !parsedNumber && required) {
962
+ return "REQUIRED";
963
+ }
964
+ // if the value is not in between min and max
965
+ if (minValue && maxValue && isNumberValid(parsedNumber) && !(parsedNumber >= minValue && parsedNumber <= maxValue)) {
966
+ return "NOT_IN_BETWEEN";
967
+ }
968
+ // if the value is less than min
969
+ if (isNumberValid(parsedNumber) && minValue !== undefined && parsedNumber < minValue) {
970
+ return "GREATER_THAN";
971
+ }
972
+ // if the value is greater than max
973
+ if (isNumberValid(parsedNumber) && maxValue !== undefined && parsedNumber > maxValue) {
974
+ return "LESS_THAN";
975
+ }
976
+ // if the value is a number and is valid
977
+ if (isNumber(parsedNumber) && isNumberValid(parsedNumber)) {
978
+ return undefined;
979
+ }
980
+ return "INVALID_NUMBER";
981
+ };
982
+
854
983
  /**
855
984
  * A thin wrapper around the `BaseInput` component for number input fields.
856
985
  *
@@ -868,10 +997,39 @@ NumberInput.displayName = "NumberInput";
868
997
  *
869
998
  * _**Do not use**_ this fields for non-serialized numbers. Use TextField instead.
870
999
  */
871
- const NumberField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId, ...rest }, ref) => {
872
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1000
+ const NumberField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, isInvalid, maxLength, className, value, dataTestId, defaultValue, onBlur, ...rest }, ref) => {
873
1001
  const htmlForId = id ? id : "numberField-" + v4();
874
- return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(NumberInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
1002
+ const [t] = useTranslation();
1003
+ const [innerValue, setInnerValue] = useState(() => {
1004
+ return Number(value === null || value === void 0 ? void 0 : value.toString()) || Number(defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString());
1005
+ });
1006
+ const [renderAsInvalid, setRenderAsInvalid] = useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
1007
+ !!validateNumber(value === null || value === void 0 ? void 0 : value.toString(), rest.required, rest.min, rest.max));
1008
+ const errorType = useMemo(() => validateNumber(innerValue, rest.required, rest.min, rest.max), [innerValue, rest.max, rest.min, rest.required]);
1009
+ const error = useMemo(() => {
1010
+ // for the case when a custom error message is provided
1011
+ if (errorMessage) {
1012
+ setRenderAsInvalid(Boolean(errorMessage));
1013
+ return errorMessage;
1014
+ }
1015
+ else if (errorType) {
1016
+ return t(`numberField.error.${errorType}`, { min: rest.min, max: rest.max });
1017
+ }
1018
+ return errorMessage;
1019
+ }, [errorMessage, errorType, rest.max, rest.min, t]);
1020
+ const handleBlur = useCallback(event => {
1021
+ const newValue = event.target.value;
1022
+ setInnerValue(newValue.toString());
1023
+ // for the case when a custom error message is provided
1024
+ if (errorMessage && !validateNumber(newValue, rest.required, rest.min, rest.max)) {
1025
+ setRenderAsInvalid(Boolean(errorMessage));
1026
+ }
1027
+ else {
1028
+ setRenderAsInvalid(!!validateNumber(newValue, rest.required, rest.min, rest.max));
1029
+ }
1030
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
1031
+ }, [errorMessage, onBlur, rest.max, rest.min, rest.required]);
1032
+ return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(NumberInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, maxLength: maxLength, onBlur: handleBlur, ref: ref, value: value, ...rest, className: className, dataTestId: dataTestId }) }));
875
1033
  });
876
1034
  NumberField.displayName = "NumberField";
877
1035
 
@@ -1052,39 +1210,6 @@ const PhoneInput = forwardRef(({ dataTestId, isInvalid, disabled = false, value,
1052
1210
  });
1053
1211
  PhoneInput.displayName = "PhoneInput";
1054
1212
 
1055
- /**
1056
- * The PhoneField component is used to enter phone number.
1057
- * It is a wrapper around the PhoneInput component and the FormGroup component.
1058
- * It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
1059
- *
1060
- * @param {string} [label] - The label for the component.
1061
- * @param {string} [tip] - The tip for the component.
1062
- * @param {string} [helpText] - The help text for the component.
1063
- * @param {string} [helpAddon] - The help addon for the component.
1064
- * @param {string} [errorMessage] - The error message for the component.
1065
- * @param {string} [defaultValue] - The default value for the component.
1066
- * @param {boolean} [disabled=false] - Whether the component is disabled or not.
1067
- * @param {string} [fieldSize="medium"] - The size of the input field.
1068
- * @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
1069
- * @returns {JSX.Element} - The PhoneField component.
1070
- */
1071
- const PhoneField = forwardRef(({ label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, dataTestId, name, onChange, onBlur, ...rest }, ref) => {
1072
- const htmlForId = id ? id : "phoneField-" + v4();
1073
- const renderAsInvalid = isInvalid === undefined ? Boolean(errorMessage) : isInvalid;
1074
- return (jsx(FormGroup, { className: className, dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && errorMessage) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(PhoneInput, { "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: onBlur, onChange: onChange, ref: ref, value: value, ...rest }) }));
1075
- });
1076
- PhoneField.displayName = "PhoneField";
1077
-
1078
- /**
1079
- * The PhoneFieldWithController component is a wrapper for the PhoneField component to connect it to react-hook-form.
1080
- *
1081
- * @returns {JSX.Element} - The PhoneFieldWithController component.
1082
- */
1083
- const PhoneFieldWithController = forwardRef(({ control, controllerProps, name, value, ...rest }, ref) => {
1084
- return (jsx(Controller, { control: control, defaultValue: value, name: name, ...controllerProps, render: ({ field }) => jsx(PhoneField, { ...rest, ...field, ref: ref }) }));
1085
- });
1086
- PhoneFieldWithController.displayName = "PhoneFieldWithController";
1087
-
1088
1213
  /**
1089
1214
  * Validates a phone number
1090
1215
  */
@@ -1124,6 +1249,79 @@ const isInvalidCountryCode = (error, required) => (!!required && error === "REQU
1124
1249
  * Checks if the phone number is valid and required
1125
1250
  */
1126
1251
  const isInvalidPhoneNumber = (error, required) => error !== "REQUIRED_COUNTRY" && ((!!error && error !== "REQUIRED") || (!!required && error === "REQUIRED"));
1252
+ /**
1253
+ * Checks if the phone number is valid and returns corresponding error message
1254
+ */
1255
+ const phoneErrorMessage = (phoneNumber, required) => {
1256
+ if ((validatePhoneNumber(phoneNumber) === "REQUIRED" && !required) ||
1257
+ (validatePhoneNumber(phoneNumber) === "REQUIRED" && required && phoneNumber === undefined)) {
1258
+ return undefined;
1259
+ }
1260
+ return validatePhoneNumber(phoneNumber);
1261
+ };
1262
+
1263
+ /**
1264
+ * The PhoneField component is used to enter phone number.
1265
+ * It is a wrapper around the PhoneInput component and the FormGroup component.
1266
+ * It is used to render a phone number field with a label, a tip, a help text, a help addon and an error message.
1267
+ *
1268
+ * @param {string} [label] - The label for the component.
1269
+ * @param {string} [tip] - The tip for the component.
1270
+ * @param {string} [helpText] - The help text for the component.
1271
+ * @param {string} [helpAddon] - The help addon for the component.
1272
+ * @param {string} [errorMessage] - The error message for the component.
1273
+ * @param {string} [defaultValue] - The default value for the component.
1274
+ * @param {boolean} [disabled=false] - Whether the component is disabled or not.
1275
+ * @param {string} [fieldSize="medium"] - The size of the input field.
1276
+ * @param {boolean} [disableAction=false] - Whether the action button is disabled or not.
1277
+ * @returns {JSX.Element} - The PhoneField component.
1278
+ */
1279
+ const PhoneField = forwardRef(({ label, id, tip, helpText, isInvalid, errorMessage, value, helpAddon, className, defaultValue, dataTestId, name, onBlur, ...rest }, ref) => {
1280
+ const htmlForId = id ? id : "phoneField-" + v4();
1281
+ const [t] = useTranslation();
1282
+ const [innerValue, setInnerValue] = useState(() => {
1283
+ var _a;
1284
+ return (_a = ((value === null || value === void 0 ? void 0 : value.toString()) || (defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()))) !== null && _a !== void 0 ? _a : undefined;
1285
+ });
1286
+ const [renderAsInvalid, setRenderAsInvalid] = useState((isInvalid === undefined ? Boolean(errorMessage) : isInvalid) ||
1287
+ !!phoneErrorMessage(value === null || value === void 0 ? void 0 : value.toString(), rest.required));
1288
+ const errorType = useMemo(() => phoneErrorMessage(innerValue, rest.required), [innerValue, rest.required]);
1289
+ const error = useMemo(() => {
1290
+ // for the case when a custom error message is provided
1291
+ if (errorMessage) {
1292
+ setRenderAsInvalid(Boolean(errorMessage));
1293
+ return errorMessage;
1294
+ }
1295
+ else if (errorType) {
1296
+ return t(`phoneField.error.${errorType}`);
1297
+ }
1298
+ return errorMessage;
1299
+ }, [errorMessage, errorType, t]);
1300
+ const handleBlur = useCallback(event => {
1301
+ const newValue = event.target.value;
1302
+ setInnerValue(newValue);
1303
+ // for the case when a custom error message is provided
1304
+ if (errorMessage && !phoneErrorMessage(newValue.toString(), rest.required)) {
1305
+ setRenderAsInvalid(Boolean(errorMessage));
1306
+ }
1307
+ else {
1308
+ setRenderAsInvalid(!!phoneErrorMessage(newValue.toString(), rest.required));
1309
+ }
1310
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
1311
+ }, [errorMessage, onBlur, rest.required]);
1312
+ return (jsx(FormGroup, { className: className, dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: (renderAsInvalid && error) || helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(PhoneInput, { "aria-labelledby": htmlForId + "-label", dataTestId: dataTestId, defaultValue: defaultValue, id: htmlForId, isInvalid: renderAsInvalid, name: name, onBlur: handleBlur, ref: ref, value: value, ...rest }) }));
1313
+ });
1314
+ PhoneField.displayName = "PhoneField";
1315
+
1316
+ /**
1317
+ * The PhoneFieldWithController component is a wrapper for the PhoneField component to connect it to react-hook-form.
1318
+ *
1319
+ * @returns {JSX.Element} - The PhoneFieldWithController component.
1320
+ */
1321
+ const PhoneFieldWithController = forwardRef(({ control, controllerProps, name, value, ...rest }, ref) => {
1322
+ return (jsx(Controller, { control: control, defaultValue: value, name: name, ...controllerProps, render: ({ field }) => jsx(PhoneField, { ...rest, ...field, ref: ref }) }));
1323
+ });
1324
+ PhoneFieldWithController.displayName = "PhoneFieldWithController";
1127
1325
 
1128
1326
  const cvaRadioGroup = cvaMerge(["flex", "gap-2", "flex-col", "items-start"], {
1129
1327
  variants: {
@@ -2435,6 +2633,22 @@ const validateUrlAddress = (url) => {
2435
2633
  return urlPattern.test(url);
2436
2634
  };
2437
2635
 
2636
+ /**
2637
+ * Validates a url
2638
+ */
2639
+ const validateUrl = (url, required) => {
2640
+ if (!url && !required) {
2641
+ return undefined;
2642
+ }
2643
+ if (!url && required) {
2644
+ return "REQUIRED";
2645
+ }
2646
+ if (url && isString(url) && validateUrlAddress(url)) {
2647
+ return undefined;
2648
+ }
2649
+ return "INVALID_URL";
2650
+ };
2651
+
2438
2652
  /**
2439
2653
  * A thin wrapper around the `BaseInput` component for URL input fields.
2440
2654
  *
@@ -2452,14 +2666,23 @@ UrlInput.displayName = "UrlField";
2452
2666
  * UrlField validates that user enters a valid web address.
2453
2667
  *
2454
2668
  */
2455
- const UrlField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, isInvalid = false, value, ...rest }, ref) => {
2669
+ const UrlField = forwardRef(({ label, id, tip, helpText, errorMessage, helpAddon, className, defaultValue, dataTestId, isInvalid = false, value, onBlur, ...rest }, ref) => {
2456
2670
  const htmlForId = id ? id : "urlField-" + v4();
2457
- // Type guard to check if value is a string
2458
- function isString(inputValue) {
2459
- return typeof inputValue === "string";
2460
- }
2461
- const renderAsInvalid = !!errorMessage || (value && isString(value) && !validateUrlAddress(value)) || isInvalid;
2462
- return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: renderAsInvalid ? errorMessage : helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(UrlInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, ref: ref, value: value || defaultValue, ...rest, className: className, dataTestId: dataTestId }) }));
2671
+ const [t] = useTranslation();
2672
+ const [innerValue, setInnerValue] = useState(() => {
2673
+ var _a;
2674
+ return (_a = ((value === null || value === void 0 ? void 0 : value.toString()) || (defaultValue === null || defaultValue === void 0 ? void 0 : defaultValue.toString()))) !== null && _a !== void 0 ? _a : "";
2675
+ });
2676
+ const [renderAsInvalid, setRenderAsInvalid] = useState(!!errorMessage || (value && isString(value) && !validateUrlAddress(value)) || isInvalid);
2677
+ const errorType = useMemo(() => validateUrl(innerValue !== null && innerValue !== void 0 ? innerValue : "", rest.required), [rest.required, innerValue]);
2678
+ const error = useMemo(() => (errorType ? t(`urlField.error.${errorType}`) : errorMessage), [errorType, errorMessage, t]);
2679
+ const handleBlur = useCallback(event => {
2680
+ const newValue = event.target.value;
2681
+ setInnerValue(newValue);
2682
+ setRenderAsInvalid(!!validateUrl(newValue, rest.required));
2683
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
2684
+ }, [onBlur, rest.required]);
2685
+ return (jsx(FormGroup, { dataTestId: dataTestId ? `${dataTestId}-FormGroup` : undefined, helpAddon: helpAddon, helpText: renderAsInvalid ? error : helpText, htmlFor: htmlForId, isInvalid: renderAsInvalid, label: label, required: rest.required, tip: tip, children: jsx(UrlInput, { "aria-labelledby": htmlForId + "-label", id: htmlForId, isInvalid: renderAsInvalid, onBlur: handleBlur, ref: ref, value: value || defaultValue, ...rest, className: className, dataTestId: dataTestId }) }));
2463
2686
  });
2464
2687
  UrlField.displayName = "UrlField";
2465
2688
 
@@ -2571,4 +2794,4 @@ const useZodValidators = () => {
2571
2794
  */
2572
2795
  setupLibraryTranslations();
2573
2796
 
2574
- export { ActionButton, BaseInput, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DateField, DateInput, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, EmailInput, FormFieldSelectAdapter, FormGroup, Label, MultiSelectMenuItem, NumberField, NumberInput, OptionCard, PasswordField, PasswordInput, PhoneField, PhoneFieldWithController, PhoneInput, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, Select, SelectField, SingleSelectMenuItem, TextArea, TextAreaField, TextField, TextInput, TimeRange, TimeRangeField, Toggle, UploadField, UploadInput, UrlField, UrlInput, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaActionButton, cvaActionContainer, cvaInput, cvaInputAction, cvaInputAddon, cvaInputAddonAfter, cvaInputAddonBefore, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputField, cvaInputPrefix, cvaInputSuffix, cvaSelect, cvaSelectControl, cvaSelectCounter, cvaSelectDynamicTagContainer, cvaSelectIcon, cvaSelectMenu, cvaSelectMenuList, cvaSelectPrefixSuffix, cvaSelectXIcon, getCountryAbbreviation, getOrderedOptions, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isMultiValue, isValidHEXColor, parseSchedule, serializeSchedule, useCustomComponents, useGetPhoneValidationRules, usePhoneInput, useZodValidators, validateEmailAddress, validatePhoneNumber, weekDay };
2797
+ export { ActionButton, BaseInput, Checkbox, CheckboxField, ColorField, CreatableSelect, CreatableSelectField, DateField, DateInput, DropZone, DropZoneDefaultLabel, EMAIL_REGEX, EmailField, EmailInput, FormFieldSelectAdapter, FormGroup, Label, MultiSelectMenuItem, NumberField, NumberInput, OptionCard, PasswordField, PasswordInput, PhoneField, PhoneFieldWithController, PhoneInput, RadioGroup, RadioItem, Schedule, ScheduleVariant, Search, Select, SelectField, SingleSelectMenuItem, TextArea, TextAreaField, TextField, TextInput, TimeRange, TimeRangeField, Toggle, UploadField, UploadInput, UrlField, UrlInput, checkIfPhoneNumberHasPlus, countryCodeToFlagEmoji, cvaActionButton, cvaActionContainer, cvaInput, cvaInputAction, cvaInputAddon, cvaInputAddonAfter, cvaInputAddonBefore, cvaInputBase, cvaInputBaseDisabled, cvaInputBaseInvalid, cvaInputField, cvaInputPrefix, cvaInputSuffix, cvaSelect, cvaSelectControl, cvaSelectCounter, cvaSelectDynamicTagContainer, cvaSelectIcon, cvaSelectMenu, cvaSelectMenuList, cvaSelectPrefixSuffix, cvaSelectXIcon, getCountryAbbreviation, getOrderedOptions, getPhoneNumberWithPlus, isInvalidCountryCode, isInvalidPhoneNumber, isMultiValue, isValidHEXColor, parseSchedule, phoneErrorMessage, serializeSchedule, useCustomComponents, useGetPhoneValidationRules, usePhoneInput, useZodValidators, validateEmailAddress, validatePhoneNumber, weekDay };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/react-form-components",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "repository": "https://github.com/Trackunit/manager",
5
5
  "license": "SEE LICENSE IN LICENSE.txt",
6
6
  "engines": {
@@ -8,7 +8,7 @@ export interface EmailInputProps extends BaseInputExposedProps {
8
8
  * @default false
9
9
  * @memberof EmailInputProps
10
10
  * @example
11
- * <UrLInput disableAction />
11
+ * <EmailInput disableAction />
12
12
  */
13
13
  disableAction?: boolean;
14
14
  }
@@ -12,3 +12,7 @@ export declare const isInvalidCountryCode: (error: PhoneInputValidationError, re
12
12
  * Checks if the phone number is valid and required
13
13
  */
14
14
  export declare const isInvalidPhoneNumber: (error: PhoneInputValidationError, required?: boolean) => boolean;
15
+ /**
16
+ * Checks if the phone number is valid and returns corresponding error message
17
+ */
18
+ export declare const phoneErrorMessage: (phoneNumber: string | undefined, required?: boolean | undefined) => PhoneInputValidationError;
@@ -14,8 +14,8 @@ export declare const translations: TranslationResource<TranslationKeys>;
14
14
  /**
15
15
  * Local useTranslation for this specific library
16
16
  */
17
- export declare const useTranslation: () => [TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "dropzone.input.title" | "dropzone.label.default" | "field.notEditable.tooltip" | "field.required.asterisk.tooltip" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined">, import("i18next").i18n, boolean] & {
18
- t: TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "dropzone.input.title" | "dropzone.label.default" | "field.notEditable.tooltip" | "field.required.asterisk.tooltip" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined">;
17
+ export declare const useTranslation: () => [TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "colorField.error.INVALID_HEX_CODE" | "colorField.error.REQUIRED" | "dropzone.input.title" | "dropzone.label.default" | "emailField.error.INVALID_EMAIL" | "emailField.error.REQUIRED" | "field.notEditable.tooltip" | "field.required.asterisk.tooltip" | "numberField.error.GREATER_THAN" | "numberField.error.INVALID_NUMBER" | "numberField.error.LESS_THAN" | "numberField.error.NOT_IN_BETWEEN" | "numberField.error.REQUIRED" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined" | "urlField.error.INVALID_URL" | "urlField.error.REQUIRED">, import("i18next").i18n, boolean] & {
18
+ t: TransForLibs<"clearIndicator.icon.tooltip.clearAll" | "colorField.error.INVALID_HEX_CODE" | "colorField.error.REQUIRED" | "dropzone.input.title" | "dropzone.label.default" | "emailField.error.INVALID_EMAIL" | "emailField.error.REQUIRED" | "field.notEditable.tooltip" | "field.required.asterisk.tooltip" | "numberField.error.GREATER_THAN" | "numberField.error.INVALID_NUMBER" | "numberField.error.LESS_THAN" | "numberField.error.NOT_IN_BETWEEN" | "numberField.error.REQUIRED" | "phoneField.error.INVALID_COUNTRY" | "phoneField.error.INVALID_LENGTH" | "phoneField.error.INVALID_NUMBER" | "phoneField.error.NOT_A_NUMBER" | "phoneField.error.REQUIRED" | "phoneField.error.REQUIRED_COUNTRY" | "phoneField.error.TOO_LONG" | "phoneField.error.TOO_SHORT" | "phoneField.error.undefined" | "urlField.error.INVALID_URL" | "urlField.error.REQUIRED">;
19
19
  i18n: import("i18next").i18n;
20
20
  ready: boolean;
21
21
  };
@@ -0,0 +1,5 @@
1
+ export type UrlValidationErrorCode = "REQUIRED" | "INVALID_HEX_CODE" | undefined;
2
+ /**
3
+ * Validates a url
4
+ */
5
+ export declare const validateColorCode: (colorCode: string | number | readonly string[], required?: boolean | undefined) => UrlValidationErrorCode;
@@ -0,0 +1,5 @@
1
+ export type EmailValidationErrorCode = "REQUIRED" | "INVALID_EMAIL" | undefined;
2
+ /**
3
+ * Validates a email id
4
+ */
5
+ export declare const validateEmailId: (emailId: string | number | readonly string[], required?: boolean | undefined) => EmailValidationErrorCode;
@@ -0,0 +1,6 @@
1
+ type NumberValidationErrorCode = "REQUIRED" | "INVALID_NUMBER" | "NOT_IN_BETWEEN" | "GREATER_THAN" | "LESS_THAN" | undefined;
2
+ /**
3
+ * Validates a number
4
+ */
5
+ export declare const validateNumber: (number: string | number | undefined, required?: boolean, min?: number | string, max?: number | string) => NumberValidationErrorCode;
6
+ export {};
@@ -0,0 +1,5 @@
1
+ export type UrlValidationErrorCode = "REQUIRED" | "INVALID_URL" | undefined;
2
+ /**
3
+ * Validates a url
4
+ */
5
+ export declare const validateUrl: (url: string | number | readonly string[], required?: boolean | undefined) => UrlValidationErrorCode;
@@ -0,0 +1,12 @@
1
+ /**
2
+ *
3
+ * @param inputValue - value to check if it is a string
4
+ * @returns {boolean} - true if value is a string
5
+ */
6
+ export declare const isString: (inputValue: string | number | readonly string[] | undefined) => inputValue is string;
7
+ /**
8
+ *
9
+ * @param inputValue - value to check if it is a number
10
+ * @returns {boolean} - true if value is a number
11
+ */
12
+ export declare const isNumber: (inputValue: string | number | undefined) => inputValue is number;
@@ -2,10 +2,19 @@
2
2
 
3
3
  var translation = {
4
4
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
5
+ "colorField.error.INVALID_HEX_CODE": "Please enter a valid HEX code",
6
+ "colorField.error.REQUIRED": "This field is required",
5
7
  "dropzone.input.title": "Dateien per Drag & Drop hinzufügen",
6
8
  "dropzone.label.default": "<clickable>Ordner durchsuchen</clickable> oder Dateien per Drag & Drop einfügen …",
9
+ "emailField.error.INVALID_EMAIL": "Please enter a valid email address",
10
+ "emailField.error.REQUIRED": "The email address is required",
7
11
  "field.notEditable.tooltip": "Dieses Feld kann nicht bearbeitet werden",
8
12
  "field.required.asterisk.tooltip": "Dieses Feld ist ein Pflichtfeld",
13
+ "numberField.error.GREATER_THAN": "Value must be greater than or equal to {{min}}",
14
+ "numberField.error.INVALID_NUMBER": "Please enter a valid number",
15
+ "numberField.error.LESS_THAN": "Value must be less than or equal to {{max}}",
16
+ "numberField.error.NOT_IN_BETWEEN": "Must be between {{min}} and {{max}}",
17
+ "numberField.error.REQUIRED": "This field is required",
9
18
  "phoneField.error.INVALID_COUNTRY": "Die Ländervorwahl ist ungültig",
10
19
  "phoneField.error.INVALID_LENGTH": "Die Telefonnummer ist ungültig",
11
20
  "phoneField.error.INVALID_NUMBER": "Die Telefonnummer ist ungültig",
@@ -14,7 +23,9 @@ var translation = {
14
23
  "phoneField.error.REQUIRED_COUNTRY": "Die Ländervorwahl ist erforderlich",
15
24
  "phoneField.error.TOO_LONG": "Die Telefonnummer ist zu lang",
16
25
  "phoneField.error.TOO_SHORT": "Die Telefonnummer ist zu kurz",
17
- "phoneField.error.undefined": ""
26
+ "phoneField.error.undefined": "",
27
+ "urlField.error.INVALID_URL": "Please enter a valid URL",
28
+ "urlField.error.REQUIRED": "The URL is required"
18
29
  };
19
30
 
20
31
  exports.default = translation;
@@ -2,10 +2,19 @@
2
2
 
3
3
  var translation = {
4
4
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
5
+ "colorField.error.INVALID_HEX_CODE": "Please enter a valid HEX code",
6
+ "colorField.error.REQUIRED": "This field is required",
5
7
  "dropzone.input.title": "Przeciągnij i upuść dane pliku",
6
8
  "dropzone.label.default": "<clickable>Przeglądaj</clickable> lub przeciągnij pliki tutaj...",
9
+ "emailField.error.INVALID_EMAIL": "Please enter a valid email address",
10
+ "emailField.error.REQUIRED": "The email address is required",
7
11
  "field.notEditable.tooltip": "To pole nie jest edytowalne",
8
12
  "field.required.asterisk.tooltip": "To pole jest wymagane",
13
+ "numberField.error.GREATER_THAN": "Value must be greater than or equal to {{min}}",
14
+ "numberField.error.INVALID_NUMBER": "Please enter a valid number",
15
+ "numberField.error.LESS_THAN": "Value must be less than or equal to {{max}}",
16
+ "numberField.error.NOT_IN_BETWEEN": "Must be between {{min}} and {{max}}",
17
+ "numberField.error.REQUIRED": "This field is required",
9
18
  "phoneField.error.INVALID_COUNTRY": "Kod kraju jest nieprawidłowy",
10
19
  "phoneField.error.INVALID_LENGTH": "Numer telefonu jest nieprawidłowy",
11
20
  "phoneField.error.INVALID_NUMBER": "Numer telefonu jest nieprawidłowy",
@@ -14,7 +23,9 @@ var translation = {
14
23
  "phoneField.error.REQUIRED_COUNTRY": "Kod kraju jest wymagany",
15
24
  "phoneField.error.TOO_LONG": "Numer telefonu jest zbyt długi",
16
25
  "phoneField.error.TOO_SHORT": "Numer telefonu jest zbyt krótki",
17
- "phoneField.error.undefined": ""
26
+ "phoneField.error.undefined": "",
27
+ "urlField.error.INVALID_URL": "Please enter a valid URL",
28
+ "urlField.error.REQUIRED": "The URL is required"
18
29
  };
19
30
 
20
31
  exports.default = translation;
@@ -2,10 +2,19 @@
2
2
 
3
3
  var translation = {
4
4
  "clearIndicator.icon.tooltip.clearAll": "Clear all",
5
+ "colorField.error.INVALID_HEX_CODE": "Please enter a valid HEX code",
6
+ "colorField.error.REQUIRED": "This field is required",
5
7
  "dropzone.input.title": "Arrastar-e-soltar entrada de ficheiro",
6
8
  "dropzone.label.default": "<clickable>Procure</clickable> ou arraste os ficheiros aqui...",
9
+ "emailField.error.INVALID_EMAIL": "Please enter a valid email address",
10
+ "emailField.error.REQUIRED": "The email address is required",
7
11
  "field.notEditable.tooltip": "Este campo não é editável",
8
12
  "field.required.asterisk.tooltip": "Este campo é obrigatório",
13
+ "numberField.error.GREATER_THAN": "Value must be greater than or equal to {{min}}",
14
+ "numberField.error.INVALID_NUMBER": "Please enter a valid number",
15
+ "numberField.error.LESS_THAN": "Value must be less than or equal to {{max}}",
16
+ "numberField.error.NOT_IN_BETWEEN": "Must be between {{min}} and {{max}}",
17
+ "numberField.error.REQUIRED": "This field is required",
9
18
  "phoneField.error.INVALID_COUNTRY": "O código do país não é válido",
10
19
  "phoneField.error.INVALID_LENGTH": "O número de telefone não é válido",
11
20
  "phoneField.error.INVALID_NUMBER": "O número de telefone não é válido",
@@ -14,7 +23,9 @@ var translation = {
14
23
  "phoneField.error.REQUIRED_COUNTRY": "O código do país não é obrigatório",
15
24
  "phoneField.error.TOO_LONG": "O número de telefone é demasiado longo",
16
25
  "phoneField.error.TOO_SHORT": "O número de telefone é demasiado curto",
17
- "phoneField.error.undefined": ""
26
+ "phoneField.error.undefined": "",
27
+ "urlField.error.INVALID_URL": "Please enter a valid URL",
28
+ "urlField.error.REQUIRED": "The URL is required"
18
29
  };
19
30
 
20
31
  exports.default = translation;