Segmented editing and eager literals

Static patterns and arrays use segmented: true and eager: true by default. Separators anchor independent fields while you edit.

Empty an internal segment

bind(input, '(999) 999-9999')Place the caret after 222 and press Backspace three times.

The same edit without eager literals

bind(input, '(999) 999-9999', { eager: false })Existing internal dividers remain even with eager disabled.
// | marks the caret after the edit.
// Delete 222:          (111) |-3333
// Backspace again:     (111|-3333
// The caret stays before the untouched -3333 tail.

// CPF: select 012.153.441 in 012.153.441-39, then type 015.
// Result:              015.|-39

Existing internal dividers survive while later segments contain data. Backspace follows collapsed text to the left, including backward word and line deletion. Movement within a divider that stays visible is preserved. Selecting everything and deleting clears the field.

Repeated separators can make an edited value ambiguous: 1/2025 with 99/99/9999 resolves to the earliest fields that fit. Distinct separators give more precise anchors. For a continuous value where all following characters should shift, set the mask's segmented: false.

A bounded quantifier such as 9{1,2} makes a segment variable-width, and the separator you type is what closes it: with 9{1,2}/9{1,2}/9{4}, typing 3/ commits a one-digit day. That boundary then behaves like any other divider while you edit — later fields stay anchored, and the retired slots are not quietly reclaimed by the next keystroke.

Typing a character straight over a selection destroys the same dividers the equivalent Delete would, so bind() gives it the same rescue — but only when it has to. Selecting the 3/12 of 3/12/1986 and typing 4 leaves 4/1986, where the one surviving / reads equally well as the day's, and the untouched year would otherwise break apart into 4/19/86. Restoring the divider gives 4|//1986, year intact. The caret stays in the day — that field takes two digits and has only one, so the next keystroke widens it to 42 rather than starting the month; eager hands the caret across by itself once the field is full. Where the tail was never in danger — retyping a CPF over 012.153.441, whose - is distinct — nothing is restored. Like the Backspace/Delete handling, this is bind()-only: the pure helpers see just (value, caret) and cannot tell a replacement from fresh input.

A divider whose removal would re-segment untouched text is not erodible either. Backspacing the second / out of 13//1986 would leave 13/1986, which re-reads as 13 / 19 / 86, so it is put back and the keystroke erodes the day instead. Where dropping a divider costs nothing — a CPF's - still pins its last field — Backspace peels it away as described above.

Eager mode reveals the next literal when a segment fills: typing 25 into a date shows 25/. Set eager: false to wait for the next digit. bind() does not immediately restore an eager literal removed with Backspace/Delete. Pure helpers have no edit history and apply the configured eager option on every call. Arrow keys, Home/End, and selection shortcuts retain native behavior.