react-input-mask-format 2.1.0 → 2.3.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/README.md +139 -1
- package/dist/chunk-CEZXZ7IJ.js +42 -0
- package/dist/chunk-CEZXZ7IJ.js.map +1 -0
- package/dist/index.cjs +214 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +199 -22
- package/dist/index.js.map +1 -1
- package/dist/number.cjs +342 -0
- package/dist/number.cjs.map +1 -0
- package/dist/number.d.cts +46 -0
- package/dist/number.d.ts +46 -0
- package/dist/number.js +280 -0
- package/dist/number.js.map +1 -0
- package/dist/presets.d.cts +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/time.cjs +240 -0
- package/dist/time.cjs.map +1 -0
- package/dist/time.d.cts +28 -0
- package/dist/time.d.ts +28 -0
- package/dist/time.js +178 -0
- package/dist/time.js.map +1 -0
- package/dist/{types-Bfu5Jmh0.d.cts → types-BTNqtchO.d.cts} +17 -1
- package/dist/{types-Bfu5Jmh0.d.ts → types-BTNqtchO.d.ts} +17 -1
- package/package.json +12 -2
package/dist/time.cjs
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/time/index.ts
|
|
31
|
+
var time_exports = {};
|
|
32
|
+
__export(time_exports, {
|
|
33
|
+
TimeFormat: () => TimeFormat,
|
|
34
|
+
formatTime: () => formatTime,
|
|
35
|
+
parseTime: () => parseTime,
|
|
36
|
+
useTimeFormat: () => useTimeFormat
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(time_exports);
|
|
39
|
+
|
|
40
|
+
// src/time/time-format.tsx
|
|
41
|
+
var import_react = __toESM(require("react"), 1);
|
|
42
|
+
|
|
43
|
+
// src/time/format-time.ts
|
|
44
|
+
function tokenizeTime(raw) {
|
|
45
|
+
const digits = String(raw != null ? raw : "").replace(/\D/g, "").slice(0, 4);
|
|
46
|
+
let hours = digits.slice(0, 2);
|
|
47
|
+
let minutes = digits.slice(2, 4);
|
|
48
|
+
if (hours.length === 2) {
|
|
49
|
+
hours = String(Math.min(parseInt(hours, 10), 23)).padStart(2, "0");
|
|
50
|
+
}
|
|
51
|
+
if (minutes.length === 2) {
|
|
52
|
+
minutes = String(Math.min(parseInt(minutes, 10), 59)).padStart(2, "0");
|
|
53
|
+
}
|
|
54
|
+
return { hours, minutes };
|
|
55
|
+
}
|
|
56
|
+
function buildFormatted(parts, separator) {
|
|
57
|
+
const { hours, minutes } = parts;
|
|
58
|
+
if (hours === "") return "";
|
|
59
|
+
if (hours.length < 2) return hours;
|
|
60
|
+
if (minutes === "") return hours + separator;
|
|
61
|
+
return hours + separator + minutes;
|
|
62
|
+
}
|
|
63
|
+
function formatTime(input, options) {
|
|
64
|
+
var _a;
|
|
65
|
+
const separator = (_a = options == null ? void 0 : options.separator) != null ? _a : ":";
|
|
66
|
+
return buildFormatted(tokenizeTime(input), separator);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/time/parse-time.ts
|
|
70
|
+
function collapseTrailingSeparator(raw, previous, separator) {
|
|
71
|
+
return previous.endsWith(separator) && raw === previous.slice(0, -separator.length) ? raw.slice(0, -1) : raw;
|
|
72
|
+
}
|
|
73
|
+
function parseTime(formatted, options) {
|
|
74
|
+
var _a;
|
|
75
|
+
const separator = (_a = options == null ? void 0 : options.separator) != null ? _a : ":";
|
|
76
|
+
const parts = tokenizeTime(formatted);
|
|
77
|
+
const formattedValue = buildFormatted(parts, separator);
|
|
78
|
+
const hours = parts.hours.length === 2 ? parseInt(parts.hours, 10) : void 0;
|
|
79
|
+
const minutes = parts.minutes.length === 2 ? parseInt(parts.minutes, 10) : void 0;
|
|
80
|
+
const value = hours !== void 0 && minutes !== void 0 ? `${parts.hours}:${parts.minutes}` : "";
|
|
81
|
+
return { value, formattedValue, hours, minutes };
|
|
82
|
+
}
|
|
83
|
+
function digitsBeforeCaret(value, caret) {
|
|
84
|
+
let count = 0;
|
|
85
|
+
for (let i = 0; i < caret && i < value.length; i++) {
|
|
86
|
+
if (value[i] >= "0" && value[i] <= "9") count++;
|
|
87
|
+
}
|
|
88
|
+
return count;
|
|
89
|
+
}
|
|
90
|
+
function caretAfterDigits(formatted, digitsBefore) {
|
|
91
|
+
if (digitsBefore <= 0) {
|
|
92
|
+
const first = formatted.search(/\d/);
|
|
93
|
+
return first === -1 ? formatted.length : first;
|
|
94
|
+
}
|
|
95
|
+
let seen = 0;
|
|
96
|
+
for (let i = 0; i < formatted.length; i++) {
|
|
97
|
+
if (formatted[i] >= "0" && formatted[i] <= "9") {
|
|
98
|
+
seen++;
|
|
99
|
+
if (seen === digitsBefore) return i + 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return formatted.length;
|
|
103
|
+
}
|
|
104
|
+
function resolveCaret(values, digitsBefore, options) {
|
|
105
|
+
var _a;
|
|
106
|
+
const separator = (_a = options == null ? void 0 : options.separator) != null ? _a : ":";
|
|
107
|
+
const caret = caretAfterDigits(values.formattedValue, digitsBefore);
|
|
108
|
+
if (separator && values.formattedValue.slice(caret, caret + separator.length) === separator) {
|
|
109
|
+
return caret + separator.length;
|
|
110
|
+
}
|
|
111
|
+
return caret;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/utils/input.ts
|
|
115
|
+
function setInputSelection(input, start, end) {
|
|
116
|
+
if (end === void 0) {
|
|
117
|
+
end = start;
|
|
118
|
+
}
|
|
119
|
+
input.setSelectionRange(start, end);
|
|
120
|
+
}
|
|
121
|
+
function isInputFocused(input) {
|
|
122
|
+
const inputDocument = input.ownerDocument;
|
|
123
|
+
return inputDocument.hasFocus() && inputDocument.activeElement === input;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/time/time-format.tsx
|
|
127
|
+
var TimeFormat = (0, import_react.forwardRef)(function TimeFormat2(props, forwardedRef) {
|
|
128
|
+
const { value = "", onValueChange, separator, ...domProps } = props;
|
|
129
|
+
const options = { separator };
|
|
130
|
+
const innerRef = (0, import_react.useRef)(null);
|
|
131
|
+
const caretRef = (0, import_react.useRef)(null);
|
|
132
|
+
const lastValuesRef = (0, import_react.useRef)(null);
|
|
133
|
+
const [, forceUpdate] = (0, import_react.useReducer)((n) => n + 1, 0);
|
|
134
|
+
const last = lastValuesRef.current;
|
|
135
|
+
const formatted = last !== null && (value === last.value || value === last.formattedValue) ? last.formattedValue : formatTime(value != null ? value : "", options);
|
|
136
|
+
function handleChange(event) {
|
|
137
|
+
var _a, _b;
|
|
138
|
+
const el = event.target;
|
|
139
|
+
const caret = (_a = el.selectionStart) != null ? _a : el.value.length;
|
|
140
|
+
const raw = collapseTrailingSeparator(el.value, formatted, (_b = options.separator) != null ? _b : ":");
|
|
141
|
+
const digits = digitsBeforeCaret(raw, caret);
|
|
142
|
+
const values = parseTime(raw, options);
|
|
143
|
+
caretRef.current = resolveCaret(values, digits, options);
|
|
144
|
+
lastValuesRef.current = values;
|
|
145
|
+
forceUpdate();
|
|
146
|
+
onValueChange == null ? void 0 : onValueChange(values);
|
|
147
|
+
}
|
|
148
|
+
(0, import_react.useLayoutEffect)(() => {
|
|
149
|
+
const el = innerRef.current;
|
|
150
|
+
if (el && caretRef.current !== null && isInputFocused(el)) {
|
|
151
|
+
setInputSelection(el, caretRef.current, caretRef.current);
|
|
152
|
+
caretRef.current = null;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
function setRef(el) {
|
|
156
|
+
innerRef.current = el;
|
|
157
|
+
if (typeof forwardedRef === "function") forwardedRef(el);
|
|
158
|
+
else if (forwardedRef)
|
|
159
|
+
forwardedRef.current = el;
|
|
160
|
+
}
|
|
161
|
+
return /* @__PURE__ */ import_react.default.createElement("input", { ...domProps, ref: setRef, value: formatted, onChange: handleChange });
|
|
162
|
+
});
|
|
163
|
+
TimeFormat.displayName = "TimeFormat";
|
|
164
|
+
|
|
165
|
+
// src/time/use-time-format.ts
|
|
166
|
+
var import_react2 = require("react");
|
|
167
|
+
|
|
168
|
+
// src/set-native-value.ts
|
|
169
|
+
function setNativeValue(input, value) {
|
|
170
|
+
const descriptor = Object.getOwnPropertyDescriptor(
|
|
171
|
+
HTMLInputElement.prototype,
|
|
172
|
+
"value"
|
|
173
|
+
);
|
|
174
|
+
const setter = descriptor && descriptor.set;
|
|
175
|
+
if (setter) {
|
|
176
|
+
setter.call(input, value);
|
|
177
|
+
} else {
|
|
178
|
+
input.value = value;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// src/time/use-time-format.ts
|
|
183
|
+
var IS_JSDOM = typeof navigator !== "undefined" && navigator.userAgent.includes("jsdom");
|
|
184
|
+
function useTimeFormat(options) {
|
|
185
|
+
const optionsRef = (0, import_react2.useRef)(options);
|
|
186
|
+
optionsRef.current = options;
|
|
187
|
+
const inputRef = (0, import_react2.useRef)(null);
|
|
188
|
+
const handlerRef = (0, import_react2.useRef)(null);
|
|
189
|
+
return (0, import_react2.useCallback)((el) => {
|
|
190
|
+
if (el) {
|
|
191
|
+
let previous = el.value;
|
|
192
|
+
const handler = () => {
|
|
193
|
+
var _a, _b, _c;
|
|
194
|
+
const opts = optionsRef.current;
|
|
195
|
+
const caret = (_a = el.selectionStart) != null ? _a : el.value.length;
|
|
196
|
+
const raw = collapseTrailingSeparator(el.value, previous, (_b = opts.separator) != null ? _b : ":");
|
|
197
|
+
const digits = digitsBeforeCaret(raw, caret);
|
|
198
|
+
const values = parseTime(raw, opts);
|
|
199
|
+
setNativeValue(el, values.formattedValue);
|
|
200
|
+
previous = values.formattedValue;
|
|
201
|
+
if (isInputFocused(el)) {
|
|
202
|
+
const next = resolveCaret(values, digits, opts);
|
|
203
|
+
setInputSelection(el, next, next);
|
|
204
|
+
}
|
|
205
|
+
if (IS_JSDOM) {
|
|
206
|
+
queueMicrotask(() => {
|
|
207
|
+
if (el.value !== values.formattedValue) return;
|
|
208
|
+
el.value = values.formattedValue;
|
|
209
|
+
if (isInputFocused(el)) {
|
|
210
|
+
const c = resolveCaret(values, digits, opts);
|
|
211
|
+
setInputSelection(el, c, c);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
(_c = opts.onValueChange) == null ? void 0 : _c.call(opts, values);
|
|
216
|
+
};
|
|
217
|
+
el.addEventListener("input", handler);
|
|
218
|
+
handlerRef.current = handler;
|
|
219
|
+
inputRef.current = el;
|
|
220
|
+
if (el.value) {
|
|
221
|
+
setNativeValue(el, formatTime(el.value, optionsRef.current));
|
|
222
|
+
previous = formatTime(el.value, optionsRef.current);
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
if (inputRef.current && handlerRef.current) {
|
|
226
|
+
inputRef.current.removeEventListener("input", handlerRef.current);
|
|
227
|
+
}
|
|
228
|
+
inputRef.current = null;
|
|
229
|
+
handlerRef.current = null;
|
|
230
|
+
}
|
|
231
|
+
}, []);
|
|
232
|
+
}
|
|
233
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
234
|
+
0 && (module.exports = {
|
|
235
|
+
TimeFormat,
|
|
236
|
+
formatTime,
|
|
237
|
+
parseTime,
|
|
238
|
+
useTimeFormat
|
|
239
|
+
});
|
|
240
|
+
//# sourceMappingURL=time.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/time/index.ts","../src/time/time-format.tsx","../src/time/format-time.ts","../src/time/parse-time.ts","../src/utils/input.ts","../src/time/use-time-format.ts","../src/set-native-value.ts"],"sourcesContent":["export { TimeFormat } from \"./time-format\";\nexport type { TimeFormatProps } from \"./time-format\";\nexport { useTimeFormat } from \"./use-time-format\";\nexport type { UseTimeFormatOptions } from \"./use-time-format\";\nexport { formatTime } from \"./format-time\";\nexport { parseTime } from \"./parse-time\";\nexport type { TimeFormatOptions, TimeFormatValues } from \"./types\";\n","import React, { forwardRef, useLayoutEffect, useReducer, useRef } from \"react\";\nimport type { TimeFormatOptions, TimeFormatValues } from \"./types\";\nimport { formatTime } from \"./format-time\";\nimport {\n collapseTrailingSeparator,\n parseTime,\n digitsBeforeCaret,\n resolveCaret,\n} from \"./parse-time\";\nimport { isInputFocused, setInputSelection } from \"../utils/input\";\n\nexport interface TimeFormatProps\n extends TimeFormatOptions,\n Omit<React.InputHTMLAttributes<HTMLInputElement>, \"value\" | \"onChange\"> {\n value?: string;\n onValueChange?: (values: TimeFormatValues) => void;\n}\n\nexport const TimeFormat = forwardRef<HTMLInputElement, TimeFormatProps>(function TimeFormat(\n props,\n forwardedRef\n) {\n const { value = \"\", onValueChange, separator, ...domProps } = props;\n const options: TimeFormatOptions = { separator };\n\n const innerRef = useRef<HTMLInputElement | null>(null);\n const caretRef = useRef<number | null>(null);\n const lastValuesRef = useRef<TimeFormatValues | null>(null);\n\n const [, forceUpdate] = useReducer((n: number) => n + 1, 0);\n\n const last = lastValuesRef.current;\n const formatted =\n last !== null && (value === last.value || value === last.formattedValue)\n ? last.formattedValue\n : formatTime(value ?? \"\", options);\n\n function handleChange(event: React.ChangeEvent<HTMLInputElement>): void {\n const el = event.target;\n const caret = el.selectionStart ?? el.value.length;\n const raw = collapseTrailingSeparator(el.value, formatted, options.separator ?? \":\");\n const digits = digitsBeforeCaret(raw, caret);\n const values = parseTime(raw, options);\n caretRef.current = resolveCaret(values, digits, options);\n lastValuesRef.current = values;\n forceUpdate();\n onValueChange?.(values);\n }\n\n useLayoutEffect(() => {\n const el = innerRef.current;\n if (el && caretRef.current !== null && isInputFocused(el)) {\n setInputSelection(el, caretRef.current, caretRef.current);\n caretRef.current = null;\n }\n });\n\n function setRef(el: HTMLInputElement | null): void {\n innerRef.current = el;\n if (typeof forwardedRef === \"function\") forwardedRef(el);\n else if (forwardedRef)\n (forwardedRef as React.MutableRefObject<HTMLInputElement | null>).current = el;\n }\n\n return <input {...domProps} ref={setRef} value={formatted} onChange={handleChange} />;\n});\n\nTimeFormat.displayName = \"TimeFormat\";\n","import type { TimeFormatOptions } from \"./types\";\n\nexport interface TimeParts {\n hours: string;\n minutes: string;\n}\n\nexport function tokenizeTime(raw: string | number): TimeParts {\n const digits = String(raw ?? \"\").replace(/\\D/g, \"\").slice(0, 4);\n let hours = digits.slice(0, 2);\n let minutes = digits.slice(2, 4);\n if (hours.length === 2) {\n hours = String(Math.min(parseInt(hours, 10), 23)).padStart(2, \"0\");\n }\n if (minutes.length === 2) {\n minutes = String(Math.min(parseInt(minutes, 10), 59)).padStart(2, \"0\");\n }\n return { hours, minutes };\n}\n\nexport function buildFormatted(parts: TimeParts, separator: string): string {\n const { hours, minutes } = parts;\n if (hours === \"\") return \"\";\n if (hours.length < 2) return hours;\n if (minutes === \"\") return hours + separator;\n return hours + separator + minutes;\n}\n\nexport function formatTime(input: string | number, options?: TimeFormatOptions): string {\n const separator = options?.separator ?? \":\";\n return buildFormatted(tokenizeTime(input), separator);\n}\n","import type { TimeFormatOptions, TimeFormatValues } from \"./types\";\nimport { tokenizeTime, buildFormatted } from \"./format-time\";\n\nexport function collapseTrailingSeparator(\n raw: string,\n previous: string,\n separator: string\n): string {\n return previous.endsWith(separator) && raw === previous.slice(0, -separator.length)\n ? raw.slice(0, -1)\n : raw;\n}\n\nexport function parseTime(formatted: string, options?: TimeFormatOptions): TimeFormatValues {\n const separator = options?.separator ?? \":\";\n const parts = tokenizeTime(formatted);\n const formattedValue = buildFormatted(parts, separator);\n const hours = parts.hours.length === 2 ? parseInt(parts.hours, 10) : undefined;\n const minutes = parts.minutes.length === 2 ? parseInt(parts.minutes, 10) : undefined;\n const value =\n hours !== undefined && minutes !== undefined ? `${parts.hours}:${parts.minutes}` : \"\";\n return { value, formattedValue, hours, minutes };\n}\n\nexport function digitsBeforeCaret(value: string, caret: number): number {\n let count = 0;\n for (let i = 0; i < caret && i < value.length; i++) {\n if (value[i] >= \"0\" && value[i] <= \"9\") count++;\n }\n return count;\n}\n\nfunction caretAfterDigits(formatted: string, digitsBefore: number): number {\n if (digitsBefore <= 0) {\n const first = formatted.search(/\\d/);\n return first === -1 ? formatted.length : first;\n }\n let seen = 0;\n for (let i = 0; i < formatted.length; i++) {\n if (formatted[i] >= \"0\" && formatted[i] <= \"9\") {\n seen++;\n if (seen === digitsBefore) return i + 1;\n }\n }\n return formatted.length;\n}\n\nexport function resolveCaret(\n values: TimeFormatValues,\n digitsBefore: number,\n options?: TimeFormatOptions\n): number {\n const separator = options?.separator ?? \":\";\n const caret = caretAfterDigits(values.formattedValue, digitsBefore);\n if (separator && values.formattedValue.slice(caret, caret + separator.length) === separator) {\n return caret + separator.length;\n }\n return caret;\n}\n","import type { Selection } from \"../types\";\n\nexport function setInputSelection(\n input: HTMLInputElement,\n start: number,\n end?: number\n): void {\n if (end === undefined) {\n end = start;\n }\n input.setSelectionRange(start, end);\n}\n\nexport function getInputSelection(input: HTMLInputElement): Required<Selection> {\n const start = input.selectionStart;\n const end = input.selectionEnd;\n\n return {\n start,\n end,\n length: (end ?? 0) - (start ?? 0)\n };\n}\n\nexport function isInputFocused(input: HTMLInputElement): boolean {\n const inputDocument = input.ownerDocument;\n return inputDocument.hasFocus() && inputDocument.activeElement === input;\n}\n","import { useRef, useCallback } from \"react\";\nimport type React from \"react\";\nimport type { TimeFormatValues } from \"./types\";\nimport type { TimeFormatOptions } from \"./types\";\nimport { formatTime } from \"./format-time\";\nimport {\n collapseTrailingSeparator,\n parseTime,\n digitsBeforeCaret,\n resolveCaret,\n} from \"./parse-time\";\nimport { setNativeValue } from \"../set-native-value\";\nimport { isInputFocused, setInputSelection } from \"../utils/input\";\n\nexport interface UseTimeFormatOptions extends TimeFormatOptions {\n onValueChange?: (values: TimeFormatValues) => void;\n}\n\nconst IS_JSDOM =\n typeof navigator !== \"undefined\" && navigator.userAgent.includes(\"jsdom\");\n\nexport function useTimeFormat(\n options: UseTimeFormatOptions\n): React.RefCallback<HTMLInputElement> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const handlerRef = useRef<((event: Event) => void) | null>(null);\n\n return useCallback((el: HTMLInputElement | null) => {\n if (el) {\n let previous = el.value;\n const handler = (): void => {\n const opts = optionsRef.current;\n const caret = el.selectionStart ?? el.value.length;\n const raw = collapseTrailingSeparator(el.value, previous, opts.separator ?? \":\");\n const digits = digitsBeforeCaret(raw, caret);\n const values = parseTime(raw, opts);\n setNativeValue(el, values.formattedValue);\n previous = values.formattedValue;\n if (isInputFocused(el)) {\n const next = resolveCaret(values, digits, opts);\n setInputSelection(el, next, next);\n }\n // JSDOM-ONLY: resync @testing-library/user-event v14's shadow-value cache.\n // setNativeValue above bypasses React's value tracker; under jsdom that\n // leaves user-event's per-input shadow value stale, corrupting masking from\n // ~the 4th keystroke. A plain (idempotent) reassignment resyncs it.\n // MUST NOT run in a real browser: there, microtasks drain BETWEEN event\n // listeners, so this write would fight React; real browsers read the live\n // DOM and need no resync. onValueChange (below) is called directly, not via\n // React's tracker, so it is unaffected in either environment.\n if (IS_JSDOM) {\n queueMicrotask(() => {\n if (el.value !== values.formattedValue) return;\n el.value = values.formattedValue;\n if (isInputFocused(el)) {\n const c = resolveCaret(values, digits, opts);\n setInputSelection(el, c, c);\n }\n });\n }\n opts.onValueChange?.(values);\n };\n el.addEventListener(\"input\", handler);\n handlerRef.current = handler;\n inputRef.current = el;\n if (el.value) {\n setNativeValue(el, formatTime(el.value, optionsRef.current));\n previous = formatTime(el.value, optionsRef.current);\n }\n } else {\n if (inputRef.current && handlerRef.current) {\n inputRef.current.removeEventListener(\"input\", handlerRef.current);\n }\n inputRef.current = null;\n handlerRef.current = null;\n }\n }, []);\n}\n","// Write to input.value through the native prototype setter so React's\n// internal value tracker stays stale. The user's keystroke `input` event then\n// bubbles into React's root listener, which sees masked value != stale tracker\n// and fires the consumer's onChange with the masked value. Using the tracked\n// (React-wrapped) setter instead would suppress that onChange.\nexport function setNativeValue(input: HTMLInputElement, value: string): void {\n const descriptor = Object.getOwnPropertyDescriptor(\n HTMLInputElement.prototype,\n \"value\"\n );\n const setter = descriptor && descriptor.set;\n if (setter) {\n setter.call(input, value);\n } else {\n input.value = value;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAuE;;;ACOhE,SAAS,aAAa,KAAiC;AAC5D,QAAM,SAAS,OAAO,oBAAO,EAAE,EAAE,QAAQ,OAAO,EAAE,EAAE,MAAM,GAAG,CAAC;AAC9D,MAAI,QAAQ,OAAO,MAAM,GAAG,CAAC;AAC7B,MAAI,UAAU,OAAO,MAAM,GAAG,CAAC;AAC/B,MAAI,MAAM,WAAW,GAAG;AACtB,YAAQ,OAAO,KAAK,IAAI,SAAS,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,EACnE;AACA,MAAI,QAAQ,WAAW,GAAG;AACxB,cAAU,OAAO,KAAK,IAAI,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,EACvE;AACA,SAAO,EAAE,OAAO,QAAQ;AAC1B;AAEO,SAAS,eAAe,OAAkB,WAA2B;AAC1E,QAAM,EAAE,OAAO,QAAQ,IAAI;AAC3B,MAAI,UAAU,GAAI,QAAO;AACzB,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,MAAI,YAAY,GAAI,QAAO,QAAQ;AACnC,SAAO,QAAQ,YAAY;AAC7B;AAEO,SAAS,WAAW,OAAwB,SAAqC;AA5BxF;AA6BE,QAAM,aAAY,wCAAS,cAAT,YAAsB;AACxC,SAAO,eAAe,aAAa,KAAK,GAAG,SAAS;AACtD;;;AC5BO,SAAS,0BACd,KACA,UACA,WACQ;AACR,SAAO,SAAS,SAAS,SAAS,KAAK,QAAQ,SAAS,MAAM,GAAG,CAAC,UAAU,MAAM,IAC9E,IAAI,MAAM,GAAG,EAAE,IACf;AACN;AAEO,SAAS,UAAU,WAAmB,SAA+C;AAb5F;AAcE,QAAM,aAAY,wCAAS,cAAT,YAAsB;AACxC,QAAM,QAAQ,aAAa,SAAS;AACpC,QAAM,iBAAiB,eAAe,OAAO,SAAS;AACtD,QAAM,QAAQ,MAAM,MAAM,WAAW,IAAI,SAAS,MAAM,OAAO,EAAE,IAAI;AACrE,QAAM,UAAU,MAAM,QAAQ,WAAW,IAAI,SAAS,MAAM,SAAS,EAAE,IAAI;AAC3E,QAAM,QACJ,UAAU,UAAa,YAAY,SAAY,GAAG,MAAM,KAAK,IAAI,MAAM,OAAO,KAAK;AACrF,SAAO,EAAE,OAAO,gBAAgB,OAAO,QAAQ;AACjD;AAEO,SAAS,kBAAkB,OAAe,OAAuB;AACtE,MAAI,QAAQ;AACZ,WAAS,IAAI,GAAG,IAAI,SAAS,IAAI,MAAM,QAAQ,KAAK;AAClD,QAAI,MAAM,CAAC,KAAK,OAAO,MAAM,CAAC,KAAK,IAAK;AAAA,EAC1C;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,WAAmB,cAA8B;AACzE,MAAI,gBAAgB,GAAG;AACrB,UAAM,QAAQ,UAAU,OAAO,IAAI;AACnC,WAAO,UAAU,KAAK,UAAU,SAAS;AAAA,EAC3C;AACA,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,QAAI,UAAU,CAAC,KAAK,OAAO,UAAU,CAAC,KAAK,KAAK;AAC9C;AACA,UAAI,SAAS,aAAc,QAAO,IAAI;AAAA,IACxC;AAAA,EACF;AACA,SAAO,UAAU;AACnB;AAEO,SAAS,aACd,QACA,cACA,SACQ;AAnDV;AAoDE,QAAM,aAAY,wCAAS,cAAT,YAAsB;AACxC,QAAM,QAAQ,iBAAiB,OAAO,gBAAgB,YAAY;AAClE,MAAI,aAAa,OAAO,eAAe,MAAM,OAAO,QAAQ,UAAU,MAAM,MAAM,WAAW;AAC3F,WAAO,QAAQ,UAAU;AAAA,EAC3B;AACA,SAAO;AACT;;;ACxDO,SAAS,kBACd,OACA,OACA,KACM;AACN,MAAI,QAAQ,QAAW;AACrB,UAAM;AAAA,EACR;AACA,QAAM,kBAAkB,OAAO,GAAG;AACpC;AAaO,SAAS,eAAe,OAAkC;AAC/D,QAAM,gBAAgB,MAAM;AAC5B,SAAO,cAAc,SAAS,KAAK,cAAc,kBAAkB;AACrE;;;AHTO,IAAM,iBAAa,yBAA8C,SAASA,YAC/E,OACA,cACA;AACA,QAAM,EAAE,QAAQ,IAAI,eAAe,WAAW,GAAG,SAAS,IAAI;AAC9D,QAAM,UAA6B,EAAE,UAAU;AAE/C,QAAM,eAAW,qBAAgC,IAAI;AACrD,QAAM,eAAW,qBAAsB,IAAI;AAC3C,QAAM,oBAAgB,qBAAgC,IAAI;AAE1D,QAAM,CAAC,EAAE,WAAW,QAAI,yBAAW,CAAC,MAAc,IAAI,GAAG,CAAC;AAE1D,QAAM,OAAO,cAAc;AAC3B,QAAM,YACJ,SAAS,SAAS,UAAU,KAAK,SAAS,UAAU,KAAK,kBACrD,KAAK,iBACL,WAAW,wBAAS,IAAI,OAAO;AAErC,WAAS,aAAa,OAAkD;AArC1E;AAsCI,UAAM,KAAK,MAAM;AACjB,UAAM,SAAQ,QAAG,mBAAH,YAAqB,GAAG,MAAM;AAC5C,UAAM,MAAM,0BAA0B,GAAG,OAAO,YAAW,aAAQ,cAAR,YAAqB,GAAG;AACnF,UAAM,SAAS,kBAAkB,KAAK,KAAK;AAC3C,UAAM,SAAS,UAAU,KAAK,OAAO;AACrC,aAAS,UAAU,aAAa,QAAQ,QAAQ,OAAO;AACvD,kBAAc,UAAU;AACxB,gBAAY;AACZ,mDAAgB;AAAA,EAClB;AAEA,oCAAgB,MAAM;AACpB,UAAM,KAAK,SAAS;AACpB,QAAI,MAAM,SAAS,YAAY,QAAQ,eAAe,EAAE,GAAG;AACzD,wBAAkB,IAAI,SAAS,SAAS,SAAS,OAAO;AACxD,eAAS,UAAU;AAAA,IACrB;AAAA,EACF,CAAC;AAED,WAAS,OAAO,IAAmC;AACjD,aAAS,UAAU;AACnB,QAAI,OAAO,iBAAiB,WAAY,cAAa,EAAE;AAAA,aAC9C;AACP,MAAC,aAAiE,UAAU;AAAA,EAChF;AAEA,SAAO,6BAAAC,QAAA,cAAC,WAAO,GAAG,UAAU,KAAK,QAAQ,OAAO,WAAW,UAAU,cAAc;AACrF,CAAC;AAED,WAAW,cAAc;;;AInEzB,IAAAC,gBAAoC;;;ACK7B,SAAS,eAAe,OAAyB,OAAqB;AAC3E,QAAM,aAAa,OAAO;AAAA,IACxB,iBAAiB;AAAA,IACjB;AAAA,EACF;AACA,QAAM,SAAS,cAAc,WAAW;AACxC,MAAI,QAAQ;AACV,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B,OAAO;AACL,UAAM,QAAQ;AAAA,EAChB;AACF;;;ADEA,IAAM,WACJ,OAAO,cAAc,eAAe,UAAU,UAAU,SAAS,OAAO;AAEnE,SAAS,cACd,SACqC;AACrC,QAAM,iBAAa,sBAAO,OAAO;AACjC,aAAW,UAAU;AAErB,QAAM,eAAW,sBAAgC,IAAI;AACrD,QAAM,iBAAa,sBAAwC,IAAI;AAE/D,aAAO,2BAAY,CAAC,OAAgC;AAClD,QAAI,IAAI;AACN,UAAI,WAAW,GAAG;AAClB,YAAM,UAAU,MAAY;AAjClC;AAkCQ,cAAM,OAAO,WAAW;AACxB,cAAM,SAAQ,QAAG,mBAAH,YAAqB,GAAG,MAAM;AAC5C,cAAM,MAAM,0BAA0B,GAAG,OAAO,WAAU,UAAK,cAAL,YAAkB,GAAG;AAC/E,cAAM,SAAS,kBAAkB,KAAK,KAAK;AAC3C,cAAM,SAAS,UAAU,KAAK,IAAI;AAClC,uBAAe,IAAI,OAAO,cAAc;AACxC,mBAAW,OAAO;AAClB,YAAI,eAAe,EAAE,GAAG;AACtB,gBAAM,OAAO,aAAa,QAAQ,QAAQ,IAAI;AAC9C,4BAAkB,IAAI,MAAM,IAAI;AAAA,QAClC;AASA,YAAI,UAAU;AACZ,yBAAe,MAAM;AACnB,gBAAI,GAAG,UAAU,OAAO,eAAgB;AACxC,eAAG,QAAQ,OAAO;AAClB,gBAAI,eAAe,EAAE,GAAG;AACtB,oBAAM,IAAI,aAAa,QAAQ,QAAQ,IAAI;AAC3C,gCAAkB,IAAI,GAAG,CAAC;AAAA,YAC5B;AAAA,UACF,CAAC;AAAA,QACH;AACA,mBAAK,kBAAL,8BAAqB;AAAA,MACvB;AACA,SAAG,iBAAiB,SAAS,OAAO;AACpC,iBAAW,UAAU;AACrB,eAAS,UAAU;AACnB,UAAI,GAAG,OAAO;AACZ,uBAAe,IAAI,WAAW,GAAG,OAAO,WAAW,OAAO,CAAC;AAC3D,mBAAW,WAAW,GAAG,OAAO,WAAW,OAAO;AAAA,MACpD;AAAA,IACF,OAAO;AACL,UAAI,SAAS,WAAW,WAAW,SAAS;AAC1C,iBAAS,QAAQ,oBAAoB,SAAS,WAAW,OAAO;AAAA,MAClE;AACA,eAAS,UAAU;AACnB,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,CAAC;AACP;","names":["TimeFormat","React","import_react"]}
|
package/dist/time.d.cts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
|
|
3
|
+
interface TimeFormatOptions {
|
|
4
|
+
separator?: string;
|
|
5
|
+
}
|
|
6
|
+
interface TimeFormatValues {
|
|
7
|
+
value: string;
|
|
8
|
+
formattedValue: string;
|
|
9
|
+
hours: number | undefined;
|
|
10
|
+
minutes: number | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface TimeFormatProps extends TimeFormatOptions, Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange"> {
|
|
14
|
+
value?: string;
|
|
15
|
+
onValueChange?: (values: TimeFormatValues) => void;
|
|
16
|
+
}
|
|
17
|
+
declare const TimeFormat: React__default.ForwardRefExoticComponent<TimeFormatProps & React__default.RefAttributes<HTMLInputElement>>;
|
|
18
|
+
|
|
19
|
+
interface UseTimeFormatOptions extends TimeFormatOptions {
|
|
20
|
+
onValueChange?: (values: TimeFormatValues) => void;
|
|
21
|
+
}
|
|
22
|
+
declare function useTimeFormat(options: UseTimeFormatOptions): React__default.RefCallback<HTMLInputElement>;
|
|
23
|
+
|
|
24
|
+
declare function formatTime(input: string | number, options?: TimeFormatOptions): string;
|
|
25
|
+
|
|
26
|
+
declare function parseTime(formatted: string, options?: TimeFormatOptions): TimeFormatValues;
|
|
27
|
+
|
|
28
|
+
export { TimeFormat, type TimeFormatOptions, type TimeFormatProps, type TimeFormatValues, type UseTimeFormatOptions, formatTime, parseTime, useTimeFormat };
|
package/dist/time.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
|
|
3
|
+
interface TimeFormatOptions {
|
|
4
|
+
separator?: string;
|
|
5
|
+
}
|
|
6
|
+
interface TimeFormatValues {
|
|
7
|
+
value: string;
|
|
8
|
+
formattedValue: string;
|
|
9
|
+
hours: number | undefined;
|
|
10
|
+
minutes: number | undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface TimeFormatProps extends TimeFormatOptions, Omit<React__default.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange"> {
|
|
14
|
+
value?: string;
|
|
15
|
+
onValueChange?: (values: TimeFormatValues) => void;
|
|
16
|
+
}
|
|
17
|
+
declare const TimeFormat: React__default.ForwardRefExoticComponent<TimeFormatProps & React__default.RefAttributes<HTMLInputElement>>;
|
|
18
|
+
|
|
19
|
+
interface UseTimeFormatOptions extends TimeFormatOptions {
|
|
20
|
+
onValueChange?: (values: TimeFormatValues) => void;
|
|
21
|
+
}
|
|
22
|
+
declare function useTimeFormat(options: UseTimeFormatOptions): React__default.RefCallback<HTMLInputElement>;
|
|
23
|
+
|
|
24
|
+
declare function formatTime(input: string | number, options?: TimeFormatOptions): string;
|
|
25
|
+
|
|
26
|
+
declare function parseTime(formatted: string, options?: TimeFormatOptions): TimeFormatValues;
|
|
27
|
+
|
|
28
|
+
export { TimeFormat, type TimeFormatOptions, type TimeFormatProps, type TimeFormatValues, type UseTimeFormatOptions, formatTime, parseTime, useTimeFormat };
|
package/dist/time.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isInputFocused,
|
|
3
|
+
setInputSelection,
|
|
4
|
+
setNativeValue
|
|
5
|
+
} from "./chunk-CEZXZ7IJ.js";
|
|
6
|
+
|
|
7
|
+
// src/time/time-format.tsx
|
|
8
|
+
import React, { forwardRef, useLayoutEffect, useReducer, useRef } from "react";
|
|
9
|
+
|
|
10
|
+
// src/time/format-time.ts
|
|
11
|
+
function tokenizeTime(raw) {
|
|
12
|
+
const digits = String(raw != null ? raw : "").replace(/\D/g, "").slice(0, 4);
|
|
13
|
+
let hours = digits.slice(0, 2);
|
|
14
|
+
let minutes = digits.slice(2, 4);
|
|
15
|
+
if (hours.length === 2) {
|
|
16
|
+
hours = String(Math.min(parseInt(hours, 10), 23)).padStart(2, "0");
|
|
17
|
+
}
|
|
18
|
+
if (minutes.length === 2) {
|
|
19
|
+
minutes = String(Math.min(parseInt(minutes, 10), 59)).padStart(2, "0");
|
|
20
|
+
}
|
|
21
|
+
return { hours, minutes };
|
|
22
|
+
}
|
|
23
|
+
function buildFormatted(parts, separator) {
|
|
24
|
+
const { hours, minutes } = parts;
|
|
25
|
+
if (hours === "") return "";
|
|
26
|
+
if (hours.length < 2) return hours;
|
|
27
|
+
if (minutes === "") return hours + separator;
|
|
28
|
+
return hours + separator + minutes;
|
|
29
|
+
}
|
|
30
|
+
function formatTime(input, options) {
|
|
31
|
+
var _a;
|
|
32
|
+
const separator = (_a = options == null ? void 0 : options.separator) != null ? _a : ":";
|
|
33
|
+
return buildFormatted(tokenizeTime(input), separator);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/time/parse-time.ts
|
|
37
|
+
function collapseTrailingSeparator(raw, previous, separator) {
|
|
38
|
+
return previous.endsWith(separator) && raw === previous.slice(0, -separator.length) ? raw.slice(0, -1) : raw;
|
|
39
|
+
}
|
|
40
|
+
function parseTime(formatted, options) {
|
|
41
|
+
var _a;
|
|
42
|
+
const separator = (_a = options == null ? void 0 : options.separator) != null ? _a : ":";
|
|
43
|
+
const parts = tokenizeTime(formatted);
|
|
44
|
+
const formattedValue = buildFormatted(parts, separator);
|
|
45
|
+
const hours = parts.hours.length === 2 ? parseInt(parts.hours, 10) : void 0;
|
|
46
|
+
const minutes = parts.minutes.length === 2 ? parseInt(parts.minutes, 10) : void 0;
|
|
47
|
+
const value = hours !== void 0 && minutes !== void 0 ? `${parts.hours}:${parts.minutes}` : "";
|
|
48
|
+
return { value, formattedValue, hours, minutes };
|
|
49
|
+
}
|
|
50
|
+
function digitsBeforeCaret(value, caret) {
|
|
51
|
+
let count = 0;
|
|
52
|
+
for (let i = 0; i < caret && i < value.length; i++) {
|
|
53
|
+
if (value[i] >= "0" && value[i] <= "9") count++;
|
|
54
|
+
}
|
|
55
|
+
return count;
|
|
56
|
+
}
|
|
57
|
+
function caretAfterDigits(formatted, digitsBefore) {
|
|
58
|
+
if (digitsBefore <= 0) {
|
|
59
|
+
const first = formatted.search(/\d/);
|
|
60
|
+
return first === -1 ? formatted.length : first;
|
|
61
|
+
}
|
|
62
|
+
let seen = 0;
|
|
63
|
+
for (let i = 0; i < formatted.length; i++) {
|
|
64
|
+
if (formatted[i] >= "0" && formatted[i] <= "9") {
|
|
65
|
+
seen++;
|
|
66
|
+
if (seen === digitsBefore) return i + 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return formatted.length;
|
|
70
|
+
}
|
|
71
|
+
function resolveCaret(values, digitsBefore, options) {
|
|
72
|
+
var _a;
|
|
73
|
+
const separator = (_a = options == null ? void 0 : options.separator) != null ? _a : ":";
|
|
74
|
+
const caret = caretAfterDigits(values.formattedValue, digitsBefore);
|
|
75
|
+
if (separator && values.formattedValue.slice(caret, caret + separator.length) === separator) {
|
|
76
|
+
return caret + separator.length;
|
|
77
|
+
}
|
|
78
|
+
return caret;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/time/time-format.tsx
|
|
82
|
+
var TimeFormat = forwardRef(function TimeFormat2(props, forwardedRef) {
|
|
83
|
+
const { value = "", onValueChange, separator, ...domProps } = props;
|
|
84
|
+
const options = { separator };
|
|
85
|
+
const innerRef = useRef(null);
|
|
86
|
+
const caretRef = useRef(null);
|
|
87
|
+
const lastValuesRef = useRef(null);
|
|
88
|
+
const [, forceUpdate] = useReducer((n) => n + 1, 0);
|
|
89
|
+
const last = lastValuesRef.current;
|
|
90
|
+
const formatted = last !== null && (value === last.value || value === last.formattedValue) ? last.formattedValue : formatTime(value != null ? value : "", options);
|
|
91
|
+
function handleChange(event) {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
const el = event.target;
|
|
94
|
+
const caret = (_a = el.selectionStart) != null ? _a : el.value.length;
|
|
95
|
+
const raw = collapseTrailingSeparator(el.value, formatted, (_b = options.separator) != null ? _b : ":");
|
|
96
|
+
const digits = digitsBeforeCaret(raw, caret);
|
|
97
|
+
const values = parseTime(raw, options);
|
|
98
|
+
caretRef.current = resolveCaret(values, digits, options);
|
|
99
|
+
lastValuesRef.current = values;
|
|
100
|
+
forceUpdate();
|
|
101
|
+
onValueChange == null ? void 0 : onValueChange(values);
|
|
102
|
+
}
|
|
103
|
+
useLayoutEffect(() => {
|
|
104
|
+
const el = innerRef.current;
|
|
105
|
+
if (el && caretRef.current !== null && isInputFocused(el)) {
|
|
106
|
+
setInputSelection(el, caretRef.current, caretRef.current);
|
|
107
|
+
caretRef.current = null;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
function setRef(el) {
|
|
111
|
+
innerRef.current = el;
|
|
112
|
+
if (typeof forwardedRef === "function") forwardedRef(el);
|
|
113
|
+
else if (forwardedRef)
|
|
114
|
+
forwardedRef.current = el;
|
|
115
|
+
}
|
|
116
|
+
return /* @__PURE__ */ React.createElement("input", { ...domProps, ref: setRef, value: formatted, onChange: handleChange });
|
|
117
|
+
});
|
|
118
|
+
TimeFormat.displayName = "TimeFormat";
|
|
119
|
+
|
|
120
|
+
// src/time/use-time-format.ts
|
|
121
|
+
import { useRef as useRef2, useCallback } from "react";
|
|
122
|
+
var IS_JSDOM = typeof navigator !== "undefined" && navigator.userAgent.includes("jsdom");
|
|
123
|
+
function useTimeFormat(options) {
|
|
124
|
+
const optionsRef = useRef2(options);
|
|
125
|
+
optionsRef.current = options;
|
|
126
|
+
const inputRef = useRef2(null);
|
|
127
|
+
const handlerRef = useRef2(null);
|
|
128
|
+
return useCallback((el) => {
|
|
129
|
+
if (el) {
|
|
130
|
+
let previous = el.value;
|
|
131
|
+
const handler = () => {
|
|
132
|
+
var _a, _b, _c;
|
|
133
|
+
const opts = optionsRef.current;
|
|
134
|
+
const caret = (_a = el.selectionStart) != null ? _a : el.value.length;
|
|
135
|
+
const raw = collapseTrailingSeparator(el.value, previous, (_b = opts.separator) != null ? _b : ":");
|
|
136
|
+
const digits = digitsBeforeCaret(raw, caret);
|
|
137
|
+
const values = parseTime(raw, opts);
|
|
138
|
+
setNativeValue(el, values.formattedValue);
|
|
139
|
+
previous = values.formattedValue;
|
|
140
|
+
if (isInputFocused(el)) {
|
|
141
|
+
const next = resolveCaret(values, digits, opts);
|
|
142
|
+
setInputSelection(el, next, next);
|
|
143
|
+
}
|
|
144
|
+
if (IS_JSDOM) {
|
|
145
|
+
queueMicrotask(() => {
|
|
146
|
+
if (el.value !== values.formattedValue) return;
|
|
147
|
+
el.value = values.formattedValue;
|
|
148
|
+
if (isInputFocused(el)) {
|
|
149
|
+
const c = resolveCaret(values, digits, opts);
|
|
150
|
+
setInputSelection(el, c, c);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
(_c = opts.onValueChange) == null ? void 0 : _c.call(opts, values);
|
|
155
|
+
};
|
|
156
|
+
el.addEventListener("input", handler);
|
|
157
|
+
handlerRef.current = handler;
|
|
158
|
+
inputRef.current = el;
|
|
159
|
+
if (el.value) {
|
|
160
|
+
setNativeValue(el, formatTime(el.value, optionsRef.current));
|
|
161
|
+
previous = formatTime(el.value, optionsRef.current);
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
if (inputRef.current && handlerRef.current) {
|
|
165
|
+
inputRef.current.removeEventListener("input", handlerRef.current);
|
|
166
|
+
}
|
|
167
|
+
inputRef.current = null;
|
|
168
|
+
handlerRef.current = null;
|
|
169
|
+
}
|
|
170
|
+
}, []);
|
|
171
|
+
}
|
|
172
|
+
export {
|
|
173
|
+
TimeFormat,
|
|
174
|
+
formatTime,
|
|
175
|
+
parseTime,
|
|
176
|
+
useTimeFormat
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=time.js.map
|
package/dist/time.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/time/time-format.tsx","../src/time/format-time.ts","../src/time/parse-time.ts","../src/time/use-time-format.ts"],"sourcesContent":["import React, { forwardRef, useLayoutEffect, useReducer, useRef } from \"react\";\nimport type { TimeFormatOptions, TimeFormatValues } from \"./types\";\nimport { formatTime } from \"./format-time\";\nimport {\n collapseTrailingSeparator,\n parseTime,\n digitsBeforeCaret,\n resolveCaret,\n} from \"./parse-time\";\nimport { isInputFocused, setInputSelection } from \"../utils/input\";\n\nexport interface TimeFormatProps\n extends TimeFormatOptions,\n Omit<React.InputHTMLAttributes<HTMLInputElement>, \"value\" | \"onChange\"> {\n value?: string;\n onValueChange?: (values: TimeFormatValues) => void;\n}\n\nexport const TimeFormat = forwardRef<HTMLInputElement, TimeFormatProps>(function TimeFormat(\n props,\n forwardedRef\n) {\n const { value = \"\", onValueChange, separator, ...domProps } = props;\n const options: TimeFormatOptions = { separator };\n\n const innerRef = useRef<HTMLInputElement | null>(null);\n const caretRef = useRef<number | null>(null);\n const lastValuesRef = useRef<TimeFormatValues | null>(null);\n\n const [, forceUpdate] = useReducer((n: number) => n + 1, 0);\n\n const last = lastValuesRef.current;\n const formatted =\n last !== null && (value === last.value || value === last.formattedValue)\n ? last.formattedValue\n : formatTime(value ?? \"\", options);\n\n function handleChange(event: React.ChangeEvent<HTMLInputElement>): void {\n const el = event.target;\n const caret = el.selectionStart ?? el.value.length;\n const raw = collapseTrailingSeparator(el.value, formatted, options.separator ?? \":\");\n const digits = digitsBeforeCaret(raw, caret);\n const values = parseTime(raw, options);\n caretRef.current = resolveCaret(values, digits, options);\n lastValuesRef.current = values;\n forceUpdate();\n onValueChange?.(values);\n }\n\n useLayoutEffect(() => {\n const el = innerRef.current;\n if (el && caretRef.current !== null && isInputFocused(el)) {\n setInputSelection(el, caretRef.current, caretRef.current);\n caretRef.current = null;\n }\n });\n\n function setRef(el: HTMLInputElement | null): void {\n innerRef.current = el;\n if (typeof forwardedRef === \"function\") forwardedRef(el);\n else if (forwardedRef)\n (forwardedRef as React.MutableRefObject<HTMLInputElement | null>).current = el;\n }\n\n return <input {...domProps} ref={setRef} value={formatted} onChange={handleChange} />;\n});\n\nTimeFormat.displayName = \"TimeFormat\";\n","import type { TimeFormatOptions } from \"./types\";\n\nexport interface TimeParts {\n hours: string;\n minutes: string;\n}\n\nexport function tokenizeTime(raw: string | number): TimeParts {\n const digits = String(raw ?? \"\").replace(/\\D/g, \"\").slice(0, 4);\n let hours = digits.slice(0, 2);\n let minutes = digits.slice(2, 4);\n if (hours.length === 2) {\n hours = String(Math.min(parseInt(hours, 10), 23)).padStart(2, \"0\");\n }\n if (minutes.length === 2) {\n minutes = String(Math.min(parseInt(minutes, 10), 59)).padStart(2, \"0\");\n }\n return { hours, minutes };\n}\n\nexport function buildFormatted(parts: TimeParts, separator: string): string {\n const { hours, minutes } = parts;\n if (hours === \"\") return \"\";\n if (hours.length < 2) return hours;\n if (minutes === \"\") return hours + separator;\n return hours + separator + minutes;\n}\n\nexport function formatTime(input: string | number, options?: TimeFormatOptions): string {\n const separator = options?.separator ?? \":\";\n return buildFormatted(tokenizeTime(input), separator);\n}\n","import type { TimeFormatOptions, TimeFormatValues } from \"./types\";\nimport { tokenizeTime, buildFormatted } from \"./format-time\";\n\nexport function collapseTrailingSeparator(\n raw: string,\n previous: string,\n separator: string\n): string {\n return previous.endsWith(separator) && raw === previous.slice(0, -separator.length)\n ? raw.slice(0, -1)\n : raw;\n}\n\nexport function parseTime(formatted: string, options?: TimeFormatOptions): TimeFormatValues {\n const separator = options?.separator ?? \":\";\n const parts = tokenizeTime(formatted);\n const formattedValue = buildFormatted(parts, separator);\n const hours = parts.hours.length === 2 ? parseInt(parts.hours, 10) : undefined;\n const minutes = parts.minutes.length === 2 ? parseInt(parts.minutes, 10) : undefined;\n const value =\n hours !== undefined && minutes !== undefined ? `${parts.hours}:${parts.minutes}` : \"\";\n return { value, formattedValue, hours, minutes };\n}\n\nexport function digitsBeforeCaret(value: string, caret: number): number {\n let count = 0;\n for (let i = 0; i < caret && i < value.length; i++) {\n if (value[i] >= \"0\" && value[i] <= \"9\") count++;\n }\n return count;\n}\n\nfunction caretAfterDigits(formatted: string, digitsBefore: number): number {\n if (digitsBefore <= 0) {\n const first = formatted.search(/\\d/);\n return first === -1 ? formatted.length : first;\n }\n let seen = 0;\n for (let i = 0; i < formatted.length; i++) {\n if (formatted[i] >= \"0\" && formatted[i] <= \"9\") {\n seen++;\n if (seen === digitsBefore) return i + 1;\n }\n }\n return formatted.length;\n}\n\nexport function resolveCaret(\n values: TimeFormatValues,\n digitsBefore: number,\n options?: TimeFormatOptions\n): number {\n const separator = options?.separator ?? \":\";\n const caret = caretAfterDigits(values.formattedValue, digitsBefore);\n if (separator && values.formattedValue.slice(caret, caret + separator.length) === separator) {\n return caret + separator.length;\n }\n return caret;\n}\n","import { useRef, useCallback } from \"react\";\nimport type React from \"react\";\nimport type { TimeFormatValues } from \"./types\";\nimport type { TimeFormatOptions } from \"./types\";\nimport { formatTime } from \"./format-time\";\nimport {\n collapseTrailingSeparator,\n parseTime,\n digitsBeforeCaret,\n resolveCaret,\n} from \"./parse-time\";\nimport { setNativeValue } from \"../set-native-value\";\nimport { isInputFocused, setInputSelection } from \"../utils/input\";\n\nexport interface UseTimeFormatOptions extends TimeFormatOptions {\n onValueChange?: (values: TimeFormatValues) => void;\n}\n\nconst IS_JSDOM =\n typeof navigator !== \"undefined\" && navigator.userAgent.includes(\"jsdom\");\n\nexport function useTimeFormat(\n options: UseTimeFormatOptions\n): React.RefCallback<HTMLInputElement> {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const handlerRef = useRef<((event: Event) => void) | null>(null);\n\n return useCallback((el: HTMLInputElement | null) => {\n if (el) {\n let previous = el.value;\n const handler = (): void => {\n const opts = optionsRef.current;\n const caret = el.selectionStart ?? el.value.length;\n const raw = collapseTrailingSeparator(el.value, previous, opts.separator ?? \":\");\n const digits = digitsBeforeCaret(raw, caret);\n const values = parseTime(raw, opts);\n setNativeValue(el, values.formattedValue);\n previous = values.formattedValue;\n if (isInputFocused(el)) {\n const next = resolveCaret(values, digits, opts);\n setInputSelection(el, next, next);\n }\n // JSDOM-ONLY: resync @testing-library/user-event v14's shadow-value cache.\n // setNativeValue above bypasses React's value tracker; under jsdom that\n // leaves user-event's per-input shadow value stale, corrupting masking from\n // ~the 4th keystroke. A plain (idempotent) reassignment resyncs it.\n // MUST NOT run in a real browser: there, microtasks drain BETWEEN event\n // listeners, so this write would fight React; real browsers read the live\n // DOM and need no resync. onValueChange (below) is called directly, not via\n // React's tracker, so it is unaffected in either environment.\n if (IS_JSDOM) {\n queueMicrotask(() => {\n if (el.value !== values.formattedValue) return;\n el.value = values.formattedValue;\n if (isInputFocused(el)) {\n const c = resolveCaret(values, digits, opts);\n setInputSelection(el, c, c);\n }\n });\n }\n opts.onValueChange?.(values);\n };\n el.addEventListener(\"input\", handler);\n handlerRef.current = handler;\n inputRef.current = el;\n if (el.value) {\n setNativeValue(el, formatTime(el.value, optionsRef.current));\n previous = formatTime(el.value, optionsRef.current);\n }\n } else {\n if (inputRef.current && handlerRef.current) {\n inputRef.current.removeEventListener(\"input\", handlerRef.current);\n }\n inputRef.current = null;\n handlerRef.current = null;\n }\n }, []);\n}\n"],"mappings":"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","names":["TimeFormat","useRef","useRef"]}
|
|
@@ -57,5 +57,21 @@ interface InputMaskProps extends Omit<React.InputHTMLAttributes<HTMLInputElement
|
|
|
57
57
|
/** @deprecated Use beforeMaskedStateChange. */
|
|
58
58
|
beforeMaskedValueChange?: BeforeMaskedValueChangeFn;
|
|
59
59
|
}
|
|
60
|
+
interface UseMaskOptions {
|
|
61
|
+
/** Mask format — same grammar as InputMask's `mask`. */
|
|
62
|
+
mask?: Mask | null;
|
|
63
|
+
/** Character(s) to cover unfilled parts. Default "_", null — empty. */
|
|
64
|
+
maskPlaceholder?: string | null;
|
|
65
|
+
/** Show mask even when input is empty and unfocused. */
|
|
66
|
+
alwaysShowMask?: boolean;
|
|
67
|
+
/** Map of custom mask tokens to character classes. Prefer RegExp values. */
|
|
68
|
+
formatChars?: Record<string, RegExp | string>;
|
|
69
|
+
/** Normalize each entered character. Must be pure. */
|
|
70
|
+
transform?: Transform;
|
|
71
|
+
/** Modify masked value and cursor position before they are applied. */
|
|
72
|
+
beforeMaskedStateChange?: BeforeMaskedStateChangeFn;
|
|
73
|
+
/** @deprecated Use beforeMaskedStateChange. */
|
|
74
|
+
beforeMaskedValueChange?: BeforeMaskedValueChangeFn;
|
|
75
|
+
}
|
|
60
76
|
|
|
61
|
-
export type { BeforeMaskedStateChangeFn as B, FormatChars as F, InputMaskProps as I, Mask as M, Selection as S, Transform as T, BeforeMaskedValueChangeFn as a, InputState as b };
|
|
77
|
+
export type { BeforeMaskedStateChangeFn as B, FormatChars as F, InputMaskProps as I, Mask as M, Selection as S, Transform as T, UseMaskOptions as U, BeforeMaskedValueChangeFn as a, InputState as b };
|
|
@@ -57,5 +57,21 @@ interface InputMaskProps extends Omit<React.InputHTMLAttributes<HTMLInputElement
|
|
|
57
57
|
/** @deprecated Use beforeMaskedStateChange. */
|
|
58
58
|
beforeMaskedValueChange?: BeforeMaskedValueChangeFn;
|
|
59
59
|
}
|
|
60
|
+
interface UseMaskOptions {
|
|
61
|
+
/** Mask format — same grammar as InputMask's `mask`. */
|
|
62
|
+
mask?: Mask | null;
|
|
63
|
+
/** Character(s) to cover unfilled parts. Default "_", null — empty. */
|
|
64
|
+
maskPlaceholder?: string | null;
|
|
65
|
+
/** Show mask even when input is empty and unfocused. */
|
|
66
|
+
alwaysShowMask?: boolean;
|
|
67
|
+
/** Map of custom mask tokens to character classes. Prefer RegExp values. */
|
|
68
|
+
formatChars?: Record<string, RegExp | string>;
|
|
69
|
+
/** Normalize each entered character. Must be pure. */
|
|
70
|
+
transform?: Transform;
|
|
71
|
+
/** Modify masked value and cursor position before they are applied. */
|
|
72
|
+
beforeMaskedStateChange?: BeforeMaskedStateChangeFn;
|
|
73
|
+
/** @deprecated Use beforeMaskedStateChange. */
|
|
74
|
+
beforeMaskedValueChange?: BeforeMaskedValueChangeFn;
|
|
75
|
+
}
|
|
60
76
|
|
|
61
|
-
export type { BeforeMaskedStateChangeFn as B, FormatChars as F, InputMaskProps as I, Mask as M, Selection as S, Transform as T, BeforeMaskedValueChangeFn as a, InputState as b };
|
|
77
|
+
export type { BeforeMaskedStateChangeFn as B, FormatChars as F, InputMaskProps as I, Mask as M, Selection as S, Transform as T, UseMaskOptions as U, BeforeMaskedValueChangeFn as a, InputState as b };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-input-mask-format",
|
|
3
3
|
"description": "Masked input component for React",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"homepage": "https://github.com/Temirtator/react-input-mask-format",
|
|
7
7
|
"license": "MIT",
|
|
@@ -58,6 +58,14 @@
|
|
|
58
58
|
"import": { "types": "./dist/validators.d.ts", "default": "./dist/validators.js" },
|
|
59
59
|
"require": { "types": "./dist/validators.d.cts", "default": "./dist/validators.cjs" }
|
|
60
60
|
},
|
|
61
|
+
"./number": {
|
|
62
|
+
"import": { "types": "./dist/number.d.ts", "default": "./dist/number.js" },
|
|
63
|
+
"require": { "types": "./dist/number.d.cts", "default": "./dist/number.cjs" }
|
|
64
|
+
},
|
|
65
|
+
"./time": {
|
|
66
|
+
"import": { "types": "./dist/time.d.ts", "default": "./dist/time.js" },
|
|
67
|
+
"require": { "types": "./dist/time.d.cts", "default": "./dist/time.cjs" }
|
|
68
|
+
},
|
|
61
69
|
"./package.json": "./package.json"
|
|
62
70
|
},
|
|
63
71
|
"sideEffects": false,
|
|
@@ -67,7 +75,9 @@
|
|
|
67
75
|
"size-limit": [
|
|
68
76
|
{ "path": "dist/index.js", "limit": "6 KB" },
|
|
69
77
|
{ "path": "dist/presets.js", "limit": "2 KB" },
|
|
70
|
-
{ "path": "dist/validators.js", "limit": "2 KB" }
|
|
78
|
+
{ "path": "dist/validators.js", "limit": "2 KB" },
|
|
79
|
+
{ "path": "dist/number.js", "limit": "2.5 KB" },
|
|
80
|
+
{ "path": "dist/time.js", "limit": "2 KB" }
|
|
71
81
|
],
|
|
72
82
|
"scripts": {
|
|
73
83
|
"build": "tsup",
|