@sdata/web-vue 3.27.0 → 3.28.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.
Files changed (37) hide show
  1. package/dist/sd.css +4 -0
  2. package/dist/sd.min.css +1 -1
  3. package/es/_utils/grapheme.d.ts +5 -0
  4. package/es/_utils/grapheme.js +93 -0
  5. package/es/basic-crud-table/basic-crud-table.vue_vue_type_script_setup_true_lang.js +33 -23
  6. package/es/basic-crud-table/index.d.ts +1 -1
  7. package/es/basic-crud-table/types.d.ts +9 -1
  8. package/es/components.d.ts +1 -0
  9. package/es/index.css +4 -0
  10. package/es/index.d.ts +3 -0
  11. package/es/index.js +4 -1
  12. package/es/index.scss +1 -0
  13. package/es/input/input.js +5 -6
  14. package/es/input-mask/index.d.ts +120 -0
  15. package/es/input-mask/index.js +12 -0
  16. package/es/input-mask/input-mask.js +5 -0
  17. package/es/input-mask/input-mask.vue.d.ts +49 -0
  18. package/es/input-mask/input-mask.vue_vue_type_script_setup_true_lang.js +346 -0
  19. package/es/input-mask/mask-engine.d.ts +18 -0
  20. package/es/input-mask/mask-engine.js +176 -0
  21. package/es/input-mask/presets.d.ts +2 -0
  22. package/es/input-mask/presets.js +220 -0
  23. package/es/input-mask/style/css.js +1 -0
  24. package/es/input-mask/style/index.css +20 -0
  25. package/es/input-mask/style/index.d.ts +2 -0
  26. package/es/input-mask/style/index.js +1 -0
  27. package/es/input-mask/style/index.scss +10 -0
  28. package/es/input-mask/style/token.scss +5 -0
  29. package/es/input-mask/types.d.ts +49 -0
  30. package/es/sd-vue.js +2 -0
  31. package/es/textarea/textarea.vue_vue_type_script_setup_true_lang.js +5 -6
  32. package/es/toolbar/toolbar.vue_vue_type_script_setup_true_lang.js +8 -10
  33. package/es/toolbar/types.d.ts +3 -0
  34. package/json/vetur-attributes.json +6 -0
  35. package/json/vetur-tags.json +5 -0
  36. package/json/web-types.json +23 -1
  37. package/package.json +1 -1
@@ -0,0 +1,346 @@
1
+ import _objectSpread2 from "../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/objectSpread2.js";
2
+ import { getPrefixCls } from "../_utils/global-config.js";
3
+ import Input from "../input/index.js";
4
+ import { formatInputMask, resolveDeletion } from "./mask-engine.js";
5
+ import { inputMaskPresets } from "./presets.js";
6
+ import { computed, createBlock, createSlots, defineComponent, mergeProps, nextTick, onBeforeUnmount, onMounted, openBlock, ref, renderSlot, unref, useAttrs, watch, withCtx } from "vue";
7
+ //#region components/input-mask/input-mask.vue?vue&type=script&setup=true&lang.ts
8
+ var input_mask_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent(_objectSpread2(_objectSpread2({}, {
9
+ name: "InputMask",
10
+ inheritAttrs: false
11
+ }), {}, {
12
+ __name: "input-mask",
13
+ props: {
14
+ modelValue: {},
15
+ defaultValue: { default: "" },
16
+ mask: {},
17
+ preset: {},
18
+ maskChar: { default: "_" },
19
+ formatChars: {},
20
+ alwaysShowMask: {
21
+ type: Boolean,
22
+ default: false
23
+ },
24
+ beforeMaskedValueChange: {},
25
+ size: {},
26
+ allowClear: {
27
+ type: Boolean,
28
+ default: false
29
+ },
30
+ disabled: {
31
+ type: Boolean,
32
+ default: false
33
+ },
34
+ readonly: {
35
+ type: [Boolean, String],
36
+ default: false
37
+ },
38
+ error: {
39
+ type: Boolean,
40
+ default: false
41
+ },
42
+ placeholder: {},
43
+ fitWidth: {
44
+ type: Boolean,
45
+ default: false
46
+ },
47
+ maxWFull: {
48
+ type: Boolean,
49
+ default: true
50
+ },
51
+ showWordLimit: {
52
+ type: Boolean,
53
+ default: false
54
+ },
55
+ maxLength: {},
56
+ wordLength: {},
57
+ wordSlice: {},
58
+ inputAttrs: {},
59
+ prepend: {},
60
+ append: {}
61
+ },
62
+ emits: [
63
+ "update:modelValue",
64
+ "input",
65
+ "change",
66
+ "complete",
67
+ "pressEnter",
68
+ "clear",
69
+ "focus",
70
+ "blur"
71
+ ],
72
+ setup(__props, { expose: __expose, emit: __emit }) {
73
+ var _props$modelValue;
74
+ const props = __props;
75
+ const emit = __emit;
76
+ const attrs = useAttrs();
77
+ const prefixCls = getPrefixCls("input-mask");
78
+ const inputComponentRef = ref();
79
+ const focused = ref(false);
80
+ const lastSelection = ref(null);
81
+ const complete = ref(false);
82
+ const presetDefinition = computed(() => props.preset ? inputMaskPresets[props.preset] : void 0);
83
+ const effectiveMask = computed(() => {
84
+ var _props$mask, _presetDefinition$val;
85
+ return (_props$mask = props.mask) !== null && _props$mask !== void 0 ? _props$mask : (_presetDefinition$val = presetDefinition.value) === null || _presetDefinition$val === void 0 ? void 0 : _presetDefinition$val.mask;
86
+ });
87
+ const effectiveFormatChars = computed(() => {
88
+ var _presetDefinition$val2;
89
+ return _objectSpread2(_objectSpread2({}, (_presetDefinition$val2 = presetDefinition.value) === null || _presetDefinition$val2 === void 0 ? void 0 : _presetDefinition$val2.formatChars), props.formatChars);
90
+ });
91
+ const effectiveMaskChar = computed(() => {
92
+ var _Array$from$;
93
+ if (props.maskChar === null) return null;
94
+ return (_Array$from$ = Array.from(props.maskChar)[0]) !== null && _Array$from$ !== void 0 ? _Array$from$ : "_";
95
+ });
96
+ const lengthManaged = computed(() => Boolean(effectiveMask.value) || Boolean(props.preset));
97
+ const normalizePresetValue = (value, previousValue) => {
98
+ var _preset$normalize, _preset$normalize2, _preset$accepts;
99
+ const preset = presetDefinition.value;
100
+ if (!preset || effectiveMask.value) return value;
101
+ const normalized = (_preset$normalize = (_preset$normalize2 = preset.normalize) === null || _preset$normalize2 === void 0 ? void 0 : _preset$normalize2.call(preset, value)) !== null && _preset$normalize !== void 0 ? _preset$normalize : value;
102
+ return ((_preset$accepts = preset.accepts) === null || _preset$accepts === void 0 ? void 0 : _preset$accepts.call(preset, normalized)) === false ? previousValue : normalized;
103
+ };
104
+ const applyNormalization = (value) => {
105
+ if (effectiveMask.value) {
106
+ const result = formatInputMask(value, null, effectiveMask.value, {
107
+ maskChar: effectiveMaskChar.value,
108
+ showMask: Boolean(value),
109
+ formatChars: effectiveFormatChars.value
110
+ });
111
+ return {
112
+ value: result.value,
113
+ complete: result.complete
114
+ };
115
+ }
116
+ return {
117
+ value: normalizePresetValue(value, ""),
118
+ complete: false
119
+ };
120
+ };
121
+ const normalizeStoredValue = (value) => applyNormalization(value).value;
122
+ const innerValue = ref(normalizeStoredValue((_props$modelValue = props.modelValue) !== null && _props$modelValue !== void 0 ? _props$modelValue : props.defaultValue));
123
+ const displayValue = computed(() => {
124
+ if (!effectiveMask.value) return innerValue.value;
125
+ return formatInputMask(innerValue.value, null, effectiveMask.value, {
126
+ maskChar: effectiveMaskChar.value,
127
+ showMask: focused.value || props.alwaysShowMask || Boolean(innerValue.value),
128
+ formatChars: effectiveFormatChars.value
129
+ }).value;
130
+ });
131
+ const mergedPlaceholder = computed(() => {
132
+ var _props$placeholder, _presetDefinition$val3;
133
+ return (_props$placeholder = props.placeholder) !== null && _props$placeholder !== void 0 ? _props$placeholder : (_presetDefinition$val3 = presetDefinition.value) === null || _presetDefinition$val3 === void 0 ? void 0 : _presetDefinition$val3.placeholder;
134
+ });
135
+ const mergedInputAttrs = computed(() => {
136
+ var _presetDefinition$val4;
137
+ const result = _objectSpread2({}, props.inputAttrs);
138
+ if (result.inputmode === void 0 && ((_presetDefinition$val4 = presetDefinition.value) === null || _presetDefinition$val4 === void 0 ? void 0 : _presetDefinition$val4.inputMode)) result.inputmode = presetDefinition.value.inputMode;
139
+ if (props.preset) result["data-mask-preset"] = props.preset;
140
+ return result;
141
+ });
142
+ const forwardedAttrs = computed(() => _objectSpread2(_objectSpread2({}, attrs), {}, { class: [prefixCls, attrs.class] }));
143
+ const getInputElement = () => {
144
+ var _inputComponentRef$va;
145
+ return (_inputComponentRef$va = inputComponentRef.value) === null || _inputComponentRef$va === void 0 ? void 0 : _inputComponentRef$va.inputRef;
146
+ };
147
+ const syncComplete = (value, nextComplete) => {
148
+ if (nextComplete && !complete.value) emit("complete", value);
149
+ complete.value = nextComplete;
150
+ };
151
+ const commitValue = (rawValue) => {
152
+ var _input$selectionStart, _props$beforeMaskedVa, _props$beforeMaskedVa2;
153
+ const input = getInputElement();
154
+ const rawCursor = (_input$selectionStart = input === null || input === void 0 ? void 0 : input.selectionStart) !== null && _input$selectionStart !== void 0 ? _input$selectionStart : rawValue.length;
155
+ const previousState = {
156
+ value: innerValue.value,
157
+ selection: lastSelection.value
158
+ };
159
+ let nextState;
160
+ let nextComplete = false;
161
+ if (effectiveMask.value) {
162
+ const deletion = lastSelection.value ? resolveDeletion(innerValue.value, lastSelection.value, rawValue, rawCursor, effectiveMask.value, effectiveFormatChars.value, effectiveMaskChar.value) : null;
163
+ if (deletion) {
164
+ nextState = {
165
+ value: deletion.value,
166
+ selection: {
167
+ start: deletion.cursor,
168
+ end: deletion.cursor
169
+ }
170
+ };
171
+ nextComplete = deletion.complete;
172
+ } else {
173
+ const result = formatInputMask(rawValue, rawCursor, effectiveMask.value, {
174
+ maskChar: effectiveMaskChar.value,
175
+ showMask: focused.value || props.alwaysShowMask || Boolean(rawValue),
176
+ formatChars: effectiveFormatChars.value
177
+ });
178
+ nextState = {
179
+ value: result.value,
180
+ selection: result.selection
181
+ };
182
+ nextComplete = result.complete;
183
+ }
184
+ } else {
185
+ const value = normalizePresetValue(rawValue, innerValue.value);
186
+ const cursor = rawCursor === rawValue.length ? value.length : Math.min(rawCursor, value.length);
187
+ nextState = {
188
+ value,
189
+ selection: {
190
+ start: cursor,
191
+ end: cursor
192
+ }
193
+ };
194
+ }
195
+ nextState = (_props$beforeMaskedVa = (_props$beforeMaskedVa2 = props.beforeMaskedValueChange) === null || _props$beforeMaskedVa2 === void 0 ? void 0 : _props$beforeMaskedVa2.call(props, nextState, previousState)) !== null && _props$beforeMaskedVa !== void 0 ? _props$beforeMaskedVa : nextState;
196
+ innerValue.value = nextState.value;
197
+ lastSelection.value = nextState.selection;
198
+ emit("update:modelValue", nextState.value);
199
+ syncComplete(nextState.value, nextComplete);
200
+ nextTick(() => {
201
+ const element = getInputElement();
202
+ if (focused.value && element && nextState.selection) element.setSelectionRange(nextState.selection.start, nextState.selection.end);
203
+ });
204
+ };
205
+ const handleModelUpdate = (value) => commitValue(value);
206
+ const handleInput = (_value, event) => emit("input", innerValue.value, event);
207
+ const handleChange = (_value, event) => emit("change", innerValue.value, event);
208
+ const handlePressEnter = (event) => emit("pressEnter", event);
209
+ const handleClear = (event) => emit("clear", event);
210
+ const handleFocus = (event) => {
211
+ focused.value = true;
212
+ emit("focus", event);
213
+ };
214
+ const handleBlur = (event) => {
215
+ focused.value = false;
216
+ emit("blur", event);
217
+ };
218
+ const trackedEvents = [
219
+ "keyup",
220
+ "mouseup",
221
+ "select"
222
+ ];
223
+ const updateSelectionFromDom = () => {
224
+ const el = getInputElement();
225
+ if (!el || document.activeElement !== el) return;
226
+ const start = el.selectionStart;
227
+ const end = el.selectionEnd;
228
+ if (start !== null && end !== null) lastSelection.value = {
229
+ start,
230
+ end
231
+ };
232
+ };
233
+ onMounted(() => {
234
+ const input = getInputElement();
235
+ if (input) trackedEvents.forEach((event) => input.addEventListener(event, updateSelectionFromDom));
236
+ document.addEventListener("selectionchange", updateSelectionFromDom);
237
+ });
238
+ onBeforeUnmount(() => {
239
+ const input = getInputElement();
240
+ if (input) trackedEvents.forEach((event) => input.removeEventListener(event, updateSelectionFromDom));
241
+ document.removeEventListener("selectionchange", updateSelectionFromDom);
242
+ });
243
+ watch(() => props.modelValue, (value) => {
244
+ if (value === void 0) return;
245
+ const { value: next, complete: nextComplete } = applyNormalization(value !== null && value !== void 0 ? value : "");
246
+ innerValue.value = next;
247
+ if (next !== value) emit("update:modelValue", next);
248
+ syncComplete(next, nextComplete);
249
+ });
250
+ watch([
251
+ effectiveMask,
252
+ presetDefinition,
253
+ effectiveMaskChar,
254
+ effectiveFormatChars
255
+ ], () => {
256
+ const { value: next, complete: nextComplete } = applyNormalization(innerValue.value);
257
+ const changed = next !== innerValue.value;
258
+ innerValue.value = next;
259
+ if (changed) emit("update:modelValue", next);
260
+ syncComplete(next, nextComplete);
261
+ });
262
+ __expose({
263
+ get inputRef() {
264
+ return getInputElement();
265
+ },
266
+ focus: () => {
267
+ var _inputComponentRef$va2;
268
+ return (_inputComponentRef$va2 = inputComponentRef.value) === null || _inputComponentRef$va2 === void 0 ? void 0 : _inputComponentRef$va2.focus();
269
+ },
270
+ blur: () => {
271
+ var _inputComponentRef$va3;
272
+ return (_inputComponentRef$va3 = inputComponentRef.value) === null || _inputComponentRef$va3 === void 0 ? void 0 : _inputComponentRef$va3.blur();
273
+ }
274
+ });
275
+ return (_ctx, _cache) => {
276
+ return openBlock(), createBlock(unref(Input), mergeProps({
277
+ ref_key: "inputComponentRef",
278
+ ref: inputComponentRef
279
+ }, forwardedAttrs.value, {
280
+ "model-value": displayValue.value,
281
+ size: __props.size,
282
+ "allow-clear": __props.allowClear && Boolean(innerValue.value),
283
+ disabled: __props.disabled,
284
+ readonly: __props.readonly,
285
+ error: __props.error,
286
+ placeholder: mergedPlaceholder.value,
287
+ "fit-width": __props.fitWidth,
288
+ "max-w-full": __props.maxWFull,
289
+ "max-length": lengthManaged.value ? void 0 : __props.maxLength,
290
+ "show-word-limit": lengthManaged.value ? false : __props.showWordLimit,
291
+ "word-length": __props.wordLength,
292
+ "word-slice": __props.wordSlice,
293
+ "input-attrs": mergedInputAttrs.value,
294
+ prepend: __props.prepend,
295
+ append: __props.append,
296
+ "onUpdate:modelValue": handleModelUpdate,
297
+ onInput: handleInput,
298
+ onChange: handleChange,
299
+ onPressEnter: handlePressEnter,
300
+ onClear: handleClear,
301
+ onFocus: handleFocus,
302
+ onBlur: handleBlur
303
+ }), createSlots({ _: 2 }, [
304
+ _ctx.$slots.prefix ? {
305
+ name: "prefix",
306
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "prefix")]),
307
+ key: "0"
308
+ } : void 0,
309
+ _ctx.$slots.suffix ? {
310
+ name: "suffix",
311
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "suffix")]),
312
+ key: "1"
313
+ } : void 0,
314
+ _ctx.$slots.prepend ? {
315
+ name: "prepend",
316
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "prepend")]),
317
+ key: "2"
318
+ } : void 0,
319
+ _ctx.$slots.append ? {
320
+ name: "append",
321
+ fn: withCtx(() => [renderSlot(_ctx.$slots, "append")]),
322
+ key: "3"
323
+ } : void 0
324
+ ]), 1040, [
325
+ "model-value",
326
+ "size",
327
+ "allow-clear",
328
+ "disabled",
329
+ "readonly",
330
+ "error",
331
+ "placeholder",
332
+ "fit-width",
333
+ "max-w-full",
334
+ "max-length",
335
+ "show-word-limit",
336
+ "word-length",
337
+ "word-slice",
338
+ "input-attrs",
339
+ "prepend",
340
+ "append"
341
+ ]);
342
+ };
343
+ }
344
+ }));
345
+ //#endregion
346
+ export { input_mask_vue_vue_type_script_setup_true_lang_default as default };
@@ -0,0 +1,18 @@
1
+ import type { InputMaskPattern, InputMaskSelection } from './types';
2
+ export interface FormatMaskOptions {
3
+ maskChar: string | null;
4
+ showMask: boolean;
5
+ formatChars?: Readonly<Record<string, RegExp>>;
6
+ }
7
+ export interface FormatMaskResult {
8
+ value: string;
9
+ selection: InputMaskSelection;
10
+ complete: boolean;
11
+ }
12
+ export declare const defaultInputMaskFormatChars: Readonly<Record<string, RegExp>>;
13
+ export declare function formatInputMask(rawValue: string, rawCursor: number | null, mask: InputMaskPattern, options: FormatMaskOptions): FormatMaskResult;
14
+ export declare function resolveDeletion(previousValue: string, previousSelection: InputMaskSelection | null, rawValue: string, rawCursor: number, mask: InputMaskPattern, formatChars?: Readonly<Record<string, RegExp>>, maskChar?: string | null): {
15
+ value: string;
16
+ cursor: number;
17
+ complete: boolean;
18
+ } | null;
@@ -0,0 +1,176 @@
1
+ import _objectSpread2 from "../_virtual/_@oxc-project_runtime@0.139.0/helpers/esm/objectSpread2.js";
2
+ import { codeUnitToGraphemeIndex, graphemeIndexToCodeUnit, splitGraphemes } from "../_utils/grapheme.js";
3
+ //#region components/input-mask/mask-engine.ts
4
+ var defaultInputMaskFormatChars = {
5
+ "9": /[0-9]/,
6
+ "a": /[A-Za-z]/,
7
+ "*": /[A-Za-z0-9]/,
8
+ "H": /* @__PURE__ */ new RegExp("\\p{Script=Han}", "u"),
9
+ "L": /* @__PURE__ */ new RegExp("\\p{Letter}", "u"),
10
+ "N": /* @__PURE__ */ new RegExp("[\\p{Letter}\\p{Number}]", "u")
11
+ };
12
+ var matches = (pattern, character) => {
13
+ pattern.lastIndex = 0;
14
+ return pattern.test(character);
15
+ };
16
+ var parseStringMask = (mask, formatChars) => {
17
+ const tokens = [];
18
+ let escaped = false;
19
+ for (const character of Array.from(mask)) {
20
+ if (!escaped && character === "\\") {
21
+ escaped = true;
22
+ continue;
23
+ }
24
+ const pattern = !escaped ? formatChars[character] : void 0;
25
+ tokens.push(pattern ? { pattern } : { literal: character });
26
+ escaped = false;
27
+ }
28
+ if (escaped) tokens.push({ literal: "\\" });
29
+ return tokens;
30
+ };
31
+ var parseMask = (mask, formatChars) => {
32
+ if (typeof mask === "string") return parseStringMask(mask, formatChars);
33
+ return mask.map((token) => token instanceof RegExp ? { pattern: token } : { literal: token });
34
+ };
35
+ var mergeFormatChars = (formatChars) => _objectSpread2(_objectSpread2({}, defaultInputMaskFormatChars), formatChars);
36
+ var readEditableCharacters = (rawValue, tokens, maskChar) => {
37
+ const input = splitGraphemes(rawValue);
38
+ const values = [];
39
+ let inputIndex = 0;
40
+ for (const token of tokens) {
41
+ if (token.literal !== void 0) {
42
+ if (input[inputIndex] === token.literal) inputIndex += 1;
43
+ continue;
44
+ }
45
+ while (inputIndex < input.length) {
46
+ const character = input[inputIndex++];
47
+ if (maskChar && character === maskChar) continue;
48
+ if (token.pattern && matches(token.pattern, character)) {
49
+ values.push(character);
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ return values;
55
+ };
56
+ var buildLayout = (tokens, values, maskChar, showMask) => {
57
+ const positions = [];
58
+ const showTemplate = showMask && Boolean(maskChar);
59
+ let valueIndex = 0;
60
+ let previousEditableFilled = false;
61
+ for (const token of tokens) {
62
+ if (token.literal !== void 0) {
63
+ if (showTemplate || valueIndex < values.length || previousEditableFilled) positions.push({
64
+ char: token.literal,
65
+ literal: true,
66
+ filled: false
67
+ });
68
+ previousEditableFilled = false;
69
+ continue;
70
+ }
71
+ const value = values[valueIndex];
72
+ if (value !== void 0) {
73
+ positions.push({
74
+ char: value,
75
+ literal: false,
76
+ filled: true
77
+ });
78
+ valueIndex += 1;
79
+ previousEditableFilled = true;
80
+ } else if (showTemplate) {
81
+ positions.push({
82
+ char: maskChar,
83
+ literal: false,
84
+ filled: false
85
+ });
86
+ previousEditableFilled = false;
87
+ } else previousEditableFilled = false;
88
+ }
89
+ return positions;
90
+ };
91
+ var renderMask = (tokens, values, maskChar, showMask) => {
92
+ if (!values.length && !showMask) return "";
93
+ return buildLayout(tokens, values, maskChar, showMask).map((position) => position.char).join("");
94
+ };
95
+ var sliceToGraphemeBoundary = (value, cursor) => {
96
+ const graphemeIndex = codeUnitToGraphemeIndex(value, cursor);
97
+ return value.slice(0, graphemeIndexToCodeUnit(value, graphemeIndex));
98
+ };
99
+ function formatInputMask(rawValue, rawCursor, mask, options) {
100
+ const tokens = parseMask(mask, mergeFormatChars(options.formatChars));
101
+ const values = readEditableCharacters(rawValue, tokens, options.maskChar);
102
+ const value = renderMask(tokens, values, options.maskChar, options.showMask);
103
+ const editableCount = tokens.filter((token) => token.pattern).length;
104
+ const cursorValue = renderMask(tokens, readEditableCharacters(rawCursor === null ? rawValue : sliceToGraphemeBoundary(rawValue, rawCursor), tokens, options.maskChar), null, false);
105
+ const cursor = Math.min(cursorValue.length, value.length);
106
+ return {
107
+ value,
108
+ selection: {
109
+ start: cursor,
110
+ end: cursor
111
+ },
112
+ complete: values.length === editableCount
113
+ };
114
+ }
115
+ var layoutOffset = (positions, index) => {
116
+ let offset = 0;
117
+ for (let i = 0; i < index && i < positions.length; i++) offset += positions[i].char.length;
118
+ return offset;
119
+ };
120
+ var layoutIndexAtOffset = (positions, offset) => {
121
+ let acc = 0;
122
+ for (let i = 0; i < positions.length; i++) {
123
+ const len = positions[i].char.length;
124
+ if (offset < acc + len) return i;
125
+ acc += len;
126
+ }
127
+ return positions.length - 1;
128
+ };
129
+ var nearestFilled = (positions, fromIndex, step) => {
130
+ for (let i = fromIndex + step; i >= 0 && i < positions.length; i += step) if (positions[i].filled) return i;
131
+ return -1;
132
+ };
133
+ /**
134
+ * Resolves a single-character deletion so that backspace/delete on a fixed
135
+ * separator (or an attempt to delete an empty placeholder) clears the adjacent
136
+ * filled editable value instead of being a no-op. This mirrors react-input-mask's
137
+ * `getLeftEditablePosition` / `getRightEditablePosition` behavior.
138
+ *
139
+ * Returns the re-formatted value, cursor and completeness, or `null` to let the
140
+ * caller fall back to a full reformat (insertions, multi-char deletions, range
141
+ * edits, or nothing-to-delete). The result is always canonical (re-packed), so
142
+ * the stored value, the displayed value and the emitted modelValue stay in sync.
143
+ */
144
+ function resolveDeletion(previousValue, previousSelection, rawValue, rawCursor, mask, formatChars, maskChar = null) {
145
+ if (!previousSelection || previousSelection.start !== previousSelection.end) return null;
146
+ if (previousValue.length - rawValue.length !== 1) return null;
147
+ const prevCursor = previousSelection.start;
148
+ const backspace = rawCursor === prevCursor - 1;
149
+ if (!backspace && !(rawCursor === prevCursor)) return null;
150
+ const merged = mergeFormatChars(formatChars);
151
+ const tokens = parseMask(mask, merged);
152
+ const layout = buildLayout(tokens, readEditableCharacters(previousValue, tokens, maskChar), maskChar, true);
153
+ const deletedIndex = layoutIndexAtOffset(layout, backspace ? prevCursor - 1 : prevCursor);
154
+ if (deletedIndex < 0) return null;
155
+ const deleted = layout[deletedIndex];
156
+ let targetIndex;
157
+ if (deleted.literal) {
158
+ targetIndex = nearestFilled(layout, deletedIndex, backspace ? -1 : 1);
159
+ if (targetIndex < 0) return null;
160
+ } else if (deleted.filled) targetIndex = deletedIndex;
161
+ else return null;
162
+ const targetOffset = layoutOffset(layout, targetIndex);
163
+ const targetLen = layout[targetIndex].char.length;
164
+ const result = formatInputMask(previousValue.slice(0, targetOffset) + previousValue.slice(targetOffset + targetLen), targetOffset, mask, {
165
+ maskChar,
166
+ showMask: true,
167
+ formatChars: merged
168
+ });
169
+ return {
170
+ value: result.value,
171
+ cursor: result.selection.start,
172
+ complete: result.complete
173
+ };
174
+ }
175
+ //#endregion
176
+ export { defaultInputMaskFormatChars, formatInputMask, resolveDeletion };
@@ -0,0 +1,2 @@
1
+ import type { InputMaskPresetDefinition, InputMaskPresetName } from './types';
2
+ export declare const inputMaskPresets: Readonly<Record<InputMaskPresetName, InputMaskPresetDefinition>>;