@opengeoweb/form-fields 19.3.0 → 19.5.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.
package/dist/index.esm.js
CHANGED
|
@@ -21,8 +21,10 @@ var en = {
|
|
|
21
21
|
"form-fields-error-min-level": "The minimum level is 1",
|
|
22
22
|
"form-fields-error-latitude": "Invalid latitude, expected number with maximum two decimal degrees between -90.00 and 90.00",
|
|
23
23
|
"form-fields-error-longitude": "Invalid longitude, expected number with maximum two decimal degrees between -180.00 and 180.00",
|
|
24
|
-
"form-fields-error-latitude-minutes": "Latitude must be between -90° and 90
|
|
25
|
-
"form-fields-error-longitude-minutes": "Longitude must be between -180° and 180
|
|
24
|
+
"form-fields-error-latitude-minutes": "Latitude degrees must be between -90° and 90°, minutes between 00 and 59",
|
|
25
|
+
"form-fields-error-longitude-minutes": "Longitude degrees must be between -180° and 180°, minutes between 00 and 59",
|
|
26
|
+
"form-fields-error-invalid-minutes": "Minutes must be between 00 and 59",
|
|
27
|
+
"form-fields-error-invalid-coordinate-format": "Invalid format: latitude must be DDMM, longitude must be DDDMM",
|
|
26
28
|
"form-fields-error-valid-max": "The maximum value is exceeded",
|
|
27
29
|
"form-fields-error-level-lower": "The lower level has to be below the upper level",
|
|
28
30
|
"form-fields-error-non-or-both-cooordinates": "Please enter both coordinates",
|
|
@@ -39,6 +41,10 @@ var fi = {
|
|
|
39
41
|
"form-fields-error-min-level": "Pienin sallittu taso on 1",
|
|
40
42
|
"form-fields-error-latitude": "Virheellinen leveysaste, odotettu arvo on kahden desimaalin tarkkuudella -90.00 ja 90.00 asteen välissä",
|
|
41
43
|
"form-fields-error-longitude": "Virheellinen pituusaste, odotettu arvo on kahden desimaalin tarkkuudella -180 ja 180 asteen välissä",
|
|
44
|
+
"form-fields-error-latitude-minutes": "Leveysasteiden on oltava välillä -90° ja 90°, minuuttien välillä 00 ja 59",
|
|
45
|
+
"form-fields-error-longitude-minutes": "Pituusasteiden on oltava välillä -180° ja 180°, minuuttien välillä 00 ja 59",
|
|
46
|
+
"form-fields-error-invalid-minutes": "Minuuttien on oltava välillä 00 ja 59",
|
|
47
|
+
"form-fields-error-invalid-coordinate-format": "Virheellinen muoto: leveysaste DDMM, pituusaste DDDMM",
|
|
42
48
|
"form-fields-error-valid-max": "Maksimiarvo on ylitetty",
|
|
43
49
|
"form-fields-error-level-lower": "Alemman tason arvon on oltava ylemmän tason alla",
|
|
44
50
|
"form-fields-error-non-or-both-cooordinates": "Lisää molemmat kordinaatit",
|
|
@@ -55,8 +61,10 @@ var no = {
|
|
|
55
61
|
"form-fields-error-min-level": "The minimum level is 1",
|
|
56
62
|
"form-fields-error-latitude": "Invalid latitude, expected number with maximum two decimal degrees between -90.00 and 90.00",
|
|
57
63
|
"form-fields-error-longitude": "Invalid longitude, expected number with maximum two decimal degrees between -180.00 and 180.00",
|
|
58
|
-
"form-fields-error-latitude-minutes": "Latitude must be between -90° and 90
|
|
59
|
-
"form-fields-error-longitude-minutes": "Longitude must be between -180° and 180
|
|
64
|
+
"form-fields-error-latitude-minutes": "Latitude degrees must be between -90° and 90°, minutes between 00 and 59",
|
|
65
|
+
"form-fields-error-longitude-minutes": "Longitude degrees must be between -180° and 180°, minutes between 00 and 59",
|
|
66
|
+
"form-fields-error-invalid-minutes": "Minutes must be between 00 and 59",
|
|
67
|
+
"form-fields-error-invalid-coordinate-format": "Invalid format: latitude must be DDMM, longitude must be DDDMM",
|
|
60
68
|
"form-fields-error-valid-max": "The maximum value is exceeded",
|
|
61
69
|
"form-fields-error-level-lower": "The lower level has to be below the upper level",
|
|
62
70
|
"form-fields-error-non-or-both-cooordinates": "Please enter both coordinates",
|
|
@@ -73,6 +81,10 @@ var nl = {
|
|
|
73
81
|
"form-fields-error-min-level": "Het minimum niveau is 1",
|
|
74
82
|
"form-fields-error-latitude": "Ongeldige breedtegraad, er wordt een getal verwacht van maximaal 2 decimalen in graden tussen -90.00 en 90.00",
|
|
75
83
|
"form-fields-error-longitude": "Ongeldige lengtegraad, er wordt een getal verwacht van maximaal 2 decimalen in graden tussen -180.00 en 180.00",
|
|
84
|
+
"form-fields-error-latitude-minutes": "Breedtegraad moet tussen -90° en 90° zijn, minuten tussen 00 en 59",
|
|
85
|
+
"form-fields-error-longitude-minutes": "Lengtegraad moet tussen -180° en 180° zijn, minuten tussen 00 en 59",
|
|
86
|
+
"form-fields-error-invalid-minutes": "Minuten moeten tussen 00 en 59 zijn",
|
|
87
|
+
"form-fields-error-invalid-coordinate-format": "Ongeldig formaat: breedtegraad moet DDMM zijn, lengtegraad moet DDDMM zijn",
|
|
76
88
|
"form-fields-error-valid-max": "Het maximum niveau is bereikt",
|
|
77
89
|
"form-fields-error-level-lower": "Het lage niveau moet onder het hoge niveau zijn",
|
|
78
90
|
"form-fields-error-non-or-both-cooordinates": "Voer beide coördinaten in",
|
|
@@ -1019,22 +1031,70 @@ function decimalToDegreesMinutes(value) {
|
|
|
1019
1031
|
}
|
|
1020
1032
|
return "" + sign + degrees + "\xB0" + minutes.toString().padStart(2, '0') + "\u2032";
|
|
1021
1033
|
}
|
|
1022
|
-
|
|
1034
|
+
/**
|
|
1035
|
+
* Parse a cardinal direction prefix (N/S/E/W) from input string.
|
|
1036
|
+
* Returns { negative: boolean, remaining: string }
|
|
1037
|
+
*/
|
|
1038
|
+
function parseCardinalDirection(input, isLongitude) {
|
|
1039
|
+
var upperInput = input.toUpperCase().trim();
|
|
1040
|
+
var firstChar = upperInput.charAt(0);
|
|
1041
|
+
var remaining = upperInput.slice(1);
|
|
1042
|
+
// Check for valid cardinal direction based on coordinate type
|
|
1043
|
+
var validDirections = isLongitude ? ['W', 'E'] : ['S', 'N'];
|
|
1044
|
+
if (!validDirections.includes(firstChar)) {
|
|
1045
|
+
return {
|
|
1046
|
+
negative: false,
|
|
1047
|
+
remaining: input
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
switch (firstChar) {
|
|
1051
|
+
case 'W':
|
|
1052
|
+
case 'S':
|
|
1053
|
+
return {
|
|
1054
|
+
negative: true,
|
|
1055
|
+
remaining: remaining
|
|
1056
|
+
};
|
|
1057
|
+
case 'E':
|
|
1058
|
+
case 'N':
|
|
1059
|
+
return {
|
|
1060
|
+
negative: false,
|
|
1061
|
+
remaining: remaining
|
|
1062
|
+
};
|
|
1063
|
+
default:
|
|
1064
|
+
return {
|
|
1065
|
+
negative: false,
|
|
1066
|
+
remaining: input
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
function degreesMinutesToDecimal(input, isLongitude) {
|
|
1071
|
+
if (isLongitude === void 0) {
|
|
1072
|
+
isLongitude = false;
|
|
1073
|
+
}
|
|
1023
1074
|
var raw = input.toString().trim();
|
|
1024
|
-
|
|
1025
|
-
var
|
|
1026
|
-
|
|
1027
|
-
|
|
1075
|
+
// Parse cardinal direction prefix (W/E/S/N)
|
|
1076
|
+
var _parseCardinalDirecti = parseCardinalDirection(raw, isLongitude),
|
|
1077
|
+
cardinalNegative = _parseCardinalDirecti.negative,
|
|
1078
|
+
remaining = _parseCardinalDirecti.remaining;
|
|
1079
|
+
// Check for minus sign in remaining input
|
|
1080
|
+
var hasMinusSign = remaining.startsWith('-');
|
|
1081
|
+
var digits = remaining.replace(/[^0-9]/g, '');
|
|
1082
|
+
// Determine sign: either from cardinal direction or minus sign
|
|
1083
|
+
var sign = cardinalNegative || hasMinusSign ? -1 : 1;
|
|
1084
|
+
// For latitude: <= 2 digits is degrees only (e.g., "90" = 90°)
|
|
1085
|
+
// For longitude: <= 3 digits is degrees only (e.g., "180" = 180°)
|
|
1086
|
+
var degreesOnlyMaxLen = isLongitude ? 3 : 2;
|
|
1087
|
+
if (digits.length <= degreesOnlyMaxLen) {
|
|
1028
1088
|
var _deg = parseInt(digits || '0', 10);
|
|
1029
1089
|
return sign * _deg;
|
|
1030
1090
|
}
|
|
1031
1091
|
// split into degrees + minutes
|
|
1032
1092
|
var deg = parseInt(digits.slice(0, digits.length - 2), 10);
|
|
1033
1093
|
var min = parseInt(digits.slice(-2), 10);
|
|
1034
|
-
// normalize minutes overflow
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
return sign * (deg +
|
|
1094
|
+
// NOTE: We no longer normalize minutes overflow here.
|
|
1095
|
+
// Invalid minutes (>59) will be rejected by validation.
|
|
1096
|
+
// This preserves the raw value for validation purposes.
|
|
1097
|
+
return sign * (deg + min / 60);
|
|
1038
1098
|
}
|
|
1039
1099
|
var DegreesMinutesField = function DegreesMinutesField(_ref) {
|
|
1040
1100
|
var name = _ref.name,
|
|
@@ -1046,16 +1106,24 @@ var DegreesMinutesField = function DegreesMinutesField(_ref) {
|
|
|
1046
1106
|
_ref$size = _ref.size,
|
|
1047
1107
|
size = _ref$size === void 0 ? 'small' : _ref$size,
|
|
1048
1108
|
_ref$isLongitude = _ref.isLongitude,
|
|
1049
|
-
isLongitude = _ref$isLongitude === void 0 ? false : _ref$isLongitude
|
|
1050
|
-
t = _ref.t;
|
|
1109
|
+
isLongitude = _ref$isLongitude === void 0 ? false : _ref$isLongitude;
|
|
1051
1110
|
var _useFormContext = useFormContext(),
|
|
1052
1111
|
control = _useFormContext.control;
|
|
1112
|
+
var _useFormFieldsTransla = useFormFieldsTranslation(),
|
|
1113
|
+
t = _useFormFieldsTransla.t;
|
|
1053
1114
|
var _useState = useState(null),
|
|
1054
1115
|
localInput = _useState[0],
|
|
1055
1116
|
setLocalInput = _useState[1];
|
|
1056
1117
|
var _useState2 = useState(false),
|
|
1057
1118
|
isEditing = _useState2[0],
|
|
1058
1119
|
setIsEditing = _useState2[1];
|
|
1120
|
+
// Track raw input when there's a validation error so we show what user typed
|
|
1121
|
+
var _useState3 = useState(null),
|
|
1122
|
+
rawInputOnError = _useState3[0],
|
|
1123
|
+
setRawInputOnError = _useState3[1];
|
|
1124
|
+
// Error key constants to distinguish error types
|
|
1125
|
+
var INVALID_MINUTES_ERROR = 'invalidMinutes';
|
|
1126
|
+
var INVALID_FORMAT_ERROR = 'invalidFormat';
|
|
1059
1127
|
return jsx(Controller, {
|
|
1060
1128
|
control: control,
|
|
1061
1129
|
name: name,
|
|
@@ -1066,34 +1134,104 @@ var DegreesMinutesField = function DegreesMinutesField(_ref) {
|
|
|
1066
1134
|
var value = field.value,
|
|
1067
1135
|
onChange = field.onChange;
|
|
1068
1136
|
var handleChange = function handleChange(e) {
|
|
1069
|
-
|
|
1137
|
+
var rawValue = e.target.value;
|
|
1138
|
+
// Filter to only allow valid characters:
|
|
1139
|
+
// - Digits (0-9)
|
|
1140
|
+
// - Minus sign (-) only at the beginning
|
|
1141
|
+
// - Cardinal directions (W/E/N/S for longitude, N/S for latitude) only at the beginning
|
|
1142
|
+
// - Common formatting chars (°, ′, ', *) which will be stripped on blur
|
|
1143
|
+
var validCardinals = isLongitude ? /^[WwEe]/ : /^[NnSs]/;
|
|
1144
|
+
var filtered = '';
|
|
1145
|
+
for (var i = 0; i < rawValue.length; i += 1) {
|
|
1146
|
+
var _char = rawValue[i];
|
|
1147
|
+
var upperChar = _char.toUpperCase();
|
|
1148
|
+
if (/[0-9]/.test(_char)) {
|
|
1149
|
+
// Always allow digits
|
|
1150
|
+
filtered += _char;
|
|
1151
|
+
} else if (_char === '-' && filtered === '') {
|
|
1152
|
+
// Allow minus sign only at the beginning
|
|
1153
|
+
filtered += _char;
|
|
1154
|
+
} else if (i === 0 && validCardinals.test(upperChar) && filtered === '') {
|
|
1155
|
+
// Allow valid cardinal direction only at the very beginning
|
|
1156
|
+
filtered += upperChar;
|
|
1157
|
+
} else if (/[°′'*]/.test(_char)) {
|
|
1158
|
+
// Allow common formatting characters (will be stripped on blur)
|
|
1159
|
+
filtered += _char;
|
|
1160
|
+
}
|
|
1161
|
+
// All other characters are silently ignored
|
|
1162
|
+
}
|
|
1163
|
+
setLocalInput(filtered);
|
|
1070
1164
|
setIsEditing(true);
|
|
1165
|
+
// Clear error state when user starts typing
|
|
1166
|
+
setRawInputOnError(null);
|
|
1071
1167
|
};
|
|
1072
1168
|
var handleBlur = function handleBlur() {
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1169
|
+
// Handle clearing the field
|
|
1170
|
+
if (localInput === '' || localInput === null) {
|
|
1171
|
+
onChange(null);
|
|
1172
|
+
setIsEditing(false);
|
|
1173
|
+
setLocalInput(null);
|
|
1174
|
+
setRawInputOnError(null);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
// Handle just a minus sign
|
|
1178
|
+
if (localInput === '-') {
|
|
1179
|
+
setIsEditing(false);
|
|
1180
|
+
setLocalInput(null);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
// Parse cardinal direction prefix (W/E/S/N)
|
|
1184
|
+
var _parseCardinalDirecti2 = parseCardinalDirection(localInput, isLongitude),
|
|
1185
|
+
isNegativeFromCardinal = _parseCardinalDirecti2.negative,
|
|
1186
|
+
remainingInput = _parseCardinalDirecti2.remaining;
|
|
1187
|
+
var input = remainingInput.replace(/[^\d-]/g, '');
|
|
1188
|
+
var hasMinusSign = input.startsWith('-');
|
|
1189
|
+
var digits = input.replace(/[^0-9]/g, '');
|
|
1190
|
+
// Latitude: max 4 digits (DDMM), Longitude: max 5 (DDDMM)
|
|
1191
|
+
var maxLen = isLongitude ? 5 : 4;
|
|
1192
|
+
if (digits.length > maxLen) {
|
|
1193
|
+
// Too many digits - show error but keep user's input visible
|
|
1194
|
+
setRawInputOnError(localInput);
|
|
1195
|
+
onChange(INVALID_FORMAT_ERROR);
|
|
1196
|
+
setIsEditing(false);
|
|
1197
|
+
setLocalInput(null);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
// Check if minutes are valid (0-59) based on coordinate type
|
|
1201
|
+
// For latitude: > 2 digits means DDMM format
|
|
1202
|
+
// For longitude: > 3 digits means DDDMM format
|
|
1203
|
+
var degreesOnlyMaxLen = isLongitude ? 3 : 2;
|
|
1204
|
+
if (digits.length > degreesOnlyMaxLen) {
|
|
1205
|
+
var minutes = parseInt(digits.slice(-2), 10);
|
|
1206
|
+
if (minutes > 59) {
|
|
1207
|
+
// Invalid minutes - show error but keep user's input visible
|
|
1208
|
+
setRawInputOnError(localInput);
|
|
1209
|
+
onChange(INVALID_MINUTES_ERROR);
|
|
1210
|
+
setIsEditing(false);
|
|
1211
|
+
setLocalInput(null);
|
|
1212
|
+
return;
|
|
1088
1213
|
}
|
|
1089
1214
|
}
|
|
1215
|
+
// Determine if result should be negative
|
|
1216
|
+
var isNegative = isNegativeFromCardinal || hasMinusSign;
|
|
1217
|
+
var normalized = isNegative ? "-" + digits : digits;
|
|
1218
|
+
try {
|
|
1219
|
+
var decimal = degreesMinutesToDecimal(normalized, isLongitude);
|
|
1220
|
+
onChange(decimal);
|
|
1221
|
+
setRawInputOnError(null);
|
|
1222
|
+
} catch (_unused) {
|
|
1223
|
+
// Invalid, do not update form value
|
|
1224
|
+
}
|
|
1090
1225
|
setIsEditing(false);
|
|
1091
1226
|
setLocalInput(null);
|
|
1092
1227
|
};
|
|
1093
1228
|
var displayValue;
|
|
1094
1229
|
if (isEditing) {
|
|
1095
1230
|
displayValue = localInput != null ? localInput : '';
|
|
1096
|
-
} else if (
|
|
1231
|
+
} else if (fieldState.error && rawInputOnError !== null) {
|
|
1232
|
+
// Show the invalid input the user typed when there's an error
|
|
1233
|
+
displayValue = rawInputOnError;
|
|
1234
|
+
} else if (value != null && typeof value === 'number') {
|
|
1097
1235
|
displayValue = decimalToDegreesMinutes(value);
|
|
1098
1236
|
} else {
|
|
1099
1237
|
displayValue = '';
|
|
@@ -1117,9 +1255,20 @@ var DegreesMinutesField = function DegreesMinutesField(_ref) {
|
|
|
1117
1255
|
},
|
|
1118
1256
|
rules: {
|
|
1119
1257
|
validate: function validate(value) {
|
|
1120
|
-
if (value == null
|
|
1258
|
+
if (value == null) {
|
|
1121
1259
|
return true;
|
|
1122
1260
|
} // let empty pass
|
|
1261
|
+
// Check for special error markers
|
|
1262
|
+
if (value === INVALID_MINUTES_ERROR) {
|
|
1263
|
+
return t('form-fields-error-invalid-minutes');
|
|
1264
|
+
}
|
|
1265
|
+
if (value === INVALID_FORMAT_ERROR) {
|
|
1266
|
+
return t('form-fields-error-invalid-coordinate-format');
|
|
1267
|
+
}
|
|
1268
|
+
// Must be a number for range checks
|
|
1269
|
+
if (typeof value !== 'number' || isNaN(value)) {
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1123
1272
|
if (!isLongitude && (value < -90 || value > 90)) {
|
|
1124
1273
|
return t('form-fields-error-latitude-minutes');
|
|
1125
1274
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import type { TFunction } from 'i18next';
|
|
2
1
|
import React from 'react';
|
|
3
2
|
export declare function decimalToDegreesMinutes(value: number): string;
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Check if the raw input has valid minutes (0-59).
|
|
5
|
+
* For latitude: digits > 2 means DDMM format
|
|
6
|
+
* For longitude: digits > 3 means DDDMM format
|
|
7
|
+
* Returns true if valid, false otherwise.
|
|
8
|
+
*/
|
|
9
|
+
export declare function hasValidMinutes(input: string | number, isLongitude?: boolean): boolean;
|
|
10
|
+
export declare function degreesMinutesToDecimal(input: string | number, isLongitude?: boolean): number;
|
|
5
11
|
interface Props {
|
|
6
12
|
name: string;
|
|
7
13
|
label: string;
|
|
@@ -9,7 +15,6 @@ interface Props {
|
|
|
9
15
|
isReadOnly?: boolean;
|
|
10
16
|
size?: 'small' | 'medium';
|
|
11
17
|
isLongitude?: boolean;
|
|
12
|
-
t: TFunction;
|
|
13
18
|
}
|
|
14
19
|
export declare const DegreesMinutesField: React.FC<Props>;
|
|
15
20
|
export {};
|