avances en plantillas

This commit is contained in:
JACS 2026-05-01 18:15:40 -05:00
parent 0f84beacf1
commit da0530d79b
2062 changed files with 598814 additions and 22 deletions

21
storage/public/dist/libs/imask/LICENSE vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 uNmAnNeR
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,24 @@
# imaskjs
vanilla javascript input mask
[![Build Status](https://travis-ci.com/uNmAnNeR/imaskjs.svg?branch=master)](https://travis-ci.com/uNmAnNeR/imaskjs)
[![Coverage Status](https://coveralls.io/repos/github/uNmAnNeR/imaskjs/badge.svg?branch=master)](https://coveralls.io/github/uNmAnNeR/imaskjs?branch=master)
[![npm version](https://badge.fury.io/js/imask.svg)](https://badge.fury.io/js/imask)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
<a href="https://opencollective.com/imask/donate" target="_blank">
<img src="https://opencollective.com/imask/donate/button.png?color=blue" width=300 />
</a>
## Docs, Examples, Demo
[https://imask.js.org/](https://imask.js.org/)
## Install
`npm install imask` and `import IMask from 'imask';`
or use CDN:
`<script src="https://unpkg.com/imask"></script>`
## Build & Test
`npm run make`

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,14 @@
import HTMLMaskElement from './html-mask-element';
export default class HTMLContenteditableMaskElement extends HTMLMaskElement {
input: HTMLElement;
/** Returns HTMLElement selection start */
get _unsafeSelectionStart(): number | null;
/** Returns HTMLElement selection end */
get _unsafeSelectionEnd(): number | null;
/** Sets HTMLElement selection */
_unsafeSelect(start: number, end: number): void;
/** HTMLElement value */
get value(): string;
set value(value: string);
}
//# sourceMappingURL=html-contenteditable-mask-element.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"html-contenteditable-mask-element.d.ts","sourceRoot":"","sources":["../../src/controls/html-contenteditable-mask-element.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,qBAAqB,CAAC;AAIlD,MAAM,CAAC,OAAO,OACR,8BAA+B,SAAQ,eAAe;IAClD,KAAK,EAAE,WAAW,CAAC;IAC3B,0CAA0C;IAC1C,IAAa,qBAAqB,IAAK,MAAM,GAAG,IAAI,CASnD;IAED,wCAAwC;IACxC,IAAa,mBAAmB,IAAK,MAAM,GAAG,IAAI,CASjD;IAED,iCAAiC;IACxB,aAAa,CAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAclD,wBAAwB;IACxB,IAAa,KAAK,IAAK,MAAM,CAE5B;IACD,IAAa,KAAK,CAAE,KAAK,EAAE,MAAM,EAEhC;CACF"}

View file

@ -0,0 +1,54 @@
import HTMLMaskElement from './html-mask-element.js';
import IMask from '../core/holder.js';
import './mask-element.js';
class HTMLContenteditableMaskElement extends HTMLMaskElement {
/** Returns HTMLElement selection start */
get _unsafeSelectionStart() {
const root = this.rootElement;
const selection = root.getSelection && root.getSelection();
const anchorOffset = selection && selection.anchorOffset;
const focusOffset = selection && selection.focusOffset;
if (focusOffset == null || anchorOffset == null || anchorOffset < focusOffset) {
return anchorOffset;
}
return focusOffset;
}
/** Returns HTMLElement selection end */
get _unsafeSelectionEnd() {
const root = this.rootElement;
const selection = root.getSelection && root.getSelection();
const anchorOffset = selection && selection.anchorOffset;
const focusOffset = selection && selection.focusOffset;
if (focusOffset == null || anchorOffset == null || anchorOffset > focusOffset) {
return anchorOffset;
}
return focusOffset;
}
/** Sets HTMLElement selection */
_unsafeSelect(start, end) {
if (!this.rootElement.createRange) return;
const range = this.rootElement.createRange();
range.setStart(this.input.firstChild || this.input, start);
range.setEnd(this.input.lastChild || this.input, end);
const root = this.rootElement;
const selection = root.getSelection && root.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
}
}
/** HTMLElement value */
get value() {
return this.input.textContent || '';
}
set value(value) {
this.input.textContent = value;
}
}
IMask.HTMLContenteditableMaskElement = HTMLContenteditableMaskElement;
export { HTMLContenteditableMaskElement as default };

View file

@ -0,0 +1,17 @@
import HTMLMaskElement from './html-mask-element';
export type InputElement = HTMLTextAreaElement | HTMLInputElement;
/** Bridge between InputElement and {@link Masked} */
export default class HTMLInputMaskElement extends HTMLMaskElement {
/** InputElement to use mask on */
input: InputElement;
constructor(input: InputElement);
/** Returns InputElement selection start */
get _unsafeSelectionStart(): number | null;
/** Returns InputElement selection end */
get _unsafeSelectionEnd(): number | null;
/** Sets InputElement selection */
_unsafeSelect(start: number, end: number): void;
get value(): string;
set value(value: string);
}
//# sourceMappingURL=html-input-mask-element.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"html-input-mask-element.d.ts","sourceRoot":"","sources":["../../src/controls/html-input-mask-element.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,MAAM,qBAAqB,CAAC;AAGlD,MAAM,MACD,YAAY,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAE3D,qDAAqD;AACrD,MAAM,CAAC,OAAO,OACR,oBAAqB,SAAQ,eAAe;IAChD,kCAAkC;IAC1B,KAAK,EAAE,YAAY,CAAC;gBAEf,KAAK,EAAE,YAAY;IAKhC,2CAA2C;IAC3C,IAAa,qBAAqB,IAAK,MAAM,GAAG,IAAI,CAEnD;IAED,yCAAyC;IACzC,IAAa,mBAAmB,IAAK,MAAM,GAAG,IAAI,CAEjD;IAED,kCAAkC;IAClC,aAAa,CAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAIzC,IAAa,KAAK,IAAK,MAAM,CAE5B;IACD,IAAa,KAAK,CAAE,KAAK,EAAE,MAAM,EAEhC;CACF"}

View file

@ -0,0 +1,37 @@
import HTMLMaskElement from './html-mask-element.js';
import IMask from '../core/holder.js';
import './mask-element.js';
/** Bridge between InputElement and {@link Masked} */
class HTMLInputMaskElement extends HTMLMaskElement {
/** InputElement to use mask on */
constructor(input) {
super(input);
this.input = input;
}
/** Returns InputElement selection start */
get _unsafeSelectionStart() {
return this.input.selectionStart != null ? this.input.selectionStart : this.value.length;
}
/** Returns InputElement selection end */
get _unsafeSelectionEnd() {
return this.input.selectionEnd;
}
/** Sets InputElement selection */
_unsafeSelect(start, end) {
this.input.setSelectionRange(start, end);
}
get value() {
return this.input.value;
}
set value(value) {
this.input.value = value;
}
}
IMask.HTMLMaskElement = HTMLMaskElement;
export { HTMLInputMaskElement as default };

View file

@ -0,0 +1,21 @@
import MaskElement, { EventHandlers } from './mask-element';
/** Bridge between HTMLElement and {@link Masked} */
export default abstract class HTMLMaskElement extends MaskElement {
/** HTMLElement to use mask on */
input: HTMLElement;
_handlers: EventHandlers;
abstract value: string;
constructor(input: HTMLElement);
get rootElement(): HTMLDocument;
/** Is element in focus */
get isActive(): boolean;
/** Binds HTMLElement events to mask internal events */
bindEvents(handlers: EventHandlers): void;
_onKeydown(e: KeyboardEvent): void;
_onBeforeinput(e: InputEvent): void;
_onCompositionEnd(e: CompositionEvent): void;
_onInput(e: InputEvent): void;
/** Unbinds HTMLElement events to mask internal events */
unbindEvents(): void;
}
//# sourceMappingURL=html-mask-element.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"html-mask-element.d.ts","sourceRoot":"","sources":["../../src/controls/html-mask-element.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,EAAE,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAO5D,oDAAoD;AACpD,MAAM,CAAC,OAAO,CACd,QAAQ,OAAO,eAAgB,SAAQ,WAAW;IAChD,iCAAiC;IACzB,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEV,KAAK,EAAE,WAAW;IAS/B,IAAI,WAAW,IAAK,YAAY,CAE/B;IAED,0BAA0B;IAC1B,IAAI,QAAQ,IAAK,OAAO,CAEvB;IAED,uDAAuD;IAC9C,UAAU,CAAE,QAAQ,EAAE,aAAa;IAY5C,UAAU,CAAE,CAAC,EAAE,aAAa;IAiB5B,cAAc,CAAE,CAAC,EAAE,UAAU;IAY7B,iBAAiB,CAAE,CAAC,EAAE,gBAAgB;IAItC,QAAQ,CAAE,CAAC,EAAE,UAAU;IAIvB,yDAAyD;IAChD,YAAY;CAWtB"}

View file

@ -0,0 +1,84 @@
import MaskElement from './mask-element.js';
import IMask from '../core/holder.js';
const KEY_Z = 90;
const KEY_Y = 89;
/** Bridge between HTMLElement and {@link Masked} */
class HTMLMaskElement extends MaskElement {
/** HTMLElement to use mask on */
constructor(input) {
super();
this.input = input;
this._onKeydown = this._onKeydown.bind(this);
this._onInput = this._onInput.bind(this);
this._onBeforeinput = this._onBeforeinput.bind(this);
this._onCompositionEnd = this._onCompositionEnd.bind(this);
}
get rootElement() {
var _this$input$getRootNo, _this$input$getRootNo2, _this$input;
return (_this$input$getRootNo = (_this$input$getRootNo2 = (_this$input = this.input).getRootNode) == null ? void 0 : _this$input$getRootNo2.call(_this$input)) != null ? _this$input$getRootNo : document;
}
/** Is element in focus */
get isActive() {
return this.input === this.rootElement.activeElement;
}
/** Binds HTMLElement events to mask internal events */
bindEvents(handlers) {
this.input.addEventListener('keydown', this._onKeydown);
this.input.addEventListener('input', this._onInput);
this.input.addEventListener('beforeinput', this._onBeforeinput);
this.input.addEventListener('compositionend', this._onCompositionEnd);
this.input.addEventListener('drop', handlers.drop);
this.input.addEventListener('click', handlers.click);
this.input.addEventListener('focus', handlers.focus);
this.input.addEventListener('blur', handlers.commit);
this._handlers = handlers;
}
_onKeydown(e) {
if (this._handlers.redo && (e.keyCode === KEY_Z && e.shiftKey && (e.metaKey || e.ctrlKey) || e.keyCode === KEY_Y && e.ctrlKey)) {
e.preventDefault();
return this._handlers.redo(e);
}
if (this._handlers.undo && e.keyCode === KEY_Z && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
return this._handlers.undo(e);
}
if (!e.isComposing) this._handlers.selectionChange(e);
}
_onBeforeinput(e) {
if (e.inputType === 'historyUndo' && this._handlers.undo) {
e.preventDefault();
return this._handlers.undo(e);
}
if (e.inputType === 'historyRedo' && this._handlers.redo) {
e.preventDefault();
return this._handlers.redo(e);
}
}
_onCompositionEnd(e) {
this._handlers.input(e);
}
_onInput(e) {
if (!e.isComposing) this._handlers.input(e);
}
/** Unbinds HTMLElement events to mask internal events */
unbindEvents() {
this.input.removeEventListener('keydown', this._onKeydown);
this.input.removeEventListener('input', this._onInput);
this.input.removeEventListener('beforeinput', this._onBeforeinput);
this.input.removeEventListener('compositionend', this._onCompositionEnd);
this.input.removeEventListener('drop', this._handlers.drop);
this.input.removeEventListener('click', this._handlers.click);
this.input.removeEventListener('focus', this._handlers.focus);
this.input.removeEventListener('blur', this._handlers.commit);
this._handlers = {};
}
}
IMask.HTMLMaskElement = HTMLMaskElement;
export { HTMLMaskElement as default };

View file

@ -0,0 +1,18 @@
import { type Selection } from '../core/utils';
export type InputHistoryState = {
unmaskedValue: string;
selection: Selection;
};
export default class InputHistory {
static MAX_LENGTH: number;
states: InputHistoryState[];
currentIndex: number;
get currentState(): InputHistoryState | undefined;
get isEmpty(): boolean;
push(state: InputHistoryState): void;
go(steps: number): InputHistoryState | undefined;
undo(): InputHistoryState | undefined;
redo(): InputHistoryState | undefined;
clear(): void;
}
//# sourceMappingURL=input-history.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"input-history.d.ts","sourceRoot":"","sources":["../../src/controls/input-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAG/C,MAAM,MACD,iBAAiB,GAAG;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAGF,MAAM,CAAC,OAAO,OACR,YAAY;IAChB,MAAM,CAAC,UAAU,SAAO;IACxB,MAAM,EAAE,iBAAiB,EAAE,CAAM;IACjC,YAAY,SAAK;IAEjB,IAAI,YAAY,IAAK,iBAAiB,GAAG,SAAS,CAEjD;IAED,IAAI,OAAO,IAAK,OAAO,CAEtB;IAED,IAAI,CAAE,KAAK,EAAE,iBAAiB;IAQ9B,EAAE,CAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAKjD,IAAI;IAIJ,IAAI;IAIJ,KAAK;CAIN"}

View file

@ -0,0 +1,36 @@
class InputHistory {
constructor() {
this.states = [];
this.currentIndex = 0;
}
get currentState() {
return this.states[this.currentIndex];
}
get isEmpty() {
return this.states.length === 0;
}
push(state) {
// if current index points before the last element then remove the future
if (this.currentIndex < this.states.length - 1) this.states.length = this.currentIndex + 1;
this.states.push(state);
if (this.states.length > InputHistory.MAX_LENGTH) this.states.shift();
this.currentIndex = this.states.length - 1;
}
go(steps) {
this.currentIndex = Math.min(Math.max(this.currentIndex + steps, 0), this.states.length - 1);
return this.currentState;
}
undo() {
return this.go(-1);
}
redo() {
return this.go(+1);
}
clear() {
this.states.length = 0;
this.currentIndex = 0;
}
}
InputHistory.MAX_LENGTH = 100;
export { InputHistory as default };

View file

@ -0,0 +1,96 @@
import { type Selection } from '../core/utils';
import { type UpdateOpts, type FactoryArg, type FactoryReturnMasked } from '../masked/factory';
import MaskElement from './mask-element';
import { type InputElement } from './html-input-mask-element';
import InputHistory, { type InputHistoryState } from './input-history';
export type InputMaskElement = MaskElement | InputElement | HTMLElement;
export type InputMaskEventListener = (e?: InputEvent) => void;
/** Listens to element events and controls changes between element and {@link Masked} */
export default class InputMask<Opts extends FactoryArg = Record<string, unknown>> {
/**
View element
*/
el: MaskElement;
/** Internal {@link Masked} model */
masked: FactoryReturnMasked<Opts>;
_listeners: Record<string, Array<InputMaskEventListener>>;
_value: string;
_changingCursorPos: number;
_unmaskedValue: string;
_rawInputValue: string;
_selection: Selection;
_cursorChanging?: ReturnType<typeof setTimeout>;
_historyChanging?: boolean;
_inputEvent?: InputEvent;
history: InputHistory;
constructor(el: InputMaskElement, opts: Opts);
maskEquals(mask: any): boolean;
/** Masked */
get mask(): FactoryReturnMasked<Opts>['mask'];
set mask(mask: any);
/** Raw value */
get value(): string;
set value(str: string);
/** Unmasked value */
get unmaskedValue(): string;
set unmaskedValue(str: string);
/** Raw input value */
get rawInputValue(): string;
set rawInputValue(str: string);
/** Typed unmasked value */
get typedValue(): FactoryReturnMasked<Opts>['typedValue'];
set typedValue(val: FactoryReturnMasked<Opts>['typedValue']);
/** Display value */
get displayValue(): string;
/** Starts listening to element events */
_bindEvents(): void;
/** Stops listening to element events */
_unbindEvents(): void;
/** Fires custom event */
_fireEvent(ev: string, e?: InputEvent): void;
/** Current selection start */
get selectionStart(): number;
/** Current cursor position */
get cursorPos(): number;
set cursorPos(pos: number);
/** Stores current selection */
_saveSelection(): void;
/** Syncronizes model value from view */
updateValue(): void;
/** Syncronizes view from model value, fires change events */
updateControl(cursorPos?: number | 'auto'): void;
/** Updates options with deep equal check, recreates {@link Masked} model if mask type changes */
updateOptions(opts: UpdateOpts<Opts>): void;
/** Updates cursor */
updateCursor(cursorPos: number): void;
/** Delays cursor update to support mobile browsers */
_delayUpdateCursor(cursorPos: number): void;
/** Fires custom events */
_fireChangeEvents(): void;
/** Aborts delayed cursor update */
_abortUpdateCursor(): void;
/** Aligns cursor to nearest available position */
alignCursor(): void;
/** Aligns cursor only if selection is empty */
alignCursorFriendly(): void;
/** Adds listener on custom event */
on(ev: string, handler: InputMaskEventListener): this;
/** Removes custom event listener */
off(ev: string, handler: InputMaskEventListener): this;
/** Handles view input event */
_onInput(e: InputEvent): void;
/** Handles view change event and commits model value */
_onChange(): void;
/** Handles view drop event, prevents by default */
_onDrop(ev: Event): void;
/** Restore last selection on focus */
_onFocus(ev: Event): void;
/** Restore last selection on focus */
_onClick(ev: Event): void;
_onUndo(): void;
_onRedo(): void;
_applyHistoryState(state: InputHistoryState | undefined): void;
/** Unbind view events and removes element reference */
destroy(): void;
}
//# sourceMappingURL=input.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/controls/input.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,350 @@
import { DIRECTION } from '../core/utils.js';
import ActionDetails from '../core/action-details.js';
import createMask, { maskedClass } from '../masked/factory.js';
import MaskElement from './mask-element.js';
import HTMLInputMaskElement from './html-input-mask-element.js';
import HTMLContenteditableMaskElement from './html-contenteditable-mask-element.js';
import IMask from '../core/holder.js';
import InputHistory from './input-history.js';
import './html-mask-element.js';
/** Listens to element events and controls changes between element and {@link Masked} */
class InputMask {
/**
View element
*/
/** Internal {@link Masked} model */
constructor(el, opts) {
this.el = el instanceof MaskElement ? el : el.isContentEditable && el.tagName !== 'INPUT' && el.tagName !== 'TEXTAREA' ? new HTMLContenteditableMaskElement(el) : new HTMLInputMaskElement(el);
this.masked = createMask(opts);
this._listeners = {};
this._value = '';
this._unmaskedValue = '';
this._rawInputValue = '';
this.history = new InputHistory();
this._saveSelection = this._saveSelection.bind(this);
this._onInput = this._onInput.bind(this);
this._onChange = this._onChange.bind(this);
this._onDrop = this._onDrop.bind(this);
this._onFocus = this._onFocus.bind(this);
this._onClick = this._onClick.bind(this);
this._onUndo = this._onUndo.bind(this);
this._onRedo = this._onRedo.bind(this);
this.alignCursor = this.alignCursor.bind(this);
this.alignCursorFriendly = this.alignCursorFriendly.bind(this);
this._bindEvents();
// refresh
this.updateValue();
this._onChange();
}
maskEquals(mask) {
var _this$masked;
return mask == null || ((_this$masked = this.masked) == null ? void 0 : _this$masked.maskEquals(mask));
}
/** Masked */
get mask() {
return this.masked.mask;
}
set mask(mask) {
if (this.maskEquals(mask)) return;
if (!(mask instanceof IMask.Masked) && this.masked.constructor === maskedClass(mask)) {
// TODO "any" no idea
this.masked.updateOptions({
mask
});
return;
}
const masked = mask instanceof IMask.Masked ? mask : createMask({
mask
});
masked.unmaskedValue = this.masked.unmaskedValue;
this.masked = masked;
}
/** Raw value */
get value() {
return this._value;
}
set value(str) {
if (this.value === str) return;
this.masked.value = str;
this.updateControl('auto');
}
/** Unmasked value */
get unmaskedValue() {
return this._unmaskedValue;
}
set unmaskedValue(str) {
if (this.unmaskedValue === str) return;
this.masked.unmaskedValue = str;
this.updateControl('auto');
}
/** Raw input value */
get rawInputValue() {
return this._rawInputValue;
}
set rawInputValue(str) {
if (this.rawInputValue === str) return;
this.masked.rawInputValue = str;
this.updateControl();
this.alignCursor();
}
/** Typed unmasked value */
get typedValue() {
return this.masked.typedValue;
}
set typedValue(val) {
if (this.masked.typedValueEquals(val)) return;
this.masked.typedValue = val;
this.updateControl('auto');
}
/** Display value */
get displayValue() {
return this.masked.displayValue;
}
/** Starts listening to element events */
_bindEvents() {
this.el.bindEvents({
selectionChange: this._saveSelection,
input: this._onInput,
drop: this._onDrop,
click: this._onClick,
focus: this._onFocus,
commit: this._onChange,
undo: this._onUndo,
redo: this._onRedo
});
}
/** Stops listening to element events */
_unbindEvents() {
if (this.el) this.el.unbindEvents();
}
/** Fires custom event */
_fireEvent(ev, e) {
const listeners = this._listeners[ev];
if (!listeners) return;
listeners.forEach(l => l(e));
}
/** Current selection start */
get selectionStart() {
return this._cursorChanging ? this._changingCursorPos : this.el.selectionStart;
}
/** Current cursor position */
get cursorPos() {
return this._cursorChanging ? this._changingCursorPos : this.el.selectionEnd;
}
set cursorPos(pos) {
if (!this.el || !this.el.isActive) return;
this.el.select(pos, pos);
this._saveSelection();
}
/** Stores current selection */
_saveSelection( /* ev */
) {
if (this.displayValue !== this.el.value) {
console.warn('Element value was changed outside of mask. Syncronize mask using `mask.updateValue()` to work properly.'); // eslint-disable-line no-console
}
this._selection = {
start: this.selectionStart,
end: this.cursorPos
};
}
/** Syncronizes model value from view */
updateValue() {
this.masked.value = this.el.value;
this._value = this.masked.value;
this._unmaskedValue = this.masked.unmaskedValue;
this._rawInputValue = this.masked.rawInputValue;
}
/** Syncronizes view from model value, fires change events */
updateControl(cursorPos) {
const newUnmaskedValue = this.masked.unmaskedValue;
const newValue = this.masked.value;
const newRawInputValue = this.masked.rawInputValue;
const newDisplayValue = this.displayValue;
const isChanged = this.unmaskedValue !== newUnmaskedValue || this.value !== newValue || this._rawInputValue !== newRawInputValue;
this._unmaskedValue = newUnmaskedValue;
this._value = newValue;
this._rawInputValue = newRawInputValue;
if (this.el.value !== newDisplayValue) this.el.value = newDisplayValue;
if (cursorPos === 'auto') this.alignCursor();else if (cursorPos != null) this.cursorPos = cursorPos;
if (isChanged) this._fireChangeEvents();
if (!this._historyChanging && (isChanged || this.history.isEmpty)) this.history.push({
unmaskedValue: newUnmaskedValue,
selection: {
start: this.selectionStart,
end: this.cursorPos
}
});
}
/** Updates options with deep equal check, recreates {@link Masked} model if mask type changes */
updateOptions(opts) {
const {
mask,
...restOpts
} = opts; // TODO types, yes, mask is optional
const updateMask = !this.maskEquals(mask);
const updateOpts = this.masked.optionsIsChanged(restOpts);
if (updateMask) this.mask = mask;
if (updateOpts) this.masked.updateOptions(restOpts); // TODO
if (updateMask || updateOpts) this.updateControl();
}
/** Updates cursor */
updateCursor(cursorPos) {
if (cursorPos == null) return;
this.cursorPos = cursorPos;
// also queue change cursor for mobile browsers
this._delayUpdateCursor(cursorPos);
}
/** Delays cursor update to support mobile browsers */
_delayUpdateCursor(cursorPos) {
this._abortUpdateCursor();
this._changingCursorPos = cursorPos;
this._cursorChanging = setTimeout(() => {
if (!this.el) return; // if was destroyed
this.cursorPos = this._changingCursorPos;
this._abortUpdateCursor();
}, 10);
}
/** Fires custom events */
_fireChangeEvents() {
this._fireEvent('accept', this._inputEvent);
if (this.masked.isComplete) this._fireEvent('complete', this._inputEvent);
}
/** Aborts delayed cursor update */
_abortUpdateCursor() {
if (this._cursorChanging) {
clearTimeout(this._cursorChanging);
delete this._cursorChanging;
}
}
/** Aligns cursor to nearest available position */
alignCursor() {
this.cursorPos = this.masked.nearestInputPos(this.masked.nearestInputPos(this.cursorPos, DIRECTION.LEFT));
}
/** Aligns cursor only if selection is empty */
alignCursorFriendly() {
if (this.selectionStart !== this.cursorPos) return; // skip if range is selected
this.alignCursor();
}
/** Adds listener on custom event */
on(ev, handler) {
if (!this._listeners[ev]) this._listeners[ev] = [];
this._listeners[ev].push(handler);
return this;
}
/** Removes custom event listener */
off(ev, handler) {
if (!this._listeners[ev]) return this;
if (!handler) {
delete this._listeners[ev];
return this;
}
const hIndex = this._listeners[ev].indexOf(handler);
if (hIndex >= 0) this._listeners[ev].splice(hIndex, 1);
return this;
}
/** Handles view input event */
_onInput(e) {
this._inputEvent = e;
this._abortUpdateCursor();
const details = new ActionDetails({
// new state
value: this.el.value,
cursorPos: this.cursorPos,
// old state
oldValue: this.displayValue,
oldSelection: this._selection
});
const oldRawValue = this.masked.rawInputValue;
const offset = this.masked.splice(details.startChangePos, details.removed.length, details.inserted, details.removeDirection, {
input: true,
raw: true
}).offset;
// force align in remove direction only if no input chars were removed
// otherwise we still need to align with NONE (to get out from fixed symbols for instance)
const removeDirection = oldRawValue === this.masked.rawInputValue ? details.removeDirection : DIRECTION.NONE;
let cursorPos = this.masked.nearestInputPos(details.startChangePos + offset, removeDirection);
if (removeDirection !== DIRECTION.NONE) cursorPos = this.masked.nearestInputPos(cursorPos, DIRECTION.NONE);
this.updateControl(cursorPos);
delete this._inputEvent;
}
/** Handles view change event and commits model value */
_onChange() {
if (this.displayValue !== this.el.value) this.updateValue();
this.masked.doCommit();
this.updateControl();
this._saveSelection();
}
/** Handles view drop event, prevents by default */
_onDrop(ev) {
ev.preventDefault();
ev.stopPropagation();
}
/** Restore last selection on focus */
_onFocus(ev) {
this.alignCursorFriendly();
}
/** Restore last selection on focus */
_onClick(ev) {
this.alignCursorFriendly();
}
_onUndo() {
this._applyHistoryState(this.history.undo());
}
_onRedo() {
this._applyHistoryState(this.history.redo());
}
_applyHistoryState(state) {
if (!state) return;
this._historyChanging = true;
this.unmaskedValue = state.unmaskedValue;
this.el.select(state.selection.start, state.selection.end);
this._saveSelection();
this._historyChanging = false;
}
/** Unbind view events and removes element reference */
destroy() {
this._unbindEvents();
this._listeners.length = 0;
delete this.el;
}
}
IMask.InputMask = InputMask;
export { InputMask as default };

View file

@ -0,0 +1,31 @@
export type ElementEvent = 'selectionChange' | 'input' | 'drop' | 'click' | 'focus' | 'commit';
export type EventHandlers = {
[key in ElementEvent]: (...args: any[]) => void;
} & {
undo?: (...args: any[]) => void;
redo?: (...args: any[]) => void;
};
/** Generic element API to use with mask */
export default abstract class MaskElement {
/** */
abstract _unsafeSelectionStart: number | null;
/** */
abstract _unsafeSelectionEnd: number | null;
/** */
abstract value: string;
/** Safely returns selection start */
get selectionStart(): number;
/** Safely returns selection end */
get selectionEnd(): number;
/** Safely sets element selection */
select(start: number, end: number): void;
/** */
get isActive(): boolean;
/** */
abstract _unsafeSelect(start: number, end: number): void;
/** */
abstract bindEvents(handlers: EventHandlers): void;
/** */
abstract unbindEvents(): void;
}
//# sourceMappingURL=mask-element.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"mask-element.d.ts","sourceRoot":"","sources":["../../src/controls/mask-element.ts"],"names":[],"mappings":"AAGA,MAAM,MACD,YAAY,GACb,iBAAiB,GACjB,OAAO,GACP,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,CACX;AAED,MAAM,MACD,aAAa,GAAG;KAAG,GAAG,IAAI,YAAY,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;CAAE,GAAG;IACzE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CACjC,CAAA;AAED,4CAA4C;AAC5C,MAAM,CAAC,OAAO,CACd,QAAQ,OAAO,WAAW;IACxB,MAAM;IACN,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM;IACN,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,MAAM;IACN,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,qCAAqC;IACrC,IAAI,cAAc,IAAK,MAAM,CAS5B;IAED,mCAAmC;IACnC,IAAI,YAAY,IAAK,MAAM,CAS1B;IAED,oCAAoC;IACpC,MAAM,CAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IASlC,MAAM;IACN,IAAI,QAAQ,IAAK,OAAO,CAAkB;IAC1C,MAAM;IACN,QAAQ,CAAC,aAAa,CAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IACzD,MAAM;IACN,QAAQ,CAAC,UAAU,CAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IACnD,MAAM;IACN,QAAQ,CAAC,YAAY,IAAK,IAAI;CAC/B"}

View file

@ -0,0 +1,49 @@
import IMask from '../core/holder.js';
/** Generic element API to use with mask */
class MaskElement {
/** */
/** */
/** */
/** Safely returns selection start */
get selectionStart() {
let start;
try {
start = this._unsafeSelectionStart;
} catch {}
return start != null ? start : this.value.length;
}
/** Safely returns selection end */
get selectionEnd() {
let end;
try {
end = this._unsafeSelectionEnd;
} catch {}
return end != null ? end : this.value.length;
}
/** Safely sets element selection */
select(start, end) {
if (start == null || end == null || start === this.selectionStart && end === this.selectionEnd) return;
try {
this._unsafeSelect(start, end);
} catch {}
}
/** */
get isActive() {
return false;
}
/** */
/** */
/** */
}
IMask.MaskElement = MaskElement;
export { MaskElement as default };

View file

@ -0,0 +1,31 @@
import { type Direction, type Selection } from './utils';
export type ActionDetailsOptions = Pick<ActionDetails, 'value' | 'cursorPos' | 'oldValue' | 'oldSelection'>;
/** Provides details of changing input */
export default class ActionDetails {
/** Current input value */
value: string;
/** Current cursor position */
cursorPos: number;
/** Old input value */
oldValue: string;
/** Old selection */
oldSelection: Selection;
constructor(opts: ActionDetailsOptions);
/** Start changing position */
get startChangePos(): number;
/** Inserted symbols count */
get insertedCount(): number;
/** Inserted symbols */
get inserted(): string;
/** Removed symbols count */
get removedCount(): number;
/** Removed symbols */
get removed(): string;
/** Unchanged head symbols */
get head(): string;
/** Unchanged tail symbols */
get tail(): string;
/** Remove direction */
get removeDirection(): Direction;
}
//# sourceMappingURL=action-details.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"action-details.d.ts","sourceRoot":"","sources":["../../src/core/action-details.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAa,MAAM,SAAS,CAAC;AAEpE,MAAM,MACD,oBAAoB,GAAG,IAAI,CAAC,aAAa,EAC1C,OAAO,GACP,WAAW,GACX,UAAU,GACV,cAAc,CACjB,CAAC;AAGF,yCAAyC;AACzC,MAAM,CAAC,OAAO,OACR,aAAa;IACjB,0BAA0B;IAClB,KAAK,EAAE,MAAM,CAAC;IACtB,8BAA8B;IACtB,SAAS,EAAE,MAAM,CAAC;IAC1B,sBAAsB;IACd,QAAQ,EAAE,MAAM,CAAC;IACzB,oBAAoB;IACZ,YAAY,EAAE,SAAS,CAAC;gBAEnB,IAAI,EAAE,oBAAoB;IAiBvC,8BAA8B;IAC9B,IAAI,cAAc,IAAK,MAAM,CAE5B;IAED,6BAA6B;IAC7B,IAAI,aAAa,IAAK,MAAM,CAE3B;IAED,uBAAuB;IACvB,IAAI,QAAQ,IAAK,MAAM,CAEtB;IAED,4BAA4B;IAC5B,IAAI,YAAY,IAAK,MAAM,CAK1B;IAED,sBAAsB;IACtB,IAAI,OAAO,IAAK,MAAM,CAErB;IAED,6BAA6B;IAC7B,IAAI,IAAI,IAAK,MAAM,CAElB;IAED,6BAA6B;IAC7B,IAAI,IAAI,IAAK,MAAM,CAElB;IAED,uBAAuB;IACvB,IAAI,eAAe,IAAK,SAAS,CAWhC;CACF"}

View file

@ -0,0 +1,77 @@
import { DIRECTION } from './utils.js';
/** Provides details of changing input */
class ActionDetails {
/** Current input value */
/** Current cursor position */
/** Old input value */
/** Old selection */
constructor(opts) {
Object.assign(this, opts);
// double check if left part was changed (autofilling, other non-standard input triggers)
while (this.value.slice(0, this.startChangePos) !== this.oldValue.slice(0, this.startChangePos)) {
--this.oldSelection.start;
}
if (this.insertedCount) {
// double check right part
while (this.value.slice(this.cursorPos) !== this.oldValue.slice(this.oldSelection.end)) {
if (this.value.length - this.cursorPos < this.oldValue.length - this.oldSelection.end) ++this.oldSelection.end;else ++this.cursorPos;
}
}
}
/** Start changing position */
get startChangePos() {
return Math.min(this.cursorPos, this.oldSelection.start);
}
/** Inserted symbols count */
get insertedCount() {
return this.cursorPos - this.startChangePos;
}
/** Inserted symbols */
get inserted() {
return this.value.substr(this.startChangePos, this.insertedCount);
}
/** Removed symbols count */
get removedCount() {
// Math.max for opposite operation
return Math.max(this.oldSelection.end - this.startChangePos ||
// for Delete
this.oldValue.length - this.value.length, 0);
}
/** Removed symbols */
get removed() {
return this.oldValue.substr(this.startChangePos, this.removedCount);
}
/** Unchanged head symbols */
get head() {
return this.value.substring(0, this.startChangePos);
}
/** Unchanged tail symbols */
get tail() {
return this.value.substring(this.startChangePos + this.insertedCount);
}
/** Remove direction */
get removeDirection() {
if (!this.removedCount || this.insertedCount) return DIRECTION.NONE;
// align right if delete at right
return (this.oldSelection.end === this.cursorPos || this.oldSelection.start === this.cursorPos) &&
// if not range removed (event with backspace)
this.oldSelection.end === this.oldSelection.start ? DIRECTION.RIGHT : DIRECTION.LEFT;
}
}
export { ActionDetails as default };

View file

@ -0,0 +1,21 @@
export type ChangeDetailsOptions = Pick<ChangeDetails, 'inserted' | 'tailShift' | 'rawInserted' | 'skip'>;
/** Provides details of changing model value */
export default class ChangeDetails {
/** Inserted symbols */
inserted: string;
/** Additional offset if any changes occurred before tail */
tailShift: number;
/** Raw inserted is used by dynamic mask */
rawInserted: string;
/** Can skip chars */
skip: boolean;
static normalize(prep: string | [string, ChangeDetails]): [string, ChangeDetails];
constructor(details?: Partial<ChangeDetailsOptions>);
/** Aggregate changes */
aggregate(details: ChangeDetails): this;
/** Total offset considering all changes */
get offset(): number;
get consumed(): boolean;
equals(details: ChangeDetails): boolean;
}
//# sourceMappingURL=change-details.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"change-details.d.ts","sourceRoot":"","sources":["../../src/core/change-details.ts"],"names":[],"mappings":"AAGA,MAAM,MACD,oBAAoB,GAAG,IAAI,CAAC,aAAa,EAC1C,UAAU,GACV,WAAW,GACX,aAAa,GACb,MAAM,CACT,CAAC;AAEF,+CAA+C;AAC/C,MAAM,CAAC,OAAO,OACR,aAAa;IACjB,uBAAuB;IACf,QAAQ,EAAE,MAAM,CAAC;IACzB,4DAA4D;IACpD,SAAS,EAAE,MAAM,CAAC;IAC1B,2CAA2C;IACnC,WAAW,EAAE,MAAM,CAAC;IAC5B,qBAAqB;IACb,IAAI,EAAE,OAAO,CAAC;IAGtB,MAAM,CAAC,SAAS,CAAE,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC;gBAOrE,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC;IASpD,wBAAwB;IACxB,SAAS,CAAE,OAAO,EAAE,aAAa,GAAG,IAAI;IASxC,2CAA2C;IAC3C,IAAI,MAAM,IAAK,MAAM,CAEpB;IAED,IAAI,QAAQ,IAAK,OAAO,CAEvB;IAED,MAAM,CAAE,OAAO,EAAE,aAAa,GAAG,OAAO;CAOzC"}

View file

@ -0,0 +1,47 @@
import IMask from './holder.js';
/** Provides details of changing model value */
class ChangeDetails {
/** Inserted symbols */
/** Additional offset if any changes occurred before tail */
/** Raw inserted is used by dynamic mask */
/** Can skip chars */
static normalize(prep) {
return Array.isArray(prep) ? prep : [prep, new ChangeDetails()];
}
constructor(details) {
Object.assign(this, {
inserted: '',
rawInserted: '',
tailShift: 0,
skip: false
}, details);
}
/** Aggregate changes */
aggregate(details) {
this.inserted += details.inserted;
this.rawInserted += details.rawInserted;
this.tailShift += details.tailShift;
this.skip = this.skip || details.skip;
return this;
}
/** Total offset considering all changes */
get offset() {
return this.tailShift + this.inserted.length;
}
get consumed() {
return Boolean(this.rawInserted) || this.skip;
}
equals(details) {
return this.inserted === details.inserted && this.tailShift === details.tailShift && this.rawInserted === details.rawInserted && this.skip === details.skip;
}
}
IMask.ChangeDetails = ChangeDetails;
export { ChangeDetails as default };

View file

@ -0,0 +1,22 @@
import type { TailDetails, AppendTail } from './tail-details';
import type ChangeDetails from './change-details';
type ContinuousTailState = Pick<ContinuousTailDetails, 'value' | 'from' | 'stop'>;
/** Provides details of continuous extracted tail */
export default class ContinuousTailDetails implements TailDetails {
/** Tail value as string */
value: string;
/** Tail start position */
from: number;
/** Start position */
stop?: number;
constructor(value?: string, from?: number, stop?: number);
toString(): string;
extend(tail: string | TailDetails): void;
appendTo(masked: AppendTail): ChangeDetails;
get state(): ContinuousTailState;
set state(state: ContinuousTailState);
unshift(beforePos?: number): string;
shift(): string;
}
export {};
//# sourceMappingURL=continuous-tail-details.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"continuous-tail-details.d.ts","sourceRoot":"","sources":["../../src/core/continuous-tail-details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAC;AAGlD,KAAK,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,EACjD,OAAO,GACP,MAAM,GACN,MAAM,CACT,CAAC;AAEF,oDAAoD;AACpD,MAAM,CAAC,OAAO,OACR,qBAAsB,YAAW,WAAW;IAChD,2BAA2B;IACnB,KAAK,EAAE,MAAM,CAAC;IACtB,0BAA0B;IAClB,IAAI,EAAE,MAAM,CAAC;IACrB,qBAAqB;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;gBAET,KAAK,GAAE,MAAS,EAAE,IAAI,GAAE,MAAQ,EAAE,IAAI,CAAC,EAAE,MAAM;IAM5D,QAAQ,IAAK,MAAM;IAEnB,MAAM,CAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAIzC,QAAQ,CAAE,MAAM,EAAE,UAAU,GAAG,aAAa;IAK5C,IAAI,KAAK,IAAK,mBAAmB,CAMhC;IAED,IAAI,KAAK,CAAE,KAAK,EAAE,mBAAmB,EAEpC;IAED,OAAO,CAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAQpC,KAAK,IAAK,MAAM;CAOjB"}

View file

@ -0,0 +1,55 @@
/** Provides details of continuous extracted tail */
class ContinuousTailDetails {
/** Tail value as string */
/** Tail start position */
/** Start position */
constructor(value, from, stop) {
if (value === void 0) {
value = '';
}
if (from === void 0) {
from = 0;
}
this.value = value;
this.from = from;
this.stop = stop;
}
toString() {
return this.value;
}
extend(tail) {
this.value += String(tail);
}
appendTo(masked) {
return masked.append(this.toString(), {
tail: true
}).aggregate(masked._appendPlaceholder());
}
get state() {
return {
value: this.value,
from: this.from,
stop: this.stop
};
}
set state(state) {
Object.assign(this, state);
}
unshift(beforePos) {
if (!this.value.length || beforePos != null && this.from >= beforePos) return '';
const shiftChar = this.value[0];
this.value = this.value.slice(1);
return shiftChar;
}
shift() {
if (!this.value.length) return '';
const shiftChar = this.value[this.value.length - 1];
this.value = this.value.slice(0, -1);
return shiftChar;
}
}
export { ContinuousTailDetails as default };

View file

@ -0,0 +1,42 @@
import type { default as _InputMask, InputMaskElement as _InputMaskElement } from '../controls/input';
import type { default as _Masked } from '../masked/base';
import type { default as _MaskedPattern } from '../masked/pattern';
import type { default as _RepeatBlock } from '../masked/repeat';
import type { default as _MaskedDate } from '../masked/date';
import type { default as _MaskedDynamic } from '../masked/dynamic';
import type { default as _MaskedEnum } from '../masked/enum';
import type { default as _MaskedRange } from '../masked/range';
import type { default as _MaskedNumber } from '../masked/number';
import type { default as _MaskedFunction } from '../masked/function';
import type { default as _MaskedRegExp } from '../masked/regexp';
import type { default as _createMask, FactoryArg } from '../masked/factory';
import type { default as _ChangeDetails } from './change-details';
import type { default as _MaskElement } from '../controls/mask-element';
import type { default as _HTMLMaskElement } from '../controls/html-mask-element';
import type { default as _HTMLContenteditableMaskElement } from '../controls/html-contenteditable-mask-element';
import type { createPipe as _createPipe, pipe as _pipe, PIPE_TYPE as _PIPE_TYPE } from '../masked/pipe';
/** Applies mask on element */
declare function IMask<Opts extends FactoryArg>(el: _InputMaskElement, opts: Opts): _InputMask<Opts>;
declare namespace IMask {
let InputMask: typeof _InputMask;
let createMask: typeof _createMask;
let Masked: typeof _Masked;
let MaskedPattern: typeof _MaskedPattern;
let RepeatBlock: typeof _RepeatBlock;
let MaskedDate: typeof _MaskedDate;
let MaskedDynamic: typeof _MaskedDynamic;
let MaskedEnum: typeof _MaskedEnum;
let MaskedRange: typeof _MaskedRange;
let MaskedNumber: typeof _MaskedNumber;
let MaskedFunction: typeof _MaskedFunction;
let MaskedRegExp: typeof _MaskedRegExp;
let ChangeDetails: typeof _ChangeDetails;
let MaskElement: typeof _MaskElement;
let HTMLMaskElement: typeof _HTMLMaskElement;
let HTMLContenteditableMaskElement: typeof _HTMLContenteditableMaskElement;
let createPipe: typeof _createPipe;
let pipe: typeof _pipe;
let PIPE_TYPE: typeof _PIPE_TYPE;
}
export default IMask;
//# sourceMappingURL=holder.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"holder.d.ts","sourceRoot":"","sources":["../../src/core/holder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,gBAAgB,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtG,OAAO,KAAK,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,KAAK,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,KAAK,EACV,OAAO,IAAI,WAAW,EACtB,UAAU,EACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,IAAI,+BAA+B,EAAE,MAAM,+CAA+C,CAAC;AAChH,OAAO,KAAK,EACV,UAAU,IAAI,WAAW,EACzB,IAAI,IAAI,KAAK,EACb,SAAS,IAAI,UAAU,EACxB,MAAM,gBAAgB,CAAC;AAGxB,8BAA8B;AAC9B,iBAAS,KAAK,CAAC,IAAI,SAAS,UAAU,EAAG,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAG5F;AAGD,OAAO,WAAW,KAAK,CAAC;IACf,IAAI,SAAS,EAAE,OAAO,UAAU,CAAC;IACjC,IAAI,UAAU,EAAE,OAAO,WAAW,CAAC;IACnC,IAAI,MAAM,EAAE,OAAO,OAAO,CAAC;IAC3B,IAAI,aAAa,EAAE,OAAO,cAAc,CAAC;IACzC,IAAI,WAAW,EAAE,OAAO,YAAY,CAAC;IACrC,IAAI,UAAU,EAAE,OAAO,WAAW,CAAC;IACnC,IAAI,aAAa,EAAE,OAAO,cAAc,CAAC;IACzC,IAAI,UAAU,EAAE,OAAO,WAAW,CAAC;IACnC,IAAI,WAAW,EAAE,OAAO,YAAY,CAAC;IACrC,IAAI,YAAY,EAAE,OAAO,aAAa,CAAC;IACvC,IAAI,cAAc,EAAE,OAAO,eAAe,CAAC;IAC3C,IAAI,YAAY,EAAE,OAAO,aAAa,CAAC;IACvC,IAAI,aAAa,EAAE,OAAO,cAAc,CAAC;IACzC,IAAI,WAAW,EAAE,OAAO,YAAY,CAAC;IACrC,IAAI,eAAe,EAAE,OAAO,gBAAgB,CAAC;IAC7C,IAAI,8BAA8B,EAAE,OAAO,+BAA+B,CAAC;IAC3E,IAAI,UAAU,EAAE,OAAO,WAAW,CAAC;IACnC,IAAI,IAAI,EAAE,OAAO,KAAK,CAAC;IACvB,IAAI,SAAS,EAAE,OAAO,UAAU,CAAC;CACzC;AAED,eAAe,KAAK,CAAC"}

View file

@ -0,0 +1,7 @@
/** Applies mask on element */
function IMask(el, opts) {
// currently available only for input-like elements
return new IMask.InputMask(el, opts);
}
export { IMask as default };

View file

@ -0,0 +1,21 @@
import type { AppendFlags } from '../masked/base';
import type ChangeDetails from './change-details';
export interface AppendTail {
append(str: string, flags?: AppendFlags): ChangeDetails;
_appendPlaceholder(): ChangeDetails;
}
/** Provides details of extracted tail */
export interface TailDetails {
/** Tail start position */
from: number;
/** Start position */
stop?: number;
/** */
state: any;
toString(): string;
extend(value: string | TailDetails): void;
appendTo(masked: AppendTail): ChangeDetails;
unshift(beforePos?: number): string;
shift(): string;
}
//# sourceMappingURL=tail-details.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"tail-details.d.ts","sourceRoot":"","sources":["../../src/core/tail-details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,aAAa,MAAM,kBAAkB,CAAC;AAGlD,MAAM,WACI,UAAU;IAClB,MAAM,CAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;IACzD,kBAAkB,IAAK,aAAa,CAAC;CACtC;AAED,yCAAyC;AACzC,MAAM,WACI,WAAW;IACnB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM;IACN,KAAK,EAAE,GAAG,CAAC;IAEX,QAAQ,IAAK,MAAM,CAAC;IACpB,MAAM,CAAE,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAE,MAAM,EAAE,UAAU,GAAG,aAAa,CAAC;IAC7C,OAAO,CAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,KAAK,IAAK,MAAM,CAAC;CAClB"}

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,25 @@
/** Checks if value is string */
export declare function isString(str: unknown): str is string;
/** Checks if value is object */
export declare function isObject(obj: unknown): obj is object;
export declare function pick<T extends Record<string, any>, K extends keyof T, V extends T[keyof T]>(obj: T, keys: K[] | ((v: V, k: K) => boolean)): Pick<T, K>;
/** Direction */
export declare const DIRECTION: {
readonly NONE: "NONE";
readonly LEFT: "LEFT";
readonly FORCE_LEFT: "FORCE_LEFT";
readonly RIGHT: "RIGHT";
readonly FORCE_RIGHT: "FORCE_RIGHT";
};
/** Direction */
export type Direction = typeof DIRECTION[keyof typeof DIRECTION];
export declare function forceDirection(direction: Direction): Direction;
/** Escapes regular expression control chars */
export declare function escapeRegExp(str: string): string;
export declare function objectIncludes(b: any, a: any): boolean;
/** Selection range */
export type Selection = {
start: number;
end: number;
};
//# sourceMappingURL=utils.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/core/utils.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,wBACS,QAAQ,CAAE,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAE9C;AAED,gCAAgC;AAChC,wBACS,QAAQ,CAAE,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAE9C;AAED,wBACS,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,EAClF,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,GACpC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAOZ;AAED,gBAAgB;AAChB,eACA,MAAM,SAAS;;;;;;CAML,CAAC;AAEX,gBAAgB;AAChB,MAAM,MACD,SAAS,GAAG,OAAO,SAAS,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAE1D,wBACS,cAAc,CAAE,SAAS,EAAE,SAAS,GAAG,SAAS,CASxD;AAED,+CAA+C;AAC/C,wBACS,YAAY,CAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1C;AAGD,wBACS,cAAc,CAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAuChD;AAED,sBAAsB;AACtB,MAAM,MACD,SAAS,GAAG;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb,CAAC"}

View file

@ -0,0 +1,82 @@
/** Checks if value is string */
function isString(str) {
return typeof str === 'string' || str instanceof String;
}
/** Checks if value is object */
function isObject(obj) {
var _obj$constructor;
return typeof obj === 'object' && obj != null && (obj == null || (_obj$constructor = obj.constructor) == null ? void 0 : _obj$constructor.name) === 'Object';
}
function pick(obj, keys) {
if (Array.isArray(keys)) return pick(obj, (_, k) => keys.includes(k));
return Object.entries(obj).reduce((acc, _ref) => {
let [k, v] = _ref;
if (keys(v, k)) acc[k] = v;
return acc;
}, {});
}
/** Direction */
const DIRECTION = {
NONE: 'NONE',
LEFT: 'LEFT',
FORCE_LEFT: 'FORCE_LEFT',
RIGHT: 'RIGHT',
FORCE_RIGHT: 'FORCE_RIGHT'
};
/** Direction */
function forceDirection(direction) {
switch (direction) {
case DIRECTION.LEFT:
return DIRECTION.FORCE_LEFT;
case DIRECTION.RIGHT:
return DIRECTION.FORCE_RIGHT;
default:
return direction;
}
}
/** Escapes regular expression control chars */
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1');
}
// cloned from https://github.com/epoberezkin/fast-deep-equal with small changes
function objectIncludes(b, a) {
if (a === b) return true;
const arrA = Array.isArray(a),
arrB = Array.isArray(b);
let i;
if (arrA && arrB) {
if (a.length != b.length) return false;
for (i = 0; i < a.length; i++) if (!objectIncludes(a[i], b[i])) return false;
return true;
}
if (arrA != arrB) return false;
if (a && b && typeof a === 'object' && typeof b === 'object') {
const dateA = a instanceof Date,
dateB = b instanceof Date;
if (dateA && dateB) return a.getTime() == b.getTime();
if (dateA != dateB) return false;
const regexpA = a instanceof RegExp,
regexpB = b instanceof RegExp;
if (regexpA && regexpB) return a.toString() == b.toString();
if (regexpA != regexpB) return false;
const keys = Object.keys(a);
// if (keys.length !== Object.keys(b).length) return false;
for (i = 0; i < keys.length; i++) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
for (i = 0; i < keys.length; i++) if (!objectIncludes(b[keys[i]], a[keys[i]])) return false;
return true;
} else if (a && b && typeof a === 'function' && typeof b === 'function') {
return a.toString() === b.toString();
}
return false;
}
/** Selection range */
export { DIRECTION, escapeRegExp, forceDirection, isObject, isString, objectIncludes, pick };

View file

@ -0,0 +1,4 @@
import './controls/input';
import IMask from './core/holder';
export default IMask;
//# sourceMappingURL=imask.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"imask.d.ts","sourceRoot":"","sources":["../src/imask.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,MAAM,eAAe,CAAC;AAClC,eAAe,KAAK,CAAC"}

View file

@ -0,0 +1,14 @@
import './controls/input.js';
import IMask from './core/holder.js';
import './core/utils.js';
import './core/action-details.js';
import './masked/factory.js';
import './controls/mask-element.js';
import './controls/html-input-mask-element.js';
import './controls/html-mask-element.js';
import './controls/html-contenteditable-mask-element.js';
import './controls/input-history.js';
export { IMask as default };

View file

@ -0,0 +1,27 @@
import IMask from './imask';
export { default as HTMLContenteditableMaskElement } from './controls/html-contenteditable-mask-element';
export { default as HTMLInputMaskElement, type InputElement } from './controls/html-input-mask-element';
export { default as HTMLMaskElement } from './controls/html-mask-element';
export { default as InputMask, type InputMaskElement } from './controls/input';
export { default as MaskElement } from './controls/mask-element';
export { default as ChangeDetails, type ChangeDetailsOptions } from './core/change-details';
export { type AppendTail, type TailDetails } from './core/tail-details';
export { DIRECTION, forceDirection, type Direction, type Selection } from './core/utils';
export { default as Masked, type AppendFlags, type ExtractFlags, type MaskedOptions, type MaskedState } from './masked/base';
export { default as MaskedDate, type DateMaskType, type MaskedDateOptions } from './masked/date';
export { default as MaskedDynamic, type DynamicMaskType, type MaskedDynamicOptions, type MaskedDynamicState } from './masked/dynamic';
export { default as MaskedEnum, type MaskedEnumOptions } from './masked/enum';
export { default as createMask, normalizeOpts, type AllFactoryStaticOpts, type FactoryArg, type FactoryConstructorOpts, type FactoryConstructorReturnMasked, type FactoryInstanceOpts, type FactoryInstanceReturnMasked, type FactoryOpts, type FactoryReturnMasked, type FactoryStaticOpts, type FactoryStaticReturnMasked, type NormalizedOpts, type UpdateOpts, } from './masked/factory';
export { default as MaskedFunction, type MaskedFunctionOptions } from './masked/function';
export { default as MaskedNumber, type MaskedNumberOptions } from './masked/number';
export { default as MaskedPattern, type BlockPosData, type Definitions, type MaskedPatternOptions, type MaskedPatternState } from './masked/pattern';
export { type default as PatternBlock } from './masked/pattern/block';
export { default as ChunksTailDetails, type ChunksTailState } from './masked/pattern/chunk-tail-details';
export { default as PatternFixedDefinition, type PatternFixedDefinitionOptions } from './masked/pattern/fixed-definition';
export { default as PatternInputDefinition, type PatternInputDefinitionOptions, type PatternInputDefinitionState } from './masked/pattern/input-definition';
export { createPipe, pipe, PIPE_TYPE } from './masked/pipe';
export { default as MaskedRange, type MaskedRangeOptions } from './masked/range';
export { default as MaskedRegExp, type MaskedRegExpOptions } from './masked/regexp';
export { default as RepeatBlock, type RepeatBlockOptions } from './masked/repeat';
export default IMask;
//# sourceMappingURL=index.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,33 @@
export { default as InputMask } from './controls/input.js';
import IMask from './core/holder.js';
export { default as HTMLContenteditableMaskElement } from './controls/html-contenteditable-mask-element.js';
export { default as HTMLInputMaskElement } from './controls/html-input-mask-element.js';
export { default as HTMLMaskElement } from './controls/html-mask-element.js';
export { default as MaskElement } from './controls/mask-element.js';
export { default as ChangeDetails } from './core/change-details.js';
export { DIRECTION, forceDirection } from './core/utils.js';
export { default as Masked } from './masked/base.js';
export { default as MaskedDate } from './masked/date.js';
export { default as MaskedDynamic } from './masked/dynamic.js';
export { default as MaskedEnum } from './masked/enum.js';
export { default as createMask, normalizeOpts } from './masked/factory.js';
export { default as MaskedFunction } from './masked/function.js';
export { default as MaskedNumber } from './masked/number.js';
export { default as MaskedPattern } from './masked/pattern.js';
export { default as ChunksTailDetails } from './masked/pattern/chunk-tail-details.js';
export { default as PatternFixedDefinition } from './masked/pattern/fixed-definition.js';
export { default as PatternInputDefinition } from './masked/pattern/input-definition.js';
export { PIPE_TYPE, createPipe, pipe } from './masked/pipe.js';
export { default as MaskedRange } from './masked/range.js';
export { default as MaskedRegExp } from './masked/regexp.js';
export { default as RepeatBlock } from './masked/repeat.js';
import './core/action-details.js';
import './controls/input-history.js';
import './core/continuous-tail-details.js';
import './masked/pattern/cursor.js';
try {
globalThis.IMask = IMask;
} catch {}
export { IMask as default };

View file

@ -0,0 +1,115 @@
import ChangeDetails from '../core/change-details';
import { type Direction } from '../core/utils';
import { type TailDetails } from '../core/tail-details';
export type MaskedState = {
_value: string;
_rawInputValue: string;
};
/** Append flags */
export type AppendFlags<State = MaskedState> = {
input?: boolean;
tail?: boolean;
raw?: boolean;
_beforeTailState?: State;
};
/** Extract flags */
export type ExtractFlags = {
raw?: boolean;
};
export type MaskedOptions<M extends Masked = Masked, Props extends keyof M = never> = Partial<Pick<M, 'mask' | 'parent' | 'prepare' | 'prepareChar' | 'validate' | 'commit' | 'format' | 'parse' | 'overwrite' | 'eager' | 'skipInvalid' | 'autofix' | Props>>;
/** Provides common masking stuff */
export default abstract class Masked<Value = any> {
static DEFAULTS: Pick<MaskedOptions, 'skipInvalid'>;
static EMPTY_VALUES: Array<any>;
/** */
mask: unknown;
/** */
parent?: Masked;
/** Transforms value before mask processing */
prepare?: (chars: string, masked: Masked, flags: AppendFlags) => string | [string, ChangeDetails];
/** Transforms each char before mask processing */
prepareChar?: (chars: string, masked: Masked, flags: AppendFlags) => string | [string, ChangeDetails];
/** Validates if value is acceptable */
validate?: (value: string, masked: Masked, flags: AppendFlags) => boolean;
/** Does additional processing at the end of editing */
commit?: (value: string, masked: Masked) => void;
/** Format typed value to string */
format?: (value: Value, masked: Masked) => string;
/** Parse string to get typed value */
parse?: (str: string, masked: Masked) => Value;
/** Enable characters overwriting */
abstract overwrite?: boolean | 'shift' | undefined;
/** */
abstract eager?: boolean | 'remove' | 'append' | undefined;
/** */
abstract skipInvalid?: boolean | undefined;
/** */
abstract autofix?: boolean | 'pad' | undefined;
/** */
_initialized: boolean;
_value: string;
_refreshing?: boolean;
_isolated?: boolean;
constructor(opts: MaskedOptions);
/** Sets and applies new options */
updateOptions(opts: Partial<MaskedOptions>): void;
/** Sets new options */
_update(opts: Partial<MaskedOptions>): void;
/** Mask state */
get state(): MaskedState;
set state(state: MaskedState);
/** Resets value */
reset(): void;
get value(): string;
set value(value: string);
/** Resolve new value */
resolve(value: string, flags?: AppendFlags): void;
get unmaskedValue(): string;
set unmaskedValue(value: string);
get typedValue(): Value;
set typedValue(value: Value);
/** Value that includes raw user input */
get rawInputValue(): string;
set rawInputValue(value: string);
get displayValue(): string;
get isComplete(): boolean;
get isFilled(): boolean;
/** Finds nearest input position in direction */
nearestInputPos(cursorPos: number, direction?: Direction): number;
totalInputPositions(fromPos?: number, toPos?: number): number;
/** Extracts value in range considering flags */
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
/** Extracts tail in range */
extractTail(fromPos?: number, toPos?: number): TailDetails;
/** Appends tail */
appendTail(tail: string | String | TailDetails): ChangeDetails;
/** Appends char */
_appendCharRaw(ch: string, flags?: AppendFlags): ChangeDetails;
/** Appends char */
_appendChar(ch: string, flags?: AppendFlags, checkTail?: TailDetails): ChangeDetails;
/** Appends optional placeholder at the end */
_appendPlaceholder(): ChangeDetails;
/** Appends optional eager placeholder at the end */
_appendEager(): ChangeDetails;
/** Appends symbols considering flags */
append(str: string, flags?: AppendFlags, tail?: string | String | TailDetails): ChangeDetails;
remove(fromPos?: number, toPos?: number): ChangeDetails;
/** Calls function and reapplies current value */
withValueRefresh<T>(fn: () => T): T;
runIsolated<T>(fn: (masked: this) => T): T;
doSkipInvalid(ch: string, flags?: AppendFlags, checkTail?: TailDetails): boolean;
/** Prepares string before mask processing */
doPrepare(str: string, flags?: AppendFlags): [string, ChangeDetails];
/** Prepares each char before mask processing */
doPrepareChar(str: string, flags?: AppendFlags): [string, ChangeDetails];
/** Validates if value is acceptable */
doValidate(flags: AppendFlags): boolean;
/** Does additional processing at the end of editing */
doCommit(): void;
splice(start: number, deleteCount: number, inserted?: string, removeDirection?: Direction, flags?: AppendFlags): ChangeDetails;
maskEquals(mask: any): boolean;
optionsIsChanged(opts: Partial<MaskedOptions>): boolean;
typedValueEquals(value: any): boolean;
pad(flags?: AppendFlags): ChangeDetails;
}
//# sourceMappingURL=base.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/masked/base.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,422 @@
import ChangeDetails from '../core/change-details.js';
import ContinuousTailDetails from '../core/continuous-tail-details.js';
import { isString, DIRECTION, objectIncludes, forceDirection } from '../core/utils.js';
import IMask from '../core/holder.js';
/** Append flags */
/** Extract flags */
// see https://github.com/microsoft/TypeScript/issues/6223
/** Provides common masking stuff */
class Masked {
/** */
/** */
/** Transforms value before mask processing */
/** Transforms each char before mask processing */
/** Validates if value is acceptable */
/** Does additional processing at the end of editing */
/** Format typed value to string */
/** Parse string to get typed value */
/** Enable characters overwriting */
/** */
/** */
/** */
/** */
constructor(opts) {
this._value = '';
this._update({
...Masked.DEFAULTS,
...opts
});
this._initialized = true;
}
/** Sets and applies new options */
updateOptions(opts) {
if (!this.optionsIsChanged(opts)) return;
this.withValueRefresh(this._update.bind(this, opts));
}
/** Sets new options */
_update(opts) {
Object.assign(this, opts);
}
/** Mask state */
get state() {
return {
_value: this.value,
_rawInputValue: this.rawInputValue
};
}
set state(state) {
this._value = state._value;
}
/** Resets value */
reset() {
this._value = '';
}
get value() {
return this._value;
}
set value(value) {
this.resolve(value, {
input: true
});
}
/** Resolve new value */
resolve(value, flags) {
if (flags === void 0) {
flags = {
input: true
};
}
this.reset();
this.append(value, flags, '');
this.doCommit();
}
get unmaskedValue() {
return this.value;
}
set unmaskedValue(value) {
this.resolve(value, {});
}
get typedValue() {
return this.parse ? this.parse(this.value, this) : this.unmaskedValue;
}
set typedValue(value) {
if (this.format) {
this.value = this.format(value, this);
} else {
this.unmaskedValue = String(value);
}
}
/** Value that includes raw user input */
get rawInputValue() {
return this.extractInput(0, this.displayValue.length, {
raw: true
});
}
set rawInputValue(value) {
this.resolve(value, {
raw: true
});
}
get displayValue() {
return this.value;
}
get isComplete() {
return true;
}
get isFilled() {
return this.isComplete;
}
/** Finds nearest input position in direction */
nearestInputPos(cursorPos, direction) {
return cursorPos;
}
totalInputPositions(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
return Math.min(this.displayValue.length, toPos - fromPos);
}
/** Extracts value in range considering flags */
extractInput(fromPos, toPos, flags) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
return this.displayValue.slice(fromPos, toPos);
}
/** Extracts tail in range */
extractTail(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
return new ContinuousTailDetails(this.extractInput(fromPos, toPos), fromPos);
}
/** Appends tail */
appendTail(tail) {
if (isString(tail)) tail = new ContinuousTailDetails(String(tail));
return tail.appendTo(this);
}
/** Appends char */
_appendCharRaw(ch, flags) {
if (!ch) return new ChangeDetails();
this._value += ch;
return new ChangeDetails({
inserted: ch,
rawInserted: ch
});
}
/** Appends char */
_appendChar(ch, flags, checkTail) {
if (flags === void 0) {
flags = {};
}
const consistentState = this.state;
let details;
[ch, details] = this.doPrepareChar(ch, flags);
if (ch) {
details = details.aggregate(this._appendCharRaw(ch, flags));
// TODO handle `skip`?
// try `autofix` lookahead
if (!details.rawInserted && this.autofix === 'pad') {
const noFixState = this.state;
this.state = consistentState;
let fixDetails = this.pad(flags);
const chDetails = this._appendCharRaw(ch, flags);
fixDetails = fixDetails.aggregate(chDetails);
// if fix was applied or
// if details are equal use skip restoring state optimization
if (chDetails.rawInserted || fixDetails.equals(details)) {
details = fixDetails;
} else {
this.state = noFixState;
}
}
}
if (details.inserted) {
let consistentTail;
let appended = this.doValidate(flags) !== false;
if (appended && checkTail != null) {
// validation ok, check tail
const beforeTailState = this.state;
if (this.overwrite === true) {
consistentTail = checkTail.state;
for (let i = 0; i < details.rawInserted.length; ++i) {
checkTail.unshift(this.displayValue.length - details.tailShift);
}
}
let tailDetails = this.appendTail(checkTail);
appended = tailDetails.rawInserted.length === checkTail.toString().length;
// not ok, try shift
if (!(appended && tailDetails.inserted) && this.overwrite === 'shift') {
this.state = beforeTailState;
consistentTail = checkTail.state;
for (let i = 0; i < details.rawInserted.length; ++i) {
checkTail.shift();
}
tailDetails = this.appendTail(checkTail);
appended = tailDetails.rawInserted.length === checkTail.toString().length;
}
// if ok, rollback state after tail
if (appended && tailDetails.inserted) this.state = beforeTailState;
}
// revert all if something went wrong
if (!appended) {
details = new ChangeDetails();
this.state = consistentState;
if (checkTail && consistentTail) checkTail.state = consistentTail;
}
}
return details;
}
/** Appends optional placeholder at the end */
_appendPlaceholder() {
return new ChangeDetails();
}
/** Appends optional eager placeholder at the end */
_appendEager() {
return new ChangeDetails();
}
/** Appends symbols considering flags */
append(str, flags, tail) {
if (!isString(str)) throw new Error('value should be string');
const checkTail = isString(tail) ? new ContinuousTailDetails(String(tail)) : tail;
if (flags != null && flags.tail) flags._beforeTailState = this.state;
let details;
[str, details] = this.doPrepare(str, flags);
for (let ci = 0; ci < str.length; ++ci) {
const d = this._appendChar(str[ci], flags, checkTail);
if (!d.rawInserted && !this.doSkipInvalid(str[ci], flags, checkTail)) break;
details.aggregate(d);
}
if ((this.eager === true || this.eager === 'append') && flags != null && flags.input && str) {
details.aggregate(this._appendEager());
}
// append tail but aggregate only tailShift
if (checkTail != null) {
details.tailShift += this.appendTail(checkTail).tailShift;
// TODO it's a good idea to clear state after appending ends
// but it causes bugs when one append calls another (when dynamic dispatch set rawInputValue)
// this._resetBeforeTailState();
}
return details;
}
remove(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
this._value = this.displayValue.slice(0, fromPos) + this.displayValue.slice(toPos);
return new ChangeDetails();
}
/** Calls function and reapplies current value */
withValueRefresh(fn) {
if (this._refreshing || !this._initialized) return fn();
this._refreshing = true;
const rawInput = this.rawInputValue;
const value = this.value;
const ret = fn();
this.rawInputValue = rawInput;
// append lost trailing chars at the end
if (this.value && this.value !== value && value.indexOf(this.value) === 0) {
this.append(value.slice(this.displayValue.length), {}, '');
this.doCommit();
}
delete this._refreshing;
return ret;
}
runIsolated(fn) {
if (this._isolated || !this._initialized) return fn(this);
this._isolated = true;
const state = this.state;
const ret = fn(this);
this.state = state;
delete this._isolated;
return ret;
}
doSkipInvalid(ch, flags, checkTail) {
return Boolean(this.skipInvalid);
}
/** Prepares string before mask processing */
doPrepare(str, flags) {
if (flags === void 0) {
flags = {};
}
return ChangeDetails.normalize(this.prepare ? this.prepare(str, this, flags) : str);
}
/** Prepares each char before mask processing */
doPrepareChar(str, flags) {
if (flags === void 0) {
flags = {};
}
return ChangeDetails.normalize(this.prepareChar ? this.prepareChar(str, this, flags) : str);
}
/** Validates if value is acceptable */
doValidate(flags) {
return (!this.validate || this.validate(this.value, this, flags)) && (!this.parent || this.parent.doValidate(flags));
}
/** Does additional processing at the end of editing */
doCommit() {
if (this.commit) this.commit(this.value, this);
}
splice(start, deleteCount, inserted, removeDirection, flags) {
if (inserted === void 0) {
inserted = '';
}
if (removeDirection === void 0) {
removeDirection = DIRECTION.NONE;
}
if (flags === void 0) {
flags = {
input: true
};
}
const tailPos = start + deleteCount;
const tail = this.extractTail(tailPos);
const eagerRemove = this.eager === true || this.eager === 'remove';
let oldRawValue;
if (eagerRemove) {
removeDirection = forceDirection(removeDirection);
oldRawValue = this.extractInput(0, tailPos, {
raw: true
});
}
let startChangePos = start;
const details = new ChangeDetails();
// if it is just deletion without insertion
if (removeDirection !== DIRECTION.NONE) {
startChangePos = this.nearestInputPos(start, deleteCount > 1 && start !== 0 && !eagerRemove ? DIRECTION.NONE : removeDirection);
// adjust tailShift if start was aligned
details.tailShift = startChangePos - start;
}
details.aggregate(this.remove(startChangePos));
if (eagerRemove && removeDirection !== DIRECTION.NONE && oldRawValue === this.rawInputValue) {
if (removeDirection === DIRECTION.FORCE_LEFT) {
let valLength;
while (oldRawValue === this.rawInputValue && (valLength = this.displayValue.length)) {
details.aggregate(new ChangeDetails({
tailShift: -1
})).aggregate(this.remove(valLength - 1));
}
} else if (removeDirection === DIRECTION.FORCE_RIGHT) {
tail.unshift();
}
}
return details.aggregate(this.append(inserted, flags, tail));
}
maskEquals(mask) {
return this.mask === mask;
}
optionsIsChanged(opts) {
return !objectIncludes(this, opts);
}
typedValueEquals(value) {
const tval = this.typedValue;
return value === tval || Masked.EMPTY_VALUES.includes(value) && Masked.EMPTY_VALUES.includes(tval) || (this.format ? this.format(value, this) === this.format(this.typedValue, this) : false);
}
pad(flags) {
return new ChangeDetails();
}
}
Masked.DEFAULTS = {
skipInvalid: true
};
Masked.EMPTY_VALUES = [undefined, null, ''];
IMask.Masked = Masked;
export { Masked as default };

View file

@ -0,0 +1,63 @@
import MaskedPattern, { type MaskedPatternOptions } from './pattern';
import { type MaskedRangeOptions } from './range';
import type Masked from './base';
import { type AppendFlags } from './base';
export type DateMaskType = DateConstructor;
type DateOptionsKeys = 'pattern' | 'min' | 'max' | 'autofix';
export type DateValue = Date | null;
declare const DefaultPattern = "d{.}`m{.}`Y";
type RequiredDateOptions = ({
pattern?: never | typeof DefaultPattern;
format?: MaskedDate["format"];
parse?: MaskedDate["parse"];
} | {
pattern: MaskedDate["pattern"];
format: MaskedDate["format"];
parse: MaskedDate["parse"];
});
export type MaskedDateOptions = Omit<MaskedPatternOptions<DateValue>, 'mask'> & Partial<Pick<MaskedDate, DateOptionsKeys>> & {
mask?: string | DateMaskType;
} & RequiredDateOptions;
/** Date mask */
export default class MaskedDate extends MaskedPattern<DateValue> {
static GET_DEFAULT_BLOCKS: () => {
[k: string]: MaskedRangeOptions;
};
static DEFAULTS: {
mask: DateConstructor;
pattern: "d{.}`m{.}`Y";
format: (date: DateValue, masked: Masked) => string;
parse: (str: string, masked: Masked) => DateValue;
lazy: boolean;
placeholderChar: string;
skipInvalid?: boolean | undefined;
};
static extractPatternOptions(opts: Partial<MaskedDateOptions>): Partial<Omit<MaskedDateOptions, 'mask' | 'pattern'> & {
mask: MaskedPatternOptions['mask'];
}>;
/** Pattern mask for date according to {@link MaskedDate#format} */
pattern: string;
/** Start date */
min?: Date;
/** End date */
max?: Date;
/** Format typed value to string */
format: (value: DateValue, masked: Masked) => string;
/** Parse string to get typed value */
parse: (str: string, masked: Masked) => DateValue;
constructor(opts?: MaskedDateOptions);
updateOptions(opts: Partial<MaskedDateOptions> & RequiredDateOptions): void;
_update(opts: Partial<MaskedDateOptions>): void;
doValidate(flags: AppendFlags): boolean;
/** Checks if date is exists */
isDateExist(str: string): boolean;
/** Parsed Date */
get date(): DateValue;
set date(date: DateValue);
get typedValue(): DateValue;
set typedValue(value: DateValue);
maskEquals(mask: any): boolean;
optionsIsChanged(opts: Partial<MaskedDateOptions>): boolean;
}
export {};
//# sourceMappingURL=date.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/masked/date.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,148 @@
import MaskedPattern from './pattern.js';
import MaskedRange from './range.js';
import IMask from '../core/holder.js';
import { isString } from '../core/utils.js';
import '../core/change-details.js';
import './base.js';
import '../core/continuous-tail-details.js';
import './factory.js';
import './pattern/chunk-tail-details.js';
import './pattern/cursor.js';
import './pattern/fixed-definition.js';
import './pattern/input-definition.js';
import './regexp.js';
const DefaultPattern = 'd{.}`m{.}`Y';
// Make format and parse required when pattern is provided
/** Date mask */
class MaskedDate extends MaskedPattern {
static extractPatternOptions(opts) {
const {
mask,
pattern,
...patternOpts
} = opts;
return {
...patternOpts,
mask: isString(mask) ? mask : pattern
};
}
/** Pattern mask for date according to {@link MaskedDate#format} */
/** Start date */
/** End date */
/** Format typed value to string */
/** Parse string to get typed value */
constructor(opts) {
super(MaskedDate.extractPatternOptions({
...MaskedDate.DEFAULTS,
...opts
}));
}
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
const {
mask,
pattern,
blocks,
...patternOpts
} = {
...MaskedDate.DEFAULTS,
...opts
};
const patternBlocks = Object.assign({}, MaskedDate.GET_DEFAULT_BLOCKS());
// adjust year block
if (opts.min) patternBlocks.Y.from = opts.min.getFullYear();
if (opts.max) patternBlocks.Y.to = opts.max.getFullYear();
if (opts.min && opts.max && patternBlocks.Y.from === patternBlocks.Y.to) {
patternBlocks.m.from = opts.min.getMonth() + 1;
patternBlocks.m.to = opts.max.getMonth() + 1;
if (patternBlocks.m.from === patternBlocks.m.to) {
patternBlocks.d.from = opts.min.getDate();
patternBlocks.d.to = opts.max.getDate();
}
}
Object.assign(patternBlocks, this.blocks, blocks);
super._update({
...patternOpts,
mask: isString(mask) ? mask : pattern,
blocks: patternBlocks
});
}
doValidate(flags) {
const date = this.date;
return super.doValidate(flags) && (!this.isComplete || this.isDateExist(this.value) && date != null && (this.min == null || this.min <= date) && (this.max == null || date <= this.max));
}
/** Checks if date is exists */
isDateExist(str) {
return this.format(this.parse(str, this), this).indexOf(str) >= 0;
}
/** Parsed Date */
get date() {
return this.typedValue;
}
set date(date) {
this.typedValue = date;
}
get typedValue() {
return this.isComplete ? super.typedValue : null;
}
set typedValue(value) {
super.typedValue = value;
}
maskEquals(mask) {
return mask === Date || super.maskEquals(mask);
}
optionsIsChanged(opts) {
return super.optionsIsChanged(MaskedDate.extractPatternOptions(opts));
}
}
MaskedDate.GET_DEFAULT_BLOCKS = () => ({
d: {
mask: MaskedRange,
from: 1,
to: 31,
maxLength: 2
},
m: {
mask: MaskedRange,
from: 1,
to: 12,
maxLength: 2
},
Y: {
mask: MaskedRange,
from: 1900,
to: 9999
}
});
MaskedDate.DEFAULTS = {
...MaskedPattern.DEFAULTS,
mask: Date,
pattern: DefaultPattern,
format: (date, masked) => {
if (!date) return '';
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0');
const year = date.getFullYear();
return [day, month, year].join('.');
},
parse: (str, masked) => {
const [day, month, year] = str.split('.').map(Number);
return new Date(year, month - 1, day);
}
};
IMask.MaskedDate = MaskedDate;
export { MaskedDate as default };

View file

@ -0,0 +1,77 @@
import ChangeDetails from '../core/change-details';
import { type ExtendFactoryArgOptions } from './factory';
import Masked, { type AppendFlags, type MaskedState, type MaskedOptions, type ExtractFlags } from './base';
import { type Direction } from '../core/utils';
import { type TailDetails } from '../core/tail-details';
type MaskedDynamicNoRefState = MaskedState & {
compiledMasks: Array<MaskedState>;
};
type MaskedDynamicRefState = MaskedDynamicNoRefState & {
currentMaskRef: Masked;
currentMask: MaskedState;
};
export type MaskedDynamicState = MaskedDynamicNoRefState | MaskedDynamicRefState;
export type DynamicMaskType = Array<ExtendFactoryArgOptions<{
expose?: boolean;
}>> | ArrayConstructor;
export type MaskedDynamicOptions = MaskedOptions<MaskedDynamic, 'dispatch'>;
type HandleState = MaskedDynamicState | MaskedState;
/** Dynamic mask for choosing appropriate mask in run-time */
export default class MaskedDynamic<Value = any> extends Masked<Value> {
mask: DynamicMaskType;
/** Currently chosen mask */
currentMask?: Masked;
/** Currently chosen mask */
exposeMask?: Masked;
/** Compliled {@link Masked} options */
compiledMasks: Array<Masked>;
/** Chooses {@link Masked} depending on input value */
dispatch: (appended: string, masked: MaskedDynamic, flags: AppendFlags<HandleState>, tail: string | String | TailDetails) => (Masked | undefined);
_overwrite?: this['overwrite'];
_eager?: this['eager'];
_skipInvalid?: this['skipInvalid'];
_autofix?: this['autofix'];
static DEFAULTS: typeof Masked.DEFAULTS & Pick<MaskedDynamic, 'dispatch'>;
constructor(opts?: MaskedDynamicOptions);
updateOptions(opts: Partial<MaskedDynamicOptions>): void;
_update(opts: Partial<MaskedDynamicOptions>): void;
_appendCharRaw(ch: string, flags?: AppendFlags<HandleState>): ChangeDetails;
_applyDispatch(appended?: string, flags?: AppendFlags<HandleState>, tail?: string | String | TailDetails): ChangeDetails;
_appendPlaceholder(): ChangeDetails;
_appendEager(): ChangeDetails;
appendTail(tail: string | String | TailDetails): ChangeDetails;
currentMaskFlags(flags: AppendFlags<HandleState>): AppendFlags;
doDispatch(appended: string, flags?: AppendFlags<HandleState>, tail?: string | String | TailDetails): Masked | undefined;
doValidate(flags: AppendFlags<HandleState>): boolean;
doPrepare(str: string, flags?: AppendFlags<HandleState>): [string, ChangeDetails];
doPrepareChar(str: string, flags?: AppendFlags<HandleState>): [string, ChangeDetails];
reset(): void;
get value(): string;
set value(value: string);
get unmaskedValue(): string;
set unmaskedValue(unmaskedValue: string);
get typedValue(): Value;
set typedValue(typedValue: Value);
get displayValue(): string;
get isComplete(): boolean;
get isFilled(): boolean;
remove(fromPos?: number, toPos?: number): ChangeDetails;
get state(): MaskedDynamicState;
set state(state: HandleState);
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
extractTail(fromPos?: number, toPos?: number): TailDetails;
doCommit(): void;
nearestInputPos(cursorPos: number, direction?: Direction): number;
get overwrite(): boolean | 'shift' | undefined;
set overwrite(overwrite: boolean | 'shift' | undefined);
get eager(): boolean | 'remove' | 'append' | undefined;
set eager(eager: boolean | 'remove' | 'append' | undefined);
get skipInvalid(): boolean | undefined;
set skipInvalid(skipInvalid: boolean | undefined);
get autofix(): boolean | 'pad' | undefined;
set autofix(autofix: boolean | 'pad' | undefined);
maskEquals(mask: any): boolean;
typedValueEquals(value: any): boolean;
}
export {};
//# sourceMappingURL=dynamic.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"dynamic.d.ts","sourceRoot":"","sources":["../../src/masked/dynamic.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,341 @@
import { DIRECTION, objectIncludes } from '../core/utils.js';
import ChangeDetails from '../core/change-details.js';
import createMask, { normalizeOpts } from './factory.js';
import Masked from './base.js';
import IMask from '../core/holder.js';
import '../core/continuous-tail-details.js';
/** Dynamic mask for choosing appropriate mask in run-time */
class MaskedDynamic extends Masked {
constructor(opts) {
super({
...MaskedDynamic.DEFAULTS,
...opts
});
this.currentMask = undefined;
}
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
super._update(opts);
if ('mask' in opts) {
this.exposeMask = undefined;
// mask could be totally dynamic with only `dispatch` option
this.compiledMasks = Array.isArray(opts.mask) ? opts.mask.map(m => {
const {
expose,
...maskOpts
} = normalizeOpts(m);
const masked = createMask({
overwrite: this._overwrite,
eager: this._eager,
skipInvalid: this._skipInvalid,
...maskOpts
});
if (expose) this.exposeMask = masked;
return masked;
}) : [];
// this.currentMask = this.doDispatch(''); // probably not needed but lets see
}
}
_appendCharRaw(ch, flags) {
if (flags === void 0) {
flags = {};
}
const details = this._applyDispatch(ch, flags);
if (this.currentMask) {
details.aggregate(this.currentMask._appendChar(ch, this.currentMaskFlags(flags)));
}
return details;
}
_applyDispatch(appended, flags, tail) {
if (appended === void 0) {
appended = '';
}
if (flags === void 0) {
flags = {};
}
if (tail === void 0) {
tail = '';
}
const prevValueBeforeTail = flags.tail && flags._beforeTailState != null ? flags._beforeTailState._value : this.value;
const inputValue = this.rawInputValue;
const insertValue = flags.tail && flags._beforeTailState != null ? flags._beforeTailState._rawInputValue : inputValue;
const tailValue = inputValue.slice(insertValue.length);
const prevMask = this.currentMask;
const details = new ChangeDetails();
const prevMaskState = prevMask == null ? void 0 : prevMask.state;
// clone flags to prevent overwriting `_beforeTailState`
this.currentMask = this.doDispatch(appended, {
...flags
}, tail);
// restore state after dispatch
if (this.currentMask) {
if (this.currentMask !== prevMask) {
// if mask changed reapply input
this.currentMask.reset();
if (insertValue) {
this.currentMask.append(insertValue, {
raw: true
});
details.tailShift = this.currentMask.value.length - prevValueBeforeTail.length;
}
if (tailValue) {
details.tailShift += this.currentMask.append(tailValue, {
raw: true,
tail: true
}).tailShift;
}
} else if (prevMaskState) {
// Dispatch can do something bad with state, so
// restore prev mask state
this.currentMask.state = prevMaskState;
}
}
return details;
}
_appendPlaceholder() {
const details = this._applyDispatch();
if (this.currentMask) {
details.aggregate(this.currentMask._appendPlaceholder());
}
return details;
}
_appendEager() {
const details = this._applyDispatch();
if (this.currentMask) {
details.aggregate(this.currentMask._appendEager());
}
return details;
}
appendTail(tail) {
const details = new ChangeDetails();
if (tail) details.aggregate(this._applyDispatch('', {}, tail));
return details.aggregate(this.currentMask ? this.currentMask.appendTail(tail) : super.appendTail(tail));
}
currentMaskFlags(flags) {
var _flags$_beforeTailSta, _flags$_beforeTailSta2;
return {
...flags,
_beforeTailState: ((_flags$_beforeTailSta = flags._beforeTailState) == null ? void 0 : _flags$_beforeTailSta.currentMaskRef) === this.currentMask && ((_flags$_beforeTailSta2 = flags._beforeTailState) == null ? void 0 : _flags$_beforeTailSta2.currentMask) || flags._beforeTailState
};
}
doDispatch(appended, flags, tail) {
if (flags === void 0) {
flags = {};
}
if (tail === void 0) {
tail = '';
}
return this.dispatch(appended, this, flags, tail);
}
doValidate(flags) {
return super.doValidate(flags) && (!this.currentMask || this.currentMask.doValidate(this.currentMaskFlags(flags)));
}
doPrepare(str, flags) {
if (flags === void 0) {
flags = {};
}
let [s, details] = super.doPrepare(str, flags);
if (this.currentMask) {
let currentDetails;
[s, currentDetails] = super.doPrepare(s, this.currentMaskFlags(flags));
details = details.aggregate(currentDetails);
}
return [s, details];
}
doPrepareChar(str, flags) {
if (flags === void 0) {
flags = {};
}
let [s, details] = super.doPrepareChar(str, flags);
if (this.currentMask) {
let currentDetails;
[s, currentDetails] = super.doPrepareChar(s, this.currentMaskFlags(flags));
details = details.aggregate(currentDetails);
}
return [s, details];
}
reset() {
var _this$currentMask;
(_this$currentMask = this.currentMask) == null || _this$currentMask.reset();
this.compiledMasks.forEach(m => m.reset());
}
get value() {
return this.exposeMask ? this.exposeMask.value : this.currentMask ? this.currentMask.value : '';
}
set value(value) {
if (this.exposeMask) {
this.exposeMask.value = value;
this.currentMask = this.exposeMask;
this._applyDispatch();
} else super.value = value;
}
get unmaskedValue() {
return this.exposeMask ? this.exposeMask.unmaskedValue : this.currentMask ? this.currentMask.unmaskedValue : '';
}
set unmaskedValue(unmaskedValue) {
if (this.exposeMask) {
this.exposeMask.unmaskedValue = unmaskedValue;
this.currentMask = this.exposeMask;
this._applyDispatch();
} else super.unmaskedValue = unmaskedValue;
}
get typedValue() {
return this.exposeMask ? this.exposeMask.typedValue : this.currentMask ? this.currentMask.typedValue : '';
}
set typedValue(typedValue) {
if (this.exposeMask) {
this.exposeMask.typedValue = typedValue;
this.currentMask = this.exposeMask;
this._applyDispatch();
return;
}
let unmaskedValue = String(typedValue);
// double check it
if (this.currentMask) {
this.currentMask.typedValue = typedValue;
unmaskedValue = this.currentMask.unmaskedValue;
}
this.unmaskedValue = unmaskedValue;
}
get displayValue() {
return this.currentMask ? this.currentMask.displayValue : '';
}
get isComplete() {
var _this$currentMask2;
return Boolean((_this$currentMask2 = this.currentMask) == null ? void 0 : _this$currentMask2.isComplete);
}
get isFilled() {
var _this$currentMask3;
return Boolean((_this$currentMask3 = this.currentMask) == null ? void 0 : _this$currentMask3.isFilled);
}
remove(fromPos, toPos) {
const details = new ChangeDetails();
if (this.currentMask) {
details.aggregate(this.currentMask.remove(fromPos, toPos))
// update with dispatch
.aggregate(this._applyDispatch());
}
return details;
}
get state() {
var _this$currentMask4;
return {
...super.state,
_rawInputValue: this.rawInputValue,
compiledMasks: this.compiledMasks.map(m => m.state),
currentMaskRef: this.currentMask,
currentMask: (_this$currentMask4 = this.currentMask) == null ? void 0 : _this$currentMask4.state
};
}
set state(state) {
const {
compiledMasks,
currentMaskRef,
currentMask,
...maskedState
} = state;
if (compiledMasks) this.compiledMasks.forEach((m, mi) => m.state = compiledMasks[mi]);
if (currentMaskRef != null) {
this.currentMask = currentMaskRef;
this.currentMask.state = currentMask;
}
super.state = maskedState;
}
extractInput(fromPos, toPos, flags) {
return this.currentMask ? this.currentMask.extractInput(fromPos, toPos, flags) : '';
}
extractTail(fromPos, toPos) {
return this.currentMask ? this.currentMask.extractTail(fromPos, toPos) : super.extractTail(fromPos, toPos);
}
doCommit() {
if (this.currentMask) this.currentMask.doCommit();
super.doCommit();
}
nearestInputPos(cursorPos, direction) {
return this.currentMask ? this.currentMask.nearestInputPos(cursorPos, direction) : super.nearestInputPos(cursorPos, direction);
}
get overwrite() {
return this.currentMask ? this.currentMask.overwrite : this._overwrite;
}
set overwrite(overwrite) {
this._overwrite = overwrite;
}
get eager() {
return this.currentMask ? this.currentMask.eager : this._eager;
}
set eager(eager) {
this._eager = eager;
}
get skipInvalid() {
return this.currentMask ? this.currentMask.skipInvalid : this._skipInvalid;
}
set skipInvalid(skipInvalid) {
this._skipInvalid = skipInvalid;
}
get autofix() {
return this.currentMask ? this.currentMask.autofix : this._autofix;
}
set autofix(autofix) {
this._autofix = autofix;
}
maskEquals(mask) {
return Array.isArray(mask) ? this.compiledMasks.every((m, mi) => {
if (!mask[mi]) return;
const {
mask: oldMask,
...restOpts
} = mask[mi];
return objectIncludes(m, restOpts) && m.maskEquals(oldMask);
}) : super.maskEquals(mask);
}
typedValueEquals(value) {
var _this$currentMask5;
return Boolean((_this$currentMask5 = this.currentMask) == null ? void 0 : _this$currentMask5.typedValueEquals(value));
}
}
/** Currently chosen mask */
/** Currently chosen mask */
/** Compliled {@link Masked} options */
/** Chooses {@link Masked} depending on input value */
MaskedDynamic.DEFAULTS = {
...Masked.DEFAULTS,
dispatch: (appended, masked, flags, tail) => {
if (!masked.compiledMasks.length) return;
const inputValue = masked.rawInputValue;
// simulate input
const inputs = masked.compiledMasks.map((m, index) => {
const isCurrent = masked.currentMask === m;
const startInputPos = isCurrent ? m.displayValue.length : m.nearestInputPos(m.displayValue.length, DIRECTION.FORCE_LEFT);
if (m.rawInputValue !== inputValue) {
m.reset();
m.append(inputValue, {
raw: true
});
} else if (!isCurrent) {
m.remove(startInputPos);
}
m.append(appended, masked.currentMaskFlags(flags));
m.appendTail(tail);
return {
index,
weight: m.rawInputValue.length,
totalInputPositions: m.totalInputPositions(0, Math.max(startInputPos, m.nearestInputPos(m.displayValue.length, DIRECTION.FORCE_LEFT)))
};
});
// pop masks with longer values first
inputs.sort((i1, i2) => i2.weight - i1.weight || i2.totalInputPositions - i1.totalInputPositions);
return masked.compiledMasks[inputs[0].index];
}
};
IMask.MaskedDynamic = MaskedDynamic;
export { MaskedDynamic as default };

View file

@ -0,0 +1,21 @@
import MaskedPattern, { MaskedPatternState, type MaskedPatternOptions } from './pattern';
import { AppendFlags } from './base';
import ChangeDetails from '../core/change-details';
import { TailDetails } from '../core/tail-details';
export type MaskedEnumOptions = Omit<MaskedPatternOptions, 'mask'> & Pick<MaskedEnum, 'enum'> & Partial<Pick<MaskedEnum, 'matchValue'>>;
export type MaskedEnumPatternOptions = MaskedPatternOptions & Partial<Pick<MaskedEnum, 'enum' | 'matchValue'>>;
/** Pattern which validates enum values */
export default class MaskedEnum extends MaskedPattern {
enum: Array<string>;
/** Match enum value */
matchValue: (enumStr: string, inputStr: string, matchFrom: number) => boolean;
static DEFAULTS: typeof MaskedPattern.DEFAULTS & Pick<MaskedEnum, 'matchValue'>;
constructor(opts?: MaskedEnumOptions);
updateOptions(opts: Partial<MaskedEnumOptions>): void;
_update(opts: Partial<MaskedEnumOptions>): void;
_appendCharRaw(ch: string, flags?: AppendFlags<MaskedPatternState>): ChangeDetails;
extractTail(fromPos?: number, toPos?: number): TailDetails;
remove(fromPos?: number, toPos?: number): ChangeDetails;
get isComplete(): boolean;
}
//# sourceMappingURL=enum.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"enum.d.ts","sourceRoot":"","sources":["../../src/masked/enum.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,EAAE,EAAE,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,aAAa,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAInD,MAAM,MACD,iBAAiB,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;AAEjI,MAAM,MACD,wBAAwB,GAAG,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC;AAGxG,0CAA0C;AAC1C,MAAM,CAAC,OAAO,OACR,UAAW,SAAQ,aAAa;IAC5B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,uBAAuB;IACf,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAEtF,MAAM,CAAC,QAAQ,EAAE,OAAO,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAG7E;gBAEW,IAAI,CAAC,EAAE,iBAAiB;IAO5B,aAAa,CAAE,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAI/C,OAAO,CAAE,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAiBzC,cAAc,CAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,WAAW,CAAC,kBAAkB,CAAI,GAAG,aAAa;IA4BrF,WAAW,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAA+B,GAAG,WAAW;IAKpF,MAAM,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAA+B,GAAG,aAAa;IAiB1F,IAAa,UAAU,IAAK,OAAO,CAElC;CACF"}

View file

@ -0,0 +1,104 @@
import MaskedPattern from './pattern.js';
import IMask from '../core/holder.js';
import ChangeDetails from '../core/change-details.js';
import { DIRECTION } from '../core/utils.js';
import ContinuousTailDetails from '../core/continuous-tail-details.js';
import './base.js';
import './factory.js';
import './pattern/chunk-tail-details.js';
import './pattern/cursor.js';
import './pattern/fixed-definition.js';
import './pattern/input-definition.js';
import './regexp.js';
/** Pattern which validates enum values */
class MaskedEnum extends MaskedPattern {
constructor(opts) {
super({
...MaskedEnum.DEFAULTS,
...opts
}); // mask will be created in _update
}
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
const {
enum: enum_,
...eopts
} = opts;
if (enum_) {
const lengths = enum_.map(e => e.length);
const requiredLength = Math.min(...lengths);
const optionalLength = Math.max(...lengths) - requiredLength;
eopts.mask = '*'.repeat(requiredLength);
if (optionalLength) eopts.mask += '[' + '*'.repeat(optionalLength) + ']';
this.enum = enum_;
}
super._update(eopts);
}
_appendCharRaw(ch, flags) {
if (flags === void 0) {
flags = {};
}
const matchFrom = Math.min(this.nearestInputPos(0, DIRECTION.FORCE_RIGHT), this.value.length);
const matches = this.enum.filter(e => this.matchValue(e, this.unmaskedValue + ch, matchFrom));
if (matches.length) {
if (matches.length === 1) {
this._forEachBlocksInRange(0, this.value.length, (b, bi) => {
const mch = matches[0][bi];
if (bi >= this.value.length || mch === b.value) return;
b.reset();
b._appendChar(mch, flags);
});
}
const d = super._appendCharRaw(matches[0][this.value.length], flags);
if (matches.length === 1) {
matches[0].slice(this.unmaskedValue.length).split('').forEach(mch => d.aggregate(super._appendCharRaw(mch)));
}
return d;
}
return new ChangeDetails({
skip: !this.isComplete
});
}
extractTail(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
// just drop tail
return new ContinuousTailDetails('', fromPos);
}
remove(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
if (fromPos === toPos) return new ChangeDetails();
const matchFrom = Math.min(super.nearestInputPos(0, DIRECTION.FORCE_RIGHT), this.value.length);
let pos;
for (pos = fromPos; pos >= 0; --pos) {
const matches = this.enum.filter(e => this.matchValue(e, this.value.slice(matchFrom, pos), matchFrom));
if (matches.length > 1) break;
}
const details = super.remove(pos, toPos);
details.tailShift += pos - fromPos;
return details;
}
get isComplete() {
return this.enum.indexOf(this.value) >= 0;
}
}
/** Match enum value */
MaskedEnum.DEFAULTS = {
...MaskedPattern.DEFAULTS,
matchValue: (estr, istr, matchFrom) => estr.indexOf(istr, matchFrom) === matchFrom
};
IMask.MaskedEnum = MaskedEnum;
export { MaskedEnum as default };

View file

@ -0,0 +1,129 @@
import type Masked from './base';
import { type MaskedOptions } from './base';
import type MaskedRegExp from './regexp';
import type MaskedPattern from './pattern';
import type MaskedFunction from './function';
import type MaskedDate from './date';
import type MaskedNumber from './number';
import type MaskedDynamic from './dynamic';
import type MaskedRange from './range';
import type MaskedEnum from './enum';
import { type MaskedEnumOptions } from './enum';
import { type MaskedRangeOptions } from './range';
import { type MaskedDynamicOptions } from './dynamic';
import { type MaskedPatternOptions } from './pattern';
import { type MaskedNumberOptions } from './number';
import { type MaskedRegExpOptions } from './regexp';
import { type MaskedFunctionOptions } from './function';
import { type MaskedDateOptions } from './date';
type MaskedDateFactoryOptions = Omit<MaskedDateOptions, 'mask'> & {
mask: DateConstructor;
};
export type FactoryStaticOpts = MaskedDateFactoryOptions | MaskedNumberOptions | MaskedPatternOptions | MaskedDynamicOptions | MaskedRegExpOptions | MaskedFunctionOptions;
export type AllFactoryStaticOpts = MaskedDateFactoryOptions & MaskedNumberOptions & MaskedPatternOptions & MaskedDynamicOptions & MaskedRegExpOptions & MaskedFunctionOptions & MaskedEnumOptions & MaskedRangeOptions;
export type FactoryStaticReturnMasked<Opts extends FactoryStaticOpts> = Opts extends MaskedDateFactoryOptions ? MaskedDate : Opts extends MaskedNumberOptions ? MaskedNumber : Opts extends MaskedPatternOptions ? MaskedPattern : Opts extends MaskedDynamicOptions ? MaskedDynamic : Opts extends MaskedRegExpOptions ? MaskedRegExp : Opts extends MaskedFunctionOptions ? MaskedFunction : never;
export type FactoryStaticMaskReturnMasked<Mask extends FactoryStaticOpts['mask']> = Mask extends MaskedDateFactoryOptions['mask'] ? MaskedDate : Mask extends MaskedNumberOptions['mask'] ? MaskedNumber : Mask extends MaskedPatternOptions['mask'] ? MaskedPattern : Mask extends MaskedDynamicOptions['mask'] ? MaskedDynamic : Mask extends MaskedRegExpOptions['mask'] ? MaskedRegExp : Mask extends MaskedFunctionOptions['mask'] ? MaskedFunction : never;
export type FactoryInstanceOpts = {
mask: MaskedDate;
} & Omit<MaskedDateFactoryOptions, 'mask'> | {
mask: MaskedNumber;
} & Omit<MaskedNumberOptions, 'mask'> | {
mask: MaskedEnum;
} & Omit<MaskedEnumOptions, 'mask'> | {
mask: MaskedRange;
} & Omit<MaskedRangeOptions, 'mask'> | {
mask: MaskedRegExp;
} & Omit<MaskedRegExpOptions, 'mask'> | {
mask: MaskedFunction;
} & Omit<MaskedFunctionOptions, 'mask'> | {
mask: MaskedPattern;
} & Omit<MaskedPatternOptions, 'mask'> | {
mask: MaskedDynamic;
} & Omit<MaskedDynamicOptions, 'mask'> | {
mask: Masked;
} & Omit<MaskedOptions, 'mask'>;
export type FactoryInstanceReturnMasked<Opts extends FactoryInstanceOpts> = Opts extends {
mask: infer M;
} ? M : never;
export type FactoryConstructorOpts = {
mask: typeof MaskedDate;
} & Omit<MaskedDateFactoryOptions, 'mask'> | {
mask: typeof MaskedNumber;
} & Omit<MaskedNumberOptions, 'mask'> | {
mask: typeof MaskedEnum;
} & Omit<MaskedEnumOptions, 'mask'> | {
mask: typeof MaskedRange;
} & Omit<MaskedRangeOptions, 'mask'> | {
mask: typeof MaskedRegExp;
} & Omit<MaskedRegExpOptions, 'mask'> | {
mask: typeof MaskedFunction;
} & Omit<MaskedFunctionOptions, 'mask'> | {
mask: typeof MaskedPattern;
} & Omit<MaskedPatternOptions, 'mask'> | {
mask: typeof MaskedDynamic;
} & Omit<MaskedDynamicOptions, 'mask'> | {
mask: typeof Masked;
} & Omit<MaskedOptions, 'mask'>;
export type FactoryConstructorReturnMasked<Opts extends FactoryConstructorOpts> = Opts extends {
mask: typeof MaskedDate;
} ? MaskedDate : Opts extends {
mask: typeof MaskedNumber;
} ? MaskedNumber : Opts extends {
mask: typeof MaskedEnum;
} ? MaskedEnum : Opts extends {
mask: typeof MaskedRange;
} ? MaskedRange : Opts extends {
mask: typeof MaskedRegExp;
} ? MaskedRegExp : Opts extends {
mask: typeof MaskedFunction;
} ? MaskedFunction : Opts extends {
mask: typeof MaskedPattern;
} ? MaskedPattern : Opts extends {
mask: typeof MaskedDynamic;
} ? MaskedDynamic : Masked;
export type FactoryOpts = FactoryConstructorOpts | FactoryInstanceOpts | FactoryStaticOpts;
export type FactoryArg = Masked | FactoryOpts | FactoryStaticOpts['mask'];
export type ExtendFactoryArgOptions<Opts extends {
[key: string]: any;
}> = Masked | FactoryOpts & Opts | FactoryStaticOpts['mask'];
export type UpdateStaticOpts<Opts extends FactoryStaticOpts> = Opts extends MaskedEnumOptions ? MaskedEnumOptions : Opts extends MaskedRangeOptions ? MaskedRangeOptions : Opts extends MaskedDynamicOptions ? MaskedDynamicOptions : Opts extends MaskedPatternOptions ? MaskedPatternOptions : Opts extends MaskedDateOptions ? MaskedDateOptions : Opts extends MaskedNumberOptions ? MaskedNumberOptions : Opts extends MaskedRegExpOptions ? MaskedRegExpOptions : Opts extends MaskedFunctionOptions ? MaskedFunctionOptions : never;
type AnyOpts = Record<string, any>;
export type UpdateInstanceOpts<M extends Masked> = M extends MaskedRegExp ? MaskedRegExpOptions : M extends MaskedFunction ? MaskedFunctionOptions : M extends MaskedDate ? MaskedDateOptions : M extends MaskedNumber ? MaskedNumberOptions : M extends MaskedDynamic ? MaskedDynamicOptions : M extends MaskedRange ? MaskedRangeOptions : M extends MaskedEnum ? MaskedEnumOptions : M extends MaskedPattern ? MaskedPatternOptions : AnyOpts;
export type UpdateConstructorOpts<M extends FactoryConstructorOpts> = M extends {
mask: typeof MaskedDate;
} ? MaskedDateOptions : M extends {
mask: typeof MaskedNumber;
} ? MaskedNumberOptions : M extends {
mask: typeof MaskedEnum;
} ? MaskedEnumOptions : M extends {
mask: typeof MaskedRange;
} ? MaskedRangeOptions : M extends {
mask: typeof MaskedRegExp;
} ? MaskedRegExpOptions : M extends {
mask: typeof MaskedFunction;
} ? MaskedFunctionOptions : M extends {
mask: typeof MaskedPattern;
} ? MaskedPatternOptions : M extends {
mask: typeof MaskedDynamic;
} ? MaskedDynamicOptions : AnyOpts;
export type UpdateStaticMaskOpts<M extends FactoryStaticOpts['mask']> = M extends MaskedDateFactoryOptions['mask'] ? MaskedDateOptions : M extends MaskedNumberOptions['mask'] ? MaskedNumberOptions : M extends MaskedPatternOptions['mask'] ? MaskedPatternOptions : M extends MaskedDynamicOptions['mask'] ? MaskedDynamicOptions : M extends MaskedRegExpOptions['mask'] ? MaskedRegExpOptions : M extends MaskedFunctionOptions['mask'] ? MaskedFunctionOptions : never;
export type UpdateOpts<Opts extends FactoryArg> = Partial<Opts extends Masked ? UpdateInstanceOpts<Opts> : Opts extends FactoryStaticOpts['mask'] ? UpdateStaticMaskOpts<Opts> : Opts extends FactoryStaticOpts ? UpdateStaticOpts<Opts> : Opts extends FactoryInstanceOpts ? UpdateInstanceOpts<Opts['mask']> : Opts extends FactoryConstructorOpts ? UpdateConstructorOpts<Opts> : AnyOpts>;
export type FactoryReturnMasked<Opts extends FactoryArg> = Opts extends Masked ? Opts : Opts extends FactoryStaticOpts['mask'] ? FactoryStaticMaskReturnMasked<Opts> : Opts extends FactoryConstructorOpts ? FactoryConstructorReturnMasked<Opts> : Opts extends FactoryInstanceOpts ? FactoryInstanceReturnMasked<Opts> : Opts extends FactoryStaticOpts ? FactoryStaticReturnMasked<Opts> : never;
/** Get Masked class by mask type */
export declare function maskedClass(mask: Masked | FactoryOpts['mask']): any;
type MaskedClassOf<M extends Masked> = M extends MaskedDate ? typeof MaskedDate : M extends MaskedNumber ? typeof MaskedNumber : M extends MaskedEnum ? typeof MaskedEnum : M extends MaskedRange ? typeof MaskedRange : M extends MaskedRegExp ? typeof MaskedRegExp : M extends MaskedFunction ? typeof MaskedFunction : M extends MaskedPattern ? typeof MaskedPattern : M extends MaskedDynamic ? typeof MaskedDynamic : any;
type NormalizedMaskedOpts<Opts extends Masked> = Omit<Opts, 'mask'> & {
_mask: Opts;
mask: MaskedClassOf<Opts>;
};
type NormalizedInstanceOpts<Opts extends FactoryInstanceOpts> = Omit<Opts['mask'], `_${string}` | 'mask'> & NormalizedMaskedOpts<Opts['mask']>;
export type NormalizedOpts<Opts extends FactoryArg> = Opts extends FactoryStaticOpts['mask'] ? {
mask: Opts;
} : Opts extends Masked ? NormalizedMaskedOpts<Opts> : Opts extends FactoryInstanceOpts ? NormalizedInstanceOpts<Opts> : Opts extends FactoryStaticOpts | FactoryConstructorOpts ? Opts : {
mask: Opts;
};
export declare function normalizeOpts<Opts extends FactoryArg>(opts: Opts): NormalizedOpts<Opts>;
/** Creates new {@link Masked} depending on mask type */
export default function createMask<Opts extends FactoryArg>(opts: Opts): FactoryReturnMasked<Opts>;
export {};
//# sourceMappingURL=factory.d.ts.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,121 @@
import { isString, isObject, pick } from '../core/utils.js';
import IMask from '../core/holder.js';
// TODO can't use overloads here because of https://github.com/microsoft/TypeScript/issues/50754
// export function maskedClass(mask: string): typeof MaskedPattern;
// export function maskedClass(mask: DateConstructor): typeof MaskedDate;
// export function maskedClass(mask: NumberConstructor): typeof MaskedNumber;
// export function maskedClass(mask: Array<any> | ArrayConstructor): typeof MaskedDynamic;
// export function maskedClass(mask: MaskedDate): typeof MaskedDate;
// export function maskedClass(mask: MaskedNumber): typeof MaskedNumber;
// export function maskedClass(mask: MaskedEnum): typeof MaskedEnum;
// export function maskedClass(mask: MaskedRange): typeof MaskedRange;
// export function maskedClass(mask: MaskedRegExp): typeof MaskedRegExp;
// export function maskedClass(mask: MaskedFunction): typeof MaskedFunction;
// export function maskedClass(mask: MaskedPattern): typeof MaskedPattern;
// export function maskedClass(mask: MaskedDynamic): typeof MaskedDynamic;
// export function maskedClass(mask: Masked): typeof Masked;
// export function maskedClass(mask: typeof Masked): typeof Masked;
// export function maskedClass(mask: typeof MaskedDate): typeof MaskedDate;
// export function maskedClass(mask: typeof MaskedNumber): typeof MaskedNumber;
// export function maskedClass(mask: typeof MaskedEnum): typeof MaskedEnum;
// export function maskedClass(mask: typeof MaskedRange): typeof MaskedRange;
// export function maskedClass(mask: typeof MaskedRegExp): typeof MaskedRegExp;
// export function maskedClass(mask: typeof MaskedFunction): typeof MaskedFunction;
// export function maskedClass(mask: typeof MaskedPattern): typeof MaskedPattern;
// export function maskedClass(mask: typeof MaskedDynamic): typeof MaskedDynamic;
// export function maskedClass<Mask extends typeof Masked> (mask: Mask): Mask;
// export function maskedClass(mask: RegExp): typeof MaskedRegExp;
// export function maskedClass(mask: (value: string, ...args: any[]) => boolean): typeof MaskedFunction;
/** Get Masked class by mask type */
function maskedClass(mask) /* TODO */{
if (mask == null) throw new Error('mask property should be defined');
if (mask instanceof RegExp) return IMask.MaskedRegExp;
if (isString(mask)) return IMask.MaskedPattern;
if (mask === Date) return IMask.MaskedDate;
if (mask === Number) return IMask.MaskedNumber;
if (Array.isArray(mask) || mask === Array) return IMask.MaskedDynamic;
if (IMask.Masked && mask.prototype instanceof IMask.Masked) return mask;
if (IMask.Masked && mask instanceof IMask.Masked) return mask.constructor;
if (mask instanceof Function) return IMask.MaskedFunction;
console.warn('Mask not found for mask', mask); // eslint-disable-line no-console
return IMask.Masked;
}
function normalizeOpts(opts) {
if (!opts) throw new Error('Options in not defined');
if (IMask.Masked) {
if (opts.prototype instanceof IMask.Masked) return {
mask: opts
};
/*
handle cases like:
1) opts = Masked
2) opts = { mask: Masked, ...instanceOpts }
*/
const {
mask = undefined,
...instanceOpts
} = opts instanceof IMask.Masked ? {
mask: opts
} : isObject(opts) && opts.mask instanceof IMask.Masked ? opts : {};
if (mask) {
const _mask = mask.mask;
return {
...pick(mask, (_, k) => !k.startsWith('_')),
mask: mask.constructor,
_mask,
...instanceOpts
};
}
}
if (!isObject(opts)) return {
mask: opts
};
return {
...opts
};
}
// TODO can't use overloads here because of https://github.com/microsoft/TypeScript/issues/50754
// From masked
// export default function createMask<Opts extends Masked, ReturnMasked=Opts> (opts: Opts): ReturnMasked;
// // From masked class
// export default function createMask<Opts extends MaskedOptions<typeof Masked>, ReturnMasked extends Masked=InstanceType<Opts['mask']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedDate>, ReturnMasked extends MaskedDate=MaskedDate<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedNumber>, ReturnMasked extends MaskedNumber=MaskedNumber<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedEnum>, ReturnMasked extends MaskedEnum=MaskedEnum<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedRange>, ReturnMasked extends MaskedRange=MaskedRange<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedRegExp>, ReturnMasked extends MaskedRegExp=MaskedRegExp<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedFunction>, ReturnMasked extends MaskedFunction=MaskedFunction<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedPattern>, ReturnMasked extends MaskedPattern=MaskedPattern<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<typeof MaskedDynamic>, ReturnMasked extends MaskedDynamic=MaskedDynamic<Opts['parent']>> (opts: Opts): ReturnMasked;
// // From mask opts
// export default function createMask<Opts extends MaskedOptions<Masked>, ReturnMasked=Opts extends MaskedOptions<infer M> ? M : never> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedNumberOptions, ReturnMasked extends MaskedNumber=MaskedNumber<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedDateFactoryOptions, ReturnMasked extends MaskedDate=MaskedDate<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedEnumOptions, ReturnMasked extends MaskedEnum=MaskedEnum<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedRangeOptions, ReturnMasked extends MaskedRange=MaskedRange<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedPatternOptions, ReturnMasked extends MaskedPattern=MaskedPattern<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedDynamicOptions, ReturnMasked extends MaskedDynamic=MaskedDynamic<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<RegExp>, ReturnMasked extends MaskedRegExp=MaskedRegExp<Opts['parent']>> (opts: Opts): ReturnMasked;
// export default function createMask<Opts extends MaskedOptions<Function>, ReturnMasked extends MaskedFunction=MaskedFunction<Opts['parent']>> (opts: Opts): ReturnMasked;
/** Creates new {@link Masked} depending on mask type */
function createMask(opts) {
if (IMask.Masked && opts instanceof IMask.Masked) return opts;
const nOpts = normalizeOpts(opts);
const MaskedClass = maskedClass(nOpts.mask);
if (!MaskedClass) throw new Error("Masked class is not found for provided mask " + nOpts.mask + ", appropriate module needs to be imported manually before creating mask.");
if (nOpts.mask === MaskedClass) delete nOpts.mask;
if (nOpts._mask) {
nOpts.mask = nOpts._mask;
delete nOpts._mask;
}
return new MaskedClass(nOpts);
}
IMask.createMask = createMask;
export { createMask as default, maskedClass, normalizeOpts };

View file

@ -0,0 +1,18 @@
import Masked, { type MaskedOptions } from './base';
export type MaskedFunctionOptions = MaskedOptions<MaskedFunction>;
/** Masking by custom Function */
export default class MaskedFunction<Value = any> extends Masked<Value> {
/** */
mask: (value: string, masked: Masked) => boolean;
/** Enable characters overwriting */
overwrite?: boolean | 'shift' | undefined;
/** */
eager?: boolean | 'remove' | 'append' | undefined;
/** */
skipInvalid?: boolean | undefined;
/** */
autofix?: boolean | 'pad' | undefined;
updateOptions(opts: Partial<MaskedFunctionOptions>): void;
_update(opts: Partial<MaskedFunctionOptions>): void;
}
//# sourceMappingURL=function.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../../src/masked/function.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAIpD,MAAM,MACD,qBAAqB,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;AAE3D,iCAAiC;AACjC,MAAM,CAAC,OAAO,OACR,cAAc,CAAC,KAAK,GAAC,GAAG,CAAE,SAAQ,MAAM,CAAC,KAAK,CAAC;IACnD,MAAM;IACE,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IACzD,oCAAoC;IAC5B,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IAClD,MAAM;IACE,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1D,MAAM;IACE,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,MAAM;IACE,OAAO,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;IAErC,aAAa,CAAE,IAAI,EAAE,OAAO,CAAC,qBAAqB,CAAC;IAInD,OAAO,CAAE,IAAI,EAAE,OAAO,CAAC,qBAAqB,CAAC;CAMvD"}

View file

@ -0,0 +1,31 @@
import Masked from './base.js';
import IMask from '../core/holder.js';
import '../core/change-details.js';
import '../core/continuous-tail-details.js';
import '../core/utils.js';
/** Masking by custom Function */
class MaskedFunction extends Masked {
/** */
/** Enable characters overwriting */
/** */
/** */
/** */
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
super._update({
...opts,
validate: opts.mask
});
}
}
IMask.MaskedFunction = MaskedFunction;
export { MaskedFunction as default };

View file

@ -0,0 +1,87 @@
import { type Direction } from '../core/utils';
import ChangeDetails from '../core/change-details';
import { type TailDetails } from '../core/tail-details';
import Masked, { type MaskedOptions, type ExtractFlags, type AppendFlags } from './base';
export type MaskedNumberOptions = MaskedOptions<MaskedNumber, 'radix' | 'thousandsSeparator' | 'mapToRadix' | 'scale' | 'min' | 'max' | 'normalizeZeros' | 'padFractionalZeros'>;
/** Number mask */
export default class MaskedNumber extends Masked<number> {
static UNMASKED_RADIX: string;
static EMPTY_VALUES: Array<null | undefined | string | number>;
static DEFAULTS: {
mask: NumberConstructor;
radix: string;
thousandsSeparator: string;
mapToRadix: string[];
min: number;
max: number;
scale: number;
normalizeZeros: boolean;
padFractionalZeros: boolean;
parse: NumberConstructor;
format: (n: number) => string;
skipInvalid?: boolean | undefined;
};
mask: NumberConstructor;
/** Single char */
radix: string;
/** Single char */
thousandsSeparator: string;
/** Array of single chars */
mapToRadix: Array<string>;
/** */
min: number;
/** */
max: number;
/** Digits after point */
scale: number;
/** Flag to remove leading and trailing zeros in the end of editing */
normalizeZeros: boolean;
/** Flag to pad trailing zeros after point in the end of editing */
padFractionalZeros: boolean;
/** Enable characters overwriting */
overwrite?: boolean | 'shift' | undefined;
/** */
eager?: boolean | 'remove' | 'append' | undefined;
/** */
skipInvalid?: boolean | undefined;
/** */
autofix?: boolean | 'pad' | undefined;
/** Format typed value to string */
format: (value: number, masked: Masked) => string;
/** Parse string to get typed value */
parse: (str: string, masked: Masked) => number;
_numberRegExp: RegExp;
_thousandsSeparatorRegExp: RegExp;
_mapToRadixRegExp: RegExp;
_separatorsProcessed: boolean;
constructor(opts?: MaskedNumberOptions);
updateOptions(opts: Partial<MaskedNumberOptions>): void;
_update(opts: Partial<MaskedNumberOptions>): void;
_updateRegExps(): void;
_removeThousandsSeparators(value: string): string;
_insertThousandsSeparators(value: string): string;
doPrepareChar(ch: string, flags?: AppendFlags): [string, ChangeDetails];
_separatorsCount(to: number, extendOnSeparators?: boolean): number;
_separatorsCountFromSlice(slice?: string): number;
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
_appendCharRaw(ch: string, flags?: AppendFlags): ChangeDetails;
_findSeparatorAround(pos: number): number;
_adjustRangeWithSeparators(from: number, to: number): [number, number];
remove(fromPos?: number, toPos?: number): ChangeDetails;
nearestInputPos(cursorPos: number, direction?: Direction): number;
doCommit(): void;
_normalizeZeros(value: string): string;
_padFractionalZeros(value: string): string;
doSkipInvalid(ch: string, flags?: AppendFlags, checkTail?: TailDetails): boolean;
get unmaskedValue(): string;
set unmaskedValue(unmaskedValue: string);
get typedValue(): number;
set typedValue(n: number);
/** Parsed Number */
get number(): number;
set number(number: number);
get allowNegative(): boolean;
get allowPositive(): boolean;
typedValueEquals(value: any): boolean;
}
//# sourceMappingURL=number.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"number.d.ts","sourceRoot":"","sources":["../../src/masked/number.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,314 @@
import { escapeRegExp, DIRECTION } from '../core/utils.js';
import ChangeDetails from '../core/change-details.js';
import Masked from './base.js';
import IMask from '../core/holder.js';
import '../core/continuous-tail-details.js';
var _MaskedNumber;
/** Number mask */
class MaskedNumber extends Masked {
/** Single char */
/** Single char */
/** Array of single chars */
/** */
/** */
/** Digits after point */
/** Flag to remove leading and trailing zeros in the end of editing */
/** Flag to pad trailing zeros after point in the end of editing */
/** Enable characters overwriting */
/** */
/** */
/** */
/** Format typed value to string */
/** Parse string to get typed value */
constructor(opts) {
super({
...MaskedNumber.DEFAULTS,
...opts
});
}
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
super._update(opts);
this._updateRegExps();
}
_updateRegExps() {
const start = '^' + (this.allowNegative ? '[+|\\-]?' : '');
const mid = '\\d*';
const end = (this.scale ? "(" + escapeRegExp(this.radix) + "\\d{0," + this.scale + "})?" : '') + '$';
this._numberRegExp = new RegExp(start + mid + end);
this._mapToRadixRegExp = new RegExp("[" + this.mapToRadix.map(escapeRegExp).join('') + "]", 'g');
this._thousandsSeparatorRegExp = new RegExp(escapeRegExp(this.thousandsSeparator), 'g');
}
_removeThousandsSeparators(value) {
return value.replace(this._thousandsSeparatorRegExp, '');
}
_insertThousandsSeparators(value) {
// https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
const parts = value.split(this.radix);
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandsSeparator);
return parts.join(this.radix);
}
doPrepareChar(ch, flags) {
if (flags === void 0) {
flags = {};
}
const [prepCh, details] = super.doPrepareChar(this._removeThousandsSeparators(this.scale && this.mapToRadix.length && (
/*
radix should be mapped when
1) input is done from keyboard = flags.input && flags.raw
2) unmasked value is set = !flags.input && !flags.raw
and should not be mapped when
1) value is set = flags.input && !flags.raw
2) raw value is set = !flags.input && flags.raw
*/
flags.input && flags.raw || !flags.input && !flags.raw) ? ch.replace(this._mapToRadixRegExp, this.radix) : ch), flags);
if (ch && !prepCh) details.skip = true;
if (prepCh && !this.allowPositive && !this.value && prepCh !== '-') details.aggregate(this._appendChar('-'));
return [prepCh, details];
}
_separatorsCount(to, extendOnSeparators) {
if (extendOnSeparators === void 0) {
extendOnSeparators = false;
}
let count = 0;
for (let pos = 0; pos < to; ++pos) {
if (this._value.indexOf(this.thousandsSeparator, pos) === pos) {
++count;
if (extendOnSeparators) to += this.thousandsSeparator.length;
}
}
return count;
}
_separatorsCountFromSlice(slice) {
if (slice === void 0) {
slice = this._value;
}
return this._separatorsCount(this._removeThousandsSeparators(slice).length, true);
}
extractInput(fromPos, toPos, flags) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
[fromPos, toPos] = this._adjustRangeWithSeparators(fromPos, toPos);
return this._removeThousandsSeparators(super.extractInput(fromPos, toPos, flags));
}
_appendCharRaw(ch, flags) {
if (flags === void 0) {
flags = {};
}
const prevBeforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
const prevBeforeTailSeparatorsCount = this._separatorsCountFromSlice(prevBeforeTailValue);
this._value = this._removeThousandsSeparators(this.value);
const oldValue = this._value;
this._value += ch;
const num = this.number;
let accepted = !isNaN(num);
let skip = false;
if (accepted) {
let fixedNum;
if (this.min != null && this.min < 0 && this.number < this.min) fixedNum = this.min;
if (this.max != null && this.max > 0 && this.number > this.max) fixedNum = this.max;
if (fixedNum != null) {
if (this.autofix) {
this._value = this.format(fixedNum, this).replace(MaskedNumber.UNMASKED_RADIX, this.radix);
skip || (skip = oldValue === this._value && !flags.tail); // if not changed on tail it's still ok to proceed
} else {
accepted = false;
}
}
accepted && (accepted = Boolean(this._value.match(this._numberRegExp)));
}
let appendDetails;
if (!accepted) {
this._value = oldValue;
appendDetails = new ChangeDetails();
} else {
appendDetails = new ChangeDetails({
inserted: this._value.slice(oldValue.length),
rawInserted: skip ? '' : ch,
skip
});
}
this._value = this._insertThousandsSeparators(this._value);
const beforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
const beforeTailSeparatorsCount = this._separatorsCountFromSlice(beforeTailValue);
appendDetails.tailShift += (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length;
return appendDetails;
}
_findSeparatorAround(pos) {
if (this.thousandsSeparator) {
const searchFrom = pos - this.thousandsSeparator.length + 1;
const separatorPos = this.value.indexOf(this.thousandsSeparator, searchFrom);
if (separatorPos <= pos) return separatorPos;
}
return -1;
}
_adjustRangeWithSeparators(from, to) {
const separatorAroundFromPos = this._findSeparatorAround(from);
if (separatorAroundFromPos >= 0) from = separatorAroundFromPos;
const separatorAroundToPos = this._findSeparatorAround(to);
if (separatorAroundToPos >= 0) to = separatorAroundToPos + this.thousandsSeparator.length;
return [from, to];
}
remove(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
[fromPos, toPos] = this._adjustRangeWithSeparators(fromPos, toPos);
const valueBeforePos = this.value.slice(0, fromPos);
const valueAfterPos = this.value.slice(toPos);
const prevBeforeTailSeparatorsCount = this._separatorsCount(valueBeforePos.length);
this._value = this._insertThousandsSeparators(this._removeThousandsSeparators(valueBeforePos + valueAfterPos));
const beforeTailSeparatorsCount = this._separatorsCountFromSlice(valueBeforePos);
return new ChangeDetails({
tailShift: (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length
});
}
nearestInputPos(cursorPos, direction) {
if (!this.thousandsSeparator) return cursorPos;
switch (direction) {
case DIRECTION.NONE:
case DIRECTION.LEFT:
case DIRECTION.FORCE_LEFT:
{
const separatorAtLeftPos = this._findSeparatorAround(cursorPos - 1);
if (separatorAtLeftPos >= 0) {
const separatorAtLeftEndPos = separatorAtLeftPos + this.thousandsSeparator.length;
if (cursorPos < separatorAtLeftEndPos || this.value.length <= separatorAtLeftEndPos || direction === DIRECTION.FORCE_LEFT) {
return separatorAtLeftPos;
}
}
break;
}
case DIRECTION.RIGHT:
case DIRECTION.FORCE_RIGHT:
{
const separatorAtRightPos = this._findSeparatorAround(cursorPos);
if (separatorAtRightPos >= 0) {
return separatorAtRightPos + this.thousandsSeparator.length;
}
}
}
return cursorPos;
}
doCommit() {
if (this.value) {
const number = this.number;
let validnum = number;
// check bounds
if (this.min != null) validnum = Math.max(validnum, this.min);
if (this.max != null) validnum = Math.min(validnum, this.max);
if (validnum !== number) this.unmaskedValue = this.format(validnum, this);
let formatted = this.value;
if (this.normalizeZeros) formatted = this._normalizeZeros(formatted);
if (this.padFractionalZeros && this.scale > 0) formatted = this._padFractionalZeros(formatted);
this._value = formatted;
}
super.doCommit();
}
_normalizeZeros(value) {
const parts = this._removeThousandsSeparators(value).split(this.radix);
// remove leading zeros
parts[0] = parts[0].replace(/^(\D*)(0*)(\d*)/, (match, sign, zeros, num) => sign + num);
// add leading zero
if (value.length && !/\d$/.test(parts[0])) parts[0] = parts[0] + '0';
if (parts.length > 1) {
parts[1] = parts[1].replace(/0*$/, ''); // remove trailing zeros
if (!parts[1].length) parts.length = 1; // remove fractional
}
return this._insertThousandsSeparators(parts.join(this.radix));
}
_padFractionalZeros(value) {
if (!value) return value;
const parts = value.split(this.radix);
if (parts.length < 2) parts.push('');
parts[1] = parts[1].padEnd(this.scale, '0');
return parts.join(this.radix);
}
doSkipInvalid(ch, flags, checkTail) {
if (flags === void 0) {
flags = {};
}
const dropFractional = this.scale === 0 && ch !== this.thousandsSeparator && (ch === this.radix || ch === MaskedNumber.UNMASKED_RADIX || this.mapToRadix.includes(ch));
return super.doSkipInvalid(ch, flags, checkTail) && !dropFractional;
}
get unmaskedValue() {
return this._removeThousandsSeparators(this._normalizeZeros(this.value)).replace(this.radix, MaskedNumber.UNMASKED_RADIX);
}
set unmaskedValue(unmaskedValue) {
super.unmaskedValue = unmaskedValue;
}
get typedValue() {
return this.parse(this.unmaskedValue, this);
}
set typedValue(n) {
this.rawInputValue = this.format(n, this).replace(MaskedNumber.UNMASKED_RADIX, this.radix);
}
/** Parsed Number */
get number() {
return this.typedValue;
}
set number(number) {
this.typedValue = number;
}
get allowNegative() {
return this.min != null && this.min < 0 || this.max != null && this.max < 0;
}
get allowPositive() {
return this.min != null && this.min > 0 || this.max != null && this.max > 0;
}
typedValueEquals(value) {
// handle 0 -> '' case (typed = 0 even if value = '')
// for details see https://github.com/uNmAnNeR/imaskjs/issues/134
return (super.typedValueEquals(value) || MaskedNumber.EMPTY_VALUES.includes(value) && MaskedNumber.EMPTY_VALUES.includes(this.typedValue)) && !(value === 0 && this.value === '');
}
}
_MaskedNumber = MaskedNumber;
MaskedNumber.UNMASKED_RADIX = '.';
MaskedNumber.EMPTY_VALUES = [...Masked.EMPTY_VALUES, 0];
MaskedNumber.DEFAULTS = {
...Masked.DEFAULTS,
mask: Number,
radix: ',',
thousandsSeparator: '',
mapToRadix: [_MaskedNumber.UNMASKED_RADIX],
min: Number.MIN_SAFE_INTEGER,
max: Number.MAX_SAFE_INTEGER,
scale: 2,
normalizeZeros: true,
padFractionalZeros: false,
parse: Number,
format: n => n.toLocaleString('en-US', {
useGrouping: false,
maximumFractionDigits: 20
})
};
IMask.MaskedNumber = MaskedNumber;
export { MaskedNumber as default };

View file

@ -0,0 +1,103 @@
import ChangeDetails from '../core/change-details';
import { type TailDetails } from '../core/tail-details';
import { type Direction } from '../core/utils';
import Masked, { type AppendFlags, type ExtractFlags, type MaskedOptions, type MaskedState } from './base';
import { type FactoryArg, type ExtendFactoryArgOptions } from './factory';
import type PatternBlock from './pattern/block';
import PatternFixedDefinition from './pattern/fixed-definition';
import PatternInputDefinition from './pattern/input-definition';
import './regexp';
export type MaskedPatternOptions<Value = string, M extends MaskedPattern<Value> = MaskedPattern<Value>, Props extends keyof M = never> = MaskedOptions<M, 'definitions' | 'blocks' | 'placeholderChar' | 'displayChar' | 'lazy' | Props>;
export type Definitions = {
[k: string]: FactoryArg;
};
export type MaskedPatternState = MaskedState & {
_blocks: Array<MaskedState>;
};
export type BlockPosData = {
index: number;
offset: number;
};
export type BlockExtraOptions = {
expose?: boolean;
repeat?: number | [number, number];
};
/** Pattern mask */
export default class MaskedPattern<Value = string> extends Masked<Value> {
static DEFAULTS: {
lazy: boolean;
placeholderChar: string;
skipInvalid?: boolean | undefined;
};
static STOP_CHAR: string;
static ESCAPE_CHAR: string;
static InputDefinition: typeof PatternInputDefinition;
static FixedDefinition: typeof PatternFixedDefinition;
mask: string;
/** */
blocks: {
[key: string]: ExtendFactoryArgOptions<BlockExtraOptions>;
};
/** */
definitions: Definitions;
/** Single char for empty input */
placeholderChar: string;
/** Single char for filled input */
displayChar: string;
/** Show placeholder only when needed */
lazy: boolean;
/** Enable characters overwriting */
overwrite?: boolean | 'shift' | undefined;
/** */
eager?: boolean | 'remove' | 'append' | undefined;
/** */
skipInvalid?: boolean | undefined;
/** */
autofix?: boolean | 'pad' | undefined;
_blocks: Array<PatternBlock>;
_maskedBlocks: {
[key: string]: Array<number>;
};
_stops: Array<number>;
exposeBlock?: Masked;
constructor(opts: MaskedPatternOptions<Value>);
updateOptions(opts: Partial<MaskedPatternOptions<Value>>): void;
_update(opts: Partial<MaskedPatternOptions<Value>>): void;
_rebuildMask(): void;
get state(): MaskedPatternState;
set state(state: MaskedPatternState);
reset(): void;
get isComplete(): boolean;
get isFilled(): boolean;
get isFixed(): boolean;
get isOptional(): boolean;
doCommit(): void;
get unmaskedValue(): string;
set unmaskedValue(unmaskedValue: string);
get value(): string;
set value(value: string);
get typedValue(): Value;
set typedValue(value: Value);
get displayValue(): string;
appendTail(tail: string | String | TailDetails): ChangeDetails;
_appendEager(): ChangeDetails;
_appendCharRaw(ch: string, flags?: AppendFlags<MaskedPatternState>): ChangeDetails;
extractTail(fromPos?: number, toPos?: number): TailDetails;
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
_findStopBefore(blockIndex: number): number | undefined;
/** Appends placeholder depending on laziness */
_appendPlaceholder(toBlockIndex?: number): ChangeDetails;
/** Finds block in pos */
_mapPosToBlock(pos: number): BlockPosData | undefined;
_blockStartPos(blockIndex: number): number;
_forEachBlocksInRange(fromPos: number, toPos: number | undefined, fn: (block: PatternBlock, blockIndex: number, fromPos: number, toPos: number) => void): void;
remove(fromPos?: number, toPos?: number): ChangeDetails;
nearestInputPos(cursorPos: number, direction?: Direction): number;
totalInputPositions(fromPos?: number, toPos?: number): number;
/** Get block by name */
maskedBlock(name: string): PatternBlock | undefined;
/** Get all blocks by name */
maskedBlocks(name: string): Array<PatternBlock>;
pad(flags?: AppendFlags): ChangeDetails;
}
//# sourceMappingURL=pattern.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"pattern.d.ts","sourceRoot":"","sources":["../../src/masked/pattern.ts"],"names":[],"mappings":"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"}

View file

@ -0,0 +1,464 @@
import ChangeDetails from '../core/change-details.js';
import IMask from '../core/holder.js';
import { DIRECTION } from '../core/utils.js';
import Masked from './base.js';
import createMask, { normalizeOpts } from './factory.js';
import ChunksTailDetails from './pattern/chunk-tail-details.js';
import PatternCursor from './pattern/cursor.js';
import PatternFixedDefinition from './pattern/fixed-definition.js';
import PatternInputDefinition from './pattern/input-definition.js';
import './regexp.js';
import '../core/continuous-tail-details.js';
/** Pattern mask */
class MaskedPattern extends Masked {
/** */
/** */
/** Single char for empty input */
/** Single char for filled input */
/** Show placeholder only when needed */
/** Enable characters overwriting */
/** */
/** */
/** */
constructor(opts) {
super({
...MaskedPattern.DEFAULTS,
...opts,
definitions: Object.assign({}, PatternInputDefinition.DEFAULT_DEFINITIONS, opts == null ? void 0 : opts.definitions)
});
}
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
opts.definitions = Object.assign({}, this.definitions, opts.definitions);
super._update(opts);
this._rebuildMask();
}
_rebuildMask() {
const defs = this.definitions;
this._blocks = [];
this.exposeBlock = undefined;
this._stops = [];
this._maskedBlocks = {};
const pattern = this.mask;
if (!pattern || !defs) return;
let unmaskingBlock = false;
let optionalBlock = false;
for (let i = 0; i < pattern.length; ++i) {
if (this.blocks) {
const p = pattern.slice(i);
const bNames = Object.keys(this.blocks).filter(bName => p.indexOf(bName) === 0);
// order by key length
bNames.sort((a, b) => b.length - a.length);
// use block name with max length
const bName = bNames[0];
if (bName) {
const {
expose,
repeat,
...bOpts
} = normalizeOpts(this.blocks[bName]); // TODO type Opts<Arg & Extra>
const blockOpts = {
lazy: this.lazy,
eager: this.eager,
placeholderChar: this.placeholderChar,
displayChar: this.displayChar,
overwrite: this.overwrite,
autofix: this.autofix,
...bOpts,
repeat,
parent: this
};
const maskedBlock = repeat != null ? new IMask.RepeatBlock(blockOpts /* TODO */) : createMask(blockOpts);
if (maskedBlock) {
this._blocks.push(maskedBlock);
if (expose) this.exposeBlock = maskedBlock;
// store block index
if (!this._maskedBlocks[bName]) this._maskedBlocks[bName] = [];
this._maskedBlocks[bName].push(this._blocks.length - 1);
}
i += bName.length - 1;
continue;
}
}
let char = pattern[i];
let isInput = (char in defs);
if (char === MaskedPattern.STOP_CHAR) {
this._stops.push(this._blocks.length);
continue;
}
if (char === '{' || char === '}') {
unmaskingBlock = !unmaskingBlock;
continue;
}
if (char === '[' || char === ']') {
optionalBlock = !optionalBlock;
continue;
}
if (char === MaskedPattern.ESCAPE_CHAR) {
++i;
char = pattern[i];
if (!char) break;
isInput = false;
}
const def = isInput ? new PatternInputDefinition({
isOptional: optionalBlock,
lazy: this.lazy,
eager: this.eager,
placeholderChar: this.placeholderChar,
displayChar: this.displayChar,
...normalizeOpts(defs[char]),
parent: this
}) : new PatternFixedDefinition({
char,
eager: this.eager,
isUnmasking: unmaskingBlock
});
this._blocks.push(def);
}
}
get state() {
return {
...super.state,
_blocks: this._blocks.map(b => b.state)
};
}
set state(state) {
if (!state) {
this.reset();
return;
}
const {
_blocks,
...maskedState
} = state;
this._blocks.forEach((b, bi) => b.state = _blocks[bi]);
super.state = maskedState;
}
reset() {
super.reset();
this._blocks.forEach(b => b.reset());
}
get isComplete() {
return this.exposeBlock ? this.exposeBlock.isComplete : this._blocks.every(b => b.isComplete);
}
get isFilled() {
return this._blocks.every(b => b.isFilled);
}
get isFixed() {
return this._blocks.every(b => b.isFixed);
}
get isOptional() {
return this._blocks.every(b => b.isOptional);
}
doCommit() {
this._blocks.forEach(b => b.doCommit());
super.doCommit();
}
get unmaskedValue() {
return this.exposeBlock ? this.exposeBlock.unmaskedValue : this._blocks.reduce((str, b) => str += b.unmaskedValue, '');
}
set unmaskedValue(unmaskedValue) {
if (this.exposeBlock) {
const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
this.exposeBlock.unmaskedValue = unmaskedValue;
this.appendTail(tail);
this.doCommit();
} else super.unmaskedValue = unmaskedValue;
}
get value() {
return this.exposeBlock ? this.exposeBlock.value :
// TODO return _value when not in change?
this._blocks.reduce((str, b) => str += b.value, '');
}
set value(value) {
if (this.exposeBlock) {
const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
this.exposeBlock.value = value;
this.appendTail(tail);
this.doCommit();
} else super.value = value;
}
get typedValue() {
return this.exposeBlock ? this.exposeBlock.typedValue : super.typedValue;
}
set typedValue(value) {
if (this.exposeBlock) {
const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
this.exposeBlock.typedValue = value;
this.appendTail(tail);
this.doCommit();
} else super.typedValue = value;
}
get displayValue() {
return this._blocks.reduce((str, b) => str += b.displayValue, '');
}
appendTail(tail) {
return super.appendTail(tail).aggregate(this._appendPlaceholder());
}
_appendEager() {
var _this$_mapPosToBlock;
const details = new ChangeDetails();
let startBlockIndex = (_this$_mapPosToBlock = this._mapPosToBlock(this.displayValue.length)) == null ? void 0 : _this$_mapPosToBlock.index;
if (startBlockIndex == null) return details;
// TODO test if it works for nested pattern masks
if (this._blocks[startBlockIndex].isFilled) ++startBlockIndex;
for (let bi = startBlockIndex; bi < this._blocks.length; ++bi) {
const d = this._blocks[bi]._appendEager();
if (!d.inserted) break;
details.aggregate(d);
}
return details;
}
_appendCharRaw(ch, flags) {
if (flags === void 0) {
flags = {};
}
const blockIter = this._mapPosToBlock(this.displayValue.length);
const details = new ChangeDetails();
if (!blockIter) return details;
for (let bi = blockIter.index, block; block = this._blocks[bi]; ++bi) {
var _flags$_beforeTailSta;
const blockDetails = block._appendChar(ch, {
...flags,
_beforeTailState: (_flags$_beforeTailSta = flags._beforeTailState) == null || (_flags$_beforeTailSta = _flags$_beforeTailSta._blocks) == null ? void 0 : _flags$_beforeTailSta[bi]
});
details.aggregate(blockDetails);
if (blockDetails.consumed) break; // go next char
}
return details;
}
extractTail(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
const chunkTail = new ChunksTailDetails();
if (fromPos === toPos) return chunkTail;
this._forEachBlocksInRange(fromPos, toPos, (b, bi, bFromPos, bToPos) => {
const blockChunk = b.extractTail(bFromPos, bToPos);
blockChunk.stop = this._findStopBefore(bi);
blockChunk.from = this._blockStartPos(bi);
if (blockChunk instanceof ChunksTailDetails) blockChunk.blockIndex = bi;
chunkTail.extend(blockChunk);
});
return chunkTail;
}
extractInput(fromPos, toPos, flags) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
if (flags === void 0) {
flags = {};
}
if (fromPos === toPos) return '';
let input = '';
this._forEachBlocksInRange(fromPos, toPos, (b, _, fromPos, toPos) => {
input += b.extractInput(fromPos, toPos, flags);
});
return input;
}
_findStopBefore(blockIndex) {
let stopBefore;
for (let si = 0; si < this._stops.length; ++si) {
const stop = this._stops[si];
if (stop <= blockIndex) stopBefore = stop;else break;
}
return stopBefore;
}
/** Appends placeholder depending on laziness */
_appendPlaceholder(toBlockIndex) {
const details = new ChangeDetails();
if (this.lazy && toBlockIndex == null) return details;
const startBlockIter = this._mapPosToBlock(this.displayValue.length);
if (!startBlockIter) return details;
const startBlockIndex = startBlockIter.index;
const endBlockIndex = toBlockIndex != null ? toBlockIndex : this._blocks.length;
this._blocks.slice(startBlockIndex, endBlockIndex).forEach(b => {
if (!b.lazy || toBlockIndex != null) {
var _blocks2;
details.aggregate(b._appendPlaceholder((_blocks2 = b._blocks) == null ? void 0 : _blocks2.length));
}
});
return details;
}
/** Finds block in pos */
_mapPosToBlock(pos) {
let accVal = '';
for (let bi = 0; bi < this._blocks.length; ++bi) {
const block = this._blocks[bi];
const blockStartPos = accVal.length;
accVal += block.displayValue;
if (pos <= accVal.length) {
return {
index: bi,
offset: pos - blockStartPos
};
}
}
}
_blockStartPos(blockIndex) {
return this._blocks.slice(0, blockIndex).reduce((pos, b) => pos += b.displayValue.length, 0);
}
_forEachBlocksInRange(fromPos, toPos, fn) {
if (toPos === void 0) {
toPos = this.displayValue.length;
}
const fromBlockIter = this._mapPosToBlock(fromPos);
if (fromBlockIter) {
const toBlockIter = this._mapPosToBlock(toPos);
// process first block
const isSameBlock = toBlockIter && fromBlockIter.index === toBlockIter.index;
const fromBlockStartPos = fromBlockIter.offset;
const fromBlockEndPos = toBlockIter && isSameBlock ? toBlockIter.offset : this._blocks[fromBlockIter.index].displayValue.length;
fn(this._blocks[fromBlockIter.index], fromBlockIter.index, fromBlockStartPos, fromBlockEndPos);
if (toBlockIter && !isSameBlock) {
// process intermediate blocks
for (let bi = fromBlockIter.index + 1; bi < toBlockIter.index; ++bi) {
fn(this._blocks[bi], bi, 0, this._blocks[bi].displayValue.length);
}
// process last block
fn(this._blocks[toBlockIter.index], toBlockIter.index, 0, toBlockIter.offset);
}
}
}
remove(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
const removeDetails = super.remove(fromPos, toPos);
this._forEachBlocksInRange(fromPos, toPos, (b, _, bFromPos, bToPos) => {
removeDetails.aggregate(b.remove(bFromPos, bToPos));
});
return removeDetails;
}
nearestInputPos(cursorPos, direction) {
if (direction === void 0) {
direction = DIRECTION.NONE;
}
if (!this._blocks.length) return 0;
const cursor = new PatternCursor(this, cursorPos);
if (direction === DIRECTION.NONE) {
// -------------------------------------------------
// NONE should only go out from fixed to the right!
// -------------------------------------------------
if (cursor.pushRightBeforeInput()) return cursor.pos;
cursor.popState();
if (cursor.pushLeftBeforeInput()) return cursor.pos;
return this.displayValue.length;
}
// FORCE is only about a|* otherwise is 0
if (direction === DIRECTION.LEFT || direction === DIRECTION.FORCE_LEFT) {
// try to break fast when *|a
if (direction === DIRECTION.LEFT) {
cursor.pushRightBeforeFilled();
if (cursor.ok && cursor.pos === cursorPos) return cursorPos;
cursor.popState();
}
// forward flow
cursor.pushLeftBeforeInput();
cursor.pushLeftBeforeRequired();
cursor.pushLeftBeforeFilled();
// backward flow
if (direction === DIRECTION.LEFT) {
cursor.pushRightBeforeInput();
cursor.pushRightBeforeRequired();
if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
cursor.popState();
if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
cursor.popState();
}
if (cursor.ok) return cursor.pos;
if (direction === DIRECTION.FORCE_LEFT) return 0;
cursor.popState();
if (cursor.ok) return cursor.pos;
cursor.popState();
if (cursor.ok) return cursor.pos;
return 0;
}
if (direction === DIRECTION.RIGHT || direction === DIRECTION.FORCE_RIGHT) {
// forward flow
cursor.pushRightBeforeInput();
cursor.pushRightBeforeRequired();
if (cursor.pushRightBeforeFilled()) return cursor.pos;
if (direction === DIRECTION.FORCE_RIGHT) return this.displayValue.length;
// backward flow
cursor.popState();
if (cursor.ok) return cursor.pos;
cursor.popState();
if (cursor.ok) return cursor.pos;
return this.nearestInputPos(cursorPos, DIRECTION.LEFT);
}
return cursorPos;
}
totalInputPositions(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.displayValue.length;
}
let total = 0;
this._forEachBlocksInRange(fromPos, toPos, (b, _, bFromPos, bToPos) => {
total += b.totalInputPositions(bFromPos, bToPos);
});
return total;
}
/** Get block by name */
maskedBlock(name) {
return this.maskedBlocks(name)[0];
}
/** Get all blocks by name */
maskedBlocks(name) {
const indices = this._maskedBlocks[name];
if (!indices) return [];
return indices.map(gi => this._blocks[gi]);
}
pad(flags) {
const details = new ChangeDetails();
this._forEachBlocksInRange(0, this.displayValue.length, b => details.aggregate(b.pad(flags)));
return details;
}
}
MaskedPattern.DEFAULTS = {
...Masked.DEFAULTS,
lazy: true,
placeholderChar: '_'
};
MaskedPattern.STOP_CHAR = '`';
MaskedPattern.ESCAPE_CHAR = '\\';
MaskedPattern.InputDefinition = PatternInputDefinition;
MaskedPattern.FixedDefinition = PatternFixedDefinition;
IMask.MaskedPattern = MaskedPattern;
export { MaskedPattern as default };

View file

@ -0,0 +1,31 @@
import type ChangeDetails from '../../core/change-details';
import { type TailDetails } from '../../core/tail-details';
import { type ExtractFlags, type AppendFlags, type MaskedState } from '../base';
import { type Direction } from '../../core/utils';
/** Subset of {@link Masked} attributes used with pattern */
export default interface PatternBlock<State = MaskedState> {
readonly value: string;
readonly unmaskedValue: string;
readonly displayValue: string;
readonly isComplete: boolean;
readonly lazy?: boolean;
readonly eager?: boolean | 'remove' | 'append' | undefined;
readonly isFilled: boolean;
readonly isOptional?: boolean;
readonly isFixed?: boolean;
state: any;
reset(): void;
remove(fromPos?: number, toPos?: number): ChangeDetails;
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
extractTail(fromPos?: number, toPos?: number): TailDetails;
append(str: string, flags?: AppendFlags<State>, tail?: TailDetails): ChangeDetails;
appendTail(tail: string | TailDetails): ChangeDetails;
_appendChar(str: string, flags: AppendFlags<State>): ChangeDetails;
_appendPlaceholder(toBlockIndex?: number): ChangeDetails;
_appendEager(): ChangeDetails;
doCommit(): void;
nearestInputPos(cursorPos: number, direction: Direction): number;
totalInputPositions(fromPos?: number, toPos?: number): number;
pad(flags?: AppendFlags): ChangeDetails;
}
//# sourceMappingURL=block.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../src/masked/pattern/block.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,4DAA4D;AAC5D,MAAM,CAAC,OAAO,WACJ,YAAY,CAAC,KAAK,GAAC,WAAW;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,EAAE,GAAG,CAAC;IAEX,KAAK,IAAK,IAAI,CAAC;IACf,MAAM,CAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACzD,YAAY,CAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAC9E,WAAW,CAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC5D,MAAM,CAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;IACpF,UAAU,CAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,CAAC;IACvD,WAAW,CAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,aAAa,CAAC;IACpE,kBAAkB,CAAE,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IAC1D,YAAY,IAAK,aAAa,CAAC;IAC/B,QAAQ,IAAK,IAAI,CAAC;IAClB,eAAe,CAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC;IAClE,mBAAmB,CAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/D,GAAG,CAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;CAC1C"}

View file

@ -0,0 +1 @@

View file

@ -0,0 +1,22 @@
import type { TailDetails, AppendTail } from '../../core/tail-details';
import ChangeDetails from '../../core/change-details';
import type MaskedPattern from '../pattern';
export type ChunksTailState = Pick<ChunksTailDetails, 'from' | 'stop' | 'blockIndex'> & {
chunks: Array<TailDetails['state']>;
};
export default class ChunksTailDetails implements TailDetails {
chunks: Array<TailDetails>;
from: number;
stop?: number;
/** */
blockIndex?: number;
constructor(chunks?: Array<TailDetails>, from?: number);
toString(): string;
extend(tailChunk: string | String | TailDetails): void;
appendTo(masked: AppendTail | MaskedPattern): ChangeDetails;
get state(): ChunksTailState;
set state(state: ChunksTailState);
unshift(beforePos?: number): string;
shift(): string;
}
//# sourceMappingURL=chunk-tail-details.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"chunk-tail-details.d.ts","sourceRoot":"","sources":["../../../src/masked/pattern/chunk-tail-details.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,aAAa,MAAM,2BAA2B,CAAC;AAItD,OAAO,KAAK,aAAa,MAAM,YAAY,CAAC;AAG5C,MAAM,MACD,eAAe,GAAG,IAAI,CAAC,iBAAiB,EACzC,MAAM,GACN,MAAM,GACN,YAAY,CACf,GAAG;IAAE,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAA;CAAE,CAAC;AAE5C,MAAM,CAAC,OAAO,OACR,iBAAkB,YAAW,WAAW;IACpC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM;IACE,UAAU,CAAC,EAAE,MAAM,CAAC;gBAEf,MAAM,GAAE,KAAK,CAAC,WAAW,CAAI,EAAE,IAAI,GAAE,MAAQ;IAK1D,QAAQ,IAAK,MAAM;IAInB,MAAM,CAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,IAAI;IAwCvD,QAAQ,CAAE,MAAM,EAAE,UAAU,GAAG,aAAa,GAAG,aAAa;IA2C5D,IAAI,KAAK,IAAK,eAAe,CAO5B;IAED,IAAI,KAAK,CAAE,KAAK,EAAE,eAAe,EAUhC;IAED,OAAO,CAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAyBpC,KAAK,IAAK,MAAM;CAuBjB"}

View file

@ -0,0 +1,158 @@
import ChangeDetails from '../../core/change-details.js';
import { isString } from '../../core/utils.js';
import ContinuousTailDetails from '../../core/continuous-tail-details.js';
import IMask from '../../core/holder.js';
class ChunksTailDetails {
/** */
constructor(chunks, from) {
if (chunks === void 0) {
chunks = [];
}
if (from === void 0) {
from = 0;
}
this.chunks = chunks;
this.from = from;
}
toString() {
return this.chunks.map(String).join('');
}
extend(tailChunk) {
if (!String(tailChunk)) return;
tailChunk = isString(tailChunk) ? new ContinuousTailDetails(String(tailChunk)) : tailChunk;
const lastChunk = this.chunks[this.chunks.length - 1];
const extendLast = lastChunk && (
// if stops are same or tail has no stop
lastChunk.stop === tailChunk.stop || tailChunk.stop == null) &&
// if tail chunk goes just after last chunk
tailChunk.from === lastChunk.from + lastChunk.toString().length;
if (tailChunk instanceof ContinuousTailDetails) {
// check the ability to extend previous chunk
if (extendLast) {
// extend previous chunk
lastChunk.extend(tailChunk.toString());
} else {
// append new chunk
this.chunks.push(tailChunk);
}
} else if (tailChunk instanceof ChunksTailDetails) {
if (tailChunk.stop == null) {
// unwrap floating chunks to parent, keeping `from` pos
let firstTailChunk;
while (tailChunk.chunks.length && tailChunk.chunks[0].stop == null) {
firstTailChunk = tailChunk.chunks.shift(); // not possible to be `undefined` because length was checked above
firstTailChunk.from += tailChunk.from;
this.extend(firstTailChunk);
}
}
// if tail chunk still has value
if (tailChunk.toString()) {
// if chunks contains stops, then popup stop to container
tailChunk.stop = tailChunk.blockIndex;
this.chunks.push(tailChunk);
}
}
}
appendTo(masked) {
if (!(masked instanceof IMask.MaskedPattern)) {
const tail = new ContinuousTailDetails(this.toString());
return tail.appendTo(masked);
}
const details = new ChangeDetails();
for (let ci = 0; ci < this.chunks.length; ++ci) {
const chunk = this.chunks[ci];
const lastBlockIter = masked._mapPosToBlock(masked.displayValue.length);
const stop = chunk.stop;
let chunkBlock;
if (stop != null && (
// if block not found or stop is behind lastBlock
!lastBlockIter || lastBlockIter.index <= stop)) {
if (chunk instanceof ChunksTailDetails ||
// for continuous block also check if stop is exist
masked._stops.indexOf(stop) >= 0) {
details.aggregate(masked._appendPlaceholder(stop));
}
chunkBlock = chunk instanceof ChunksTailDetails && masked._blocks[stop];
}
if (chunkBlock) {
const tailDetails = chunkBlock.appendTail(chunk);
details.aggregate(tailDetails);
// get not inserted chars
const remainChars = chunk.toString().slice(tailDetails.rawInserted.length);
if (remainChars) details.aggregate(masked.append(remainChars, {
tail: true
}));
} else {
details.aggregate(masked.append(chunk.toString(), {
tail: true
}));
}
}
return details;
}
get state() {
return {
chunks: this.chunks.map(c => c.state),
from: this.from,
stop: this.stop,
blockIndex: this.blockIndex
};
}
set state(state) {
const {
chunks,
...props
} = state;
Object.assign(this, props);
this.chunks = chunks.map(cstate => {
const chunk = "chunks" in cstate ? new ChunksTailDetails() : new ContinuousTailDetails();
chunk.state = cstate;
return chunk;
});
}
unshift(beforePos) {
if (!this.chunks.length || beforePos != null && this.from >= beforePos) return '';
const chunkShiftPos = beforePos != null ? beforePos - this.from : beforePos;
let ci = 0;
while (ci < this.chunks.length) {
const chunk = this.chunks[ci];
const shiftChar = chunk.unshift(chunkShiftPos);
if (chunk.toString()) {
// chunk still contains value
// but not shifted - means no more available chars to shift
if (!shiftChar) break;
++ci;
} else {
// clean if chunk has no value
this.chunks.splice(ci, 1);
}
if (shiftChar) return shiftChar;
}
return '';
}
shift() {
if (!this.chunks.length) return '';
let ci = this.chunks.length - 1;
while (0 <= ci) {
const chunk = this.chunks[ci];
const shiftChar = chunk.shift();
if (chunk.toString()) {
// chunk still contains value
// but not shifted - means no more available chars to shift
if (!shiftChar) break;
--ci;
} else {
// clean if chunk has no value
this.chunks.splice(ci, 1);
}
if (shiftChar) return shiftChar;
}
return '';
}
}
export { ChunksTailDetails as default };

View file

@ -0,0 +1,32 @@
import type MaskedPattern from '../pattern';
import type PatternBlock from './block';
type PatternCursorState = {
offset: number;
index: number;
ok: boolean;
};
export default class PatternCursor<Value> {
masked: MaskedPattern<Value>;
offset: number;
index: number;
ok: boolean;
_log: PatternCursorState[];
constructor(masked: MaskedPattern<Value>, pos: number);
get block(): PatternBlock;
get pos(): number;
get state(): PatternCursorState;
set state(s: PatternCursorState);
pushState(): void;
popState(): PatternCursorState | undefined;
bindBlock(): void;
_pushLeft(fn: () => boolean | undefined): boolean;
_pushRight(fn: () => boolean | undefined): boolean;
pushLeftBeforeFilled(): boolean;
pushLeftBeforeInput(): boolean;
pushLeftBeforeRequired(): boolean;
pushRightBeforeFilled(): boolean;
pushRightBeforeInput(): boolean;
pushRightBeforeRequired(): boolean;
}
export {};
//# sourceMappingURL=cursor.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../../src/masked/pattern/cursor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,aAAa,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,YAAY,MAAM,SAAS,CAAC;AAGxC,KAAK,kBAAkB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAA;CAAE,CAAC;AAEzE,MAAM,CAAC,OAAO,OACR,aAAa,CAAC,KAAK;IACf,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,kBAAkB,EAAE,CAAC;gBAEtB,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,MAAM;IAgBtD,IAAI,KAAK,IAAK,YAAY,CAEzB;IAED,IAAI,GAAG,IAAK,MAAM,CAEjB;IAED,IAAI,KAAK,IAAK,kBAAkB,CAE/B;IAED,IAAI,KAAK,CAAE,CAAC,EAAE,kBAAkB,EAE/B;IAED,SAAS;IAIT,QAAQ,IAAK,kBAAkB,GAAG,SAAS;IAM3C,SAAS;IAYT,SAAS,CAAC,EAAE,EAAE,MAAM,OAAO,GAAG,SAAS,GAAG,OAAO;IASjD,UAAU,CAAE,EAAE,EAAE,MAAM,OAAO,GAAG,SAAS,GAAG,OAAO;IASnD,oBAAoB,IAAK,OAAO;IAShC,mBAAmB,IAAK,OAAO;IAa/B,sBAAsB,IAAK,OAAO;IASlC,qBAAqB,IAAK,OAAO;IASjC,oBAAoB,IAAK,OAAO;IAchC,uBAAuB,IAAK,OAAO;CASpC"}

View file

@ -0,0 +1,131 @@
import { DIRECTION } from '../../core/utils.js';
class PatternCursor {
constructor(masked, pos) {
this.masked = masked;
this._log = [];
const {
offset,
index
} = masked._mapPosToBlock(pos) || (pos < 0 ?
// first
{
index: 0,
offset: 0
} :
// last
{
index: this.masked._blocks.length,
offset: 0
});
this.offset = offset;
this.index = index;
this.ok = false;
}
get block() {
return this.masked._blocks[this.index];
}
get pos() {
return this.masked._blockStartPos(this.index) + this.offset;
}
get state() {
return {
index: this.index,
offset: this.offset,
ok: this.ok
};
}
set state(s) {
Object.assign(this, s);
}
pushState() {
this._log.push(this.state);
}
popState() {
const s = this._log.pop();
if (s) this.state = s;
return s;
}
bindBlock() {
if (this.block) return;
if (this.index < 0) {
this.index = 0;
this.offset = 0;
}
if (this.index >= this.masked._blocks.length) {
this.index = this.masked._blocks.length - 1;
this.offset = this.block.displayValue.length; // TODO this is stupid type error, `block` depends on index that was changed above
}
}
_pushLeft(fn) {
this.pushState();
for (this.bindBlock(); 0 <= this.index; --this.index, this.offset = ((_this$block = this.block) == null ? void 0 : _this$block.displayValue.length) || 0) {
var _this$block;
if (fn()) return this.ok = true;
}
return this.ok = false;
}
_pushRight(fn) {
this.pushState();
for (this.bindBlock(); this.index < this.masked._blocks.length; ++this.index, this.offset = 0) {
if (fn()) return this.ok = true;
}
return this.ok = false;
}
pushLeftBeforeFilled() {
return this._pushLeft(() => {
if (this.block.isFixed || !this.block.value) return;
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.FORCE_LEFT);
if (this.offset !== 0) return true;
});
}
pushLeftBeforeInput() {
// cases:
// filled input: 00|
// optional empty input: 00[]|
// nested block: XX<[]>|
return this._pushLeft(() => {
if (this.block.isFixed) return;
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.LEFT);
return true;
});
}
pushLeftBeforeRequired() {
return this._pushLeft(() => {
if (this.block.isFixed || this.block.isOptional && !this.block.value) return;
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.LEFT);
return true;
});
}
pushRightBeforeFilled() {
return this._pushRight(() => {
if (this.block.isFixed || !this.block.value) return;
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.FORCE_RIGHT);
if (this.offset !== this.block.value.length) return true;
});
}
pushRightBeforeInput() {
return this._pushRight(() => {
if (this.block.isFixed) return;
// const o = this.offset;
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.NONE);
// HACK cases like (STILL DOES NOT WORK FOR NESTED)
// aa|X
// aa<X|[]>X_ - this will not work
// if (o && o === this.offset && this.block instanceof PatternInputDefinition) continue;
return true;
});
}
pushRightBeforeRequired() {
return this._pushRight(() => {
if (this.block.isFixed || this.block.isOptional && !this.block.value) return;
// TODO check |[*]XX_
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.NONE);
return true;
});
}
}
export { PatternCursor as default };

View file

@ -0,0 +1,43 @@
import ChangeDetails from '../../core/change-details';
import { type Direction } from '../../core/utils';
import { type TailDetails } from '../../core/tail-details';
import { type ExtractFlags, type AppendFlags, type MaskedState } from '../base';
import type PatternBlock from './block';
export type PatternFixedDefinitionOptions = Pick<PatternFixedDefinition, 'char' | 'isUnmasking' | 'eager'>;
export default class PatternFixedDefinition implements PatternBlock {
/** */
_value: string;
/** */
char: string;
/** */
isUnmasking?: boolean;
/** */
eager: boolean | 'remove' | 'append' | undefined;
/** */
_isRawInput?: boolean;
/** */
isFixed: boolean;
constructor(opts: PatternFixedDefinitionOptions);
get value(): string;
get unmaskedValue(): string;
get rawInputValue(): string;
get displayValue(): string;
reset(): void;
remove(fromPos?: number, toPos?: number): ChangeDetails;
nearestInputPos(cursorPos: number, direction?: Direction): number;
totalInputPositions(fromPos?: number, toPos?: number): number;
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
get isComplete(): boolean;
get isFilled(): boolean;
_appendChar(ch: string, flags?: AppendFlags): ChangeDetails;
_appendEager(): ChangeDetails;
_appendPlaceholder(): ChangeDetails;
extractTail(): TailDetails;
appendTail(tail: string | String | TailDetails): ChangeDetails;
append(str: string, flags?: AppendFlags, tail?: TailDetails): ChangeDetails;
doCommit(): void;
get state(): MaskedState;
set state(state: MaskedState);
pad(flags?: AppendFlags): ChangeDetails;
}
//# sourceMappingURL=fixed-definition.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"fixed-definition.d.ts","sourceRoot":"","sources":["../../../src/masked/pattern/fixed-definition.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAa,KAAK,SAAS,EAAY,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,KAAK,YAAY,MAAM,SAAS,CAAC;AAGxC,MAAM,MACD,6BAA6B,GAAG,IAAI,CAAC,sBAAsB,EAAE,MAAM,GAAG,aAAa,GAAG,OAAO,CAAC,CAAC;AAGpG,MAAM,CAAC,OAAO,OACR,sBAAuB,YAAW,YAAY;IAClD,MAAM;IACE,MAAM,EAAE,MAAM,CAAC;IACvB,MAAM;IACE,IAAI,EAAE,MAAM,CAAC;IACrB,MAAM;IACE,WAAW,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM;IACE,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzD,MAAM;IACE,WAAW,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM;IACE,OAAO,EAAE,OAAO,CAAC;gBAEb,IAAI,EAAE,6BAA6B;IAM/C,IAAI,KAAK,IAAK,MAAM,CAEnB;IAED,IAAI,aAAa,IAAK,MAAM,CAE3B;IAED,IAAI,aAAa,IAAK,MAAM,CAE3B;IAED,IAAI,YAAY,IAAK,MAAM,CAE1B;IAED,KAAK;IAKL,MAAM,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAAyB,GAAG,aAAa;IAO3E,eAAe,CAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,SAAwB,GAAG,MAAM;IAgBhF,mBAAmB,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAAyB,GAAG,MAAM;IAIjF,YAAY,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAAyB,EAAE,KAAK,GAAE,YAAe,GAAG,MAAM;IAIlG,IAAI,UAAU,IAAK,OAAO,CAEzB;IAED,IAAI,QAAQ,IAAK,OAAO,CAEvB;IAED,WAAW,CAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,WAAc,GAAG,aAAa;IAgB9D,YAAY,IAAK,aAAa;IAI9B,kBAAkB,IAAK,aAAa;IAQpC,WAAW,IAAK,WAAW;IAI3B,UAAU,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,aAAa;IAM/D,MAAM,CAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,aAAa;IAU5E,QAAQ;IAER,IAAI,KAAK,IAAK,WAAW,CAKxB;IAED,IAAI,KAAK,CAAE,KAAK,EAAE,WAAW,EAG5B;IAED,GAAG,CAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa;CAGzC"}

View file

@ -0,0 +1,152 @@
import ChangeDetails from '../../core/change-details.js';
import { DIRECTION, isString } from '../../core/utils.js';
import ContinuousTailDetails from '../../core/continuous-tail-details.js';
import '../../core/holder.js';
class PatternFixedDefinition {
/** */
/** */
/** */
/** */
/** */
/** */
constructor(opts) {
Object.assign(this, opts);
this._value = '';
this.isFixed = true;
}
get value() {
return this._value;
}
get unmaskedValue() {
return this.isUnmasking ? this.value : '';
}
get rawInputValue() {
return this._isRawInput ? this.value : '';
}
get displayValue() {
return this.value;
}
reset() {
this._isRawInput = false;
this._value = '';
}
remove(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this._value.length;
}
this._value = this._value.slice(0, fromPos) + this._value.slice(toPos);
if (!this._value) this._isRawInput = false;
return new ChangeDetails();
}
nearestInputPos(cursorPos, direction) {
if (direction === void 0) {
direction = DIRECTION.NONE;
}
const minPos = 0;
const maxPos = this._value.length;
switch (direction) {
case DIRECTION.LEFT:
case DIRECTION.FORCE_LEFT:
return minPos;
case DIRECTION.NONE:
case DIRECTION.RIGHT:
case DIRECTION.FORCE_RIGHT:
default:
return maxPos;
}
}
totalInputPositions(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this._value.length;
}
return this._isRawInput ? toPos - fromPos : 0;
}
extractInput(fromPos, toPos, flags) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this._value.length;
}
if (flags === void 0) {
flags = {};
}
return flags.raw && this._isRawInput && this._value.slice(fromPos, toPos) || '';
}
get isComplete() {
return true;
}
get isFilled() {
return Boolean(this._value);
}
_appendChar(ch, flags) {
if (flags === void 0) {
flags = {};
}
if (this.isFilled) return new ChangeDetails();
const appendEager = this.eager === true || this.eager === 'append';
const appended = this.char === ch;
const isResolved = appended && (this.isUnmasking || flags.input || flags.raw) && (!flags.raw || !appendEager) && !flags.tail;
const details = new ChangeDetails({
inserted: this.char,
rawInserted: isResolved ? this.char : ''
});
this._value = this.char;
this._isRawInput = isResolved && (flags.raw || flags.input);
return details;
}
_appendEager() {
return this._appendChar(this.char, {
tail: true
});
}
_appendPlaceholder() {
const details = new ChangeDetails();
if (this.isFilled) return details;
this._value = details.inserted = this.char;
return details;
}
extractTail() {
return new ContinuousTailDetails('');
}
appendTail(tail) {
if (isString(tail)) tail = new ContinuousTailDetails(String(tail));
return tail.appendTo(this);
}
append(str, flags, tail) {
const details = this._appendChar(str[0], flags);
if (tail != null) {
details.tailShift += this.appendTail(tail).tailShift;
}
return details;
}
doCommit() {}
get state() {
return {
_value: this._value,
_rawInputValue: this.rawInputValue
};
}
set state(state) {
this._value = state._value;
this._isRawInput = Boolean(state._rawInputValue);
}
pad(flags) {
return this._appendPlaceholder();
}
}
export { PatternFixedDefinition as default };

View file

@ -0,0 +1,58 @@
import { type FactoryArg, type FactoryOpts, type FactoryReturnMasked } from '../factory';
import type Masked from '../base';
import type MaskedPattern from '../pattern';
import { type TailDetails } from '../../core/tail-details';
import { type ExtractFlags, type AppendFlags, type MaskedState } from '../base';
import ChangeDetails from '../../core/change-details';
import { type Direction } from '../../core/utils';
import type PatternBlock from './block';
export type PatternInputDefinitionOptions<Opts extends FactoryOpts> = Omit<Opts, 'parent' | 'isOptional' | 'lazy' | 'eager' | 'placeholderChar' | 'displayChar'> & Partial<Pick<PatternInputDefinition, 'parent' | 'isOptional' | 'lazy' | 'eager' | 'placeholderChar' | 'displayChar'>>;
export type PatternInputDefinitionState<Opts extends FactoryArg> = MaskedState & {
masked: FactoryReturnMasked<Opts>['state'];
isFilled: boolean;
};
export default class PatternInputDefinition<Opts extends FactoryOpts = any> implements PatternBlock<PatternInputDefinitionState<Opts>> {
static DEFAULT_DEFINITIONS: {
[k: string]: RegExp;
};
/** */
readonly masked: FactoryReturnMasked<Opts>;
/** */
parent: Masked;
/** */
isOptional: boolean;
/** */
isFilled: boolean;
/** */
lazy: MaskedPattern['lazy'];
/** */
eager: MaskedPattern['eager'];
/** */
placeholderChar: MaskedPattern['placeholderChar'];
/** */
displayChar: MaskedPattern['displayChar'];
constructor(opts: PatternInputDefinitionOptions<Opts>);
reset(): void;
remove(fromPos?: number, toPos?: number): ChangeDetails;
get value(): string;
get unmaskedValue(): string;
get rawInputValue(): string;
get displayValue(): string;
get isComplete(): boolean;
_appendChar(ch: string, flags?: AppendFlags<PatternInputDefinitionState<Opts>>): ChangeDetails;
append(str: string, flags?: AppendFlags<PatternInputDefinitionState<Opts>>, tail?: TailDetails): ChangeDetails;
_appendPlaceholder(): ChangeDetails;
_appendEager(): ChangeDetails;
extractTail(fromPos?: number, toPos?: number): TailDetails;
appendTail(tail: string | TailDetails): ChangeDetails;
extractInput(fromPos?: number, toPos?: number, flags?: ExtractFlags): string;
nearestInputPos(cursorPos: number, direction?: Direction): number;
totalInputPositions(fromPos?: number, toPos?: number): number;
doValidate(flags: AppendFlags<PatternInputDefinitionState<Opts>>): boolean;
doCommit(): void;
get state(): PatternInputDefinitionState<Opts>;
set state(state: PatternInputDefinitionState<Opts>);
currentMaskFlags(flags?: AppendFlags<PatternInputDefinitionState<Opts>>): AppendFlags;
pad(flags?: AppendFlags): ChangeDetails;
}
//# sourceMappingURL=input-definition.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"input-definition.d.ts","sourceRoot":"","sources":["../../../src/masked/pattern/input-definition.ts"],"names":[],"mappings":"AAAA,OAAmB,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACrG,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,aAAa,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AAChF,OAAO,aAAa,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,YAAY,MAAM,SAAS,CAAC;AAGxC,MAAM,MACD,6BAA6B,CAAC,IAAI,SAAS,WAAW,IACzD,IAAI,CAAC,IAAI,EACP,QAAQ,GACR,YAAY,GACZ,MAAM,GACN,OAAO,GACP,iBAAiB,GACjB,aAAa,CAAC,GAChB,OAAO,CAAC,IAAI,CAAC,sBAAsB,EACjC,QAAQ,GACR,YAAY,GACZ,MAAM,GACN,OAAO,GACP,iBAAiB,GACjB,aAAa,CAChB,CAAC,CAAC;AAEH,MAAM,MACD,2BAA2B,CAAC,IAAI,SAAS,UAAU,IAAI,WAAW,GAAG;IACxE,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IAC3C,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAGF,MAAM,CAAC,OAAO,OACR,sBAAsB,CAAC,IAAI,SAAS,WAAW,GAAC,GAAG,CAAE,YAAW,YAAY,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC;IACnH,MAAM,CAAC,mBAAmB,EAAE;QAAE,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAIlD;IAED,MAAM;IACN,SAAiB,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM;IACE,MAAM,EAAE,MAAM,CAAC;IACvB,MAAM;IACE,UAAU,EAAE,OAAO,CAAC;IAC5B,MAAM;IACE,QAAQ,EAAE,OAAO,CAAC;IAC1B,MAAM;IACE,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM;IACE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM;IACE,eAAe,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAC1D,MAAM;IACE,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;gBAGtC,IAAI,EAAE,6BAA6B,CAAC,IAAI,CAAC;IAOrD,KAAK;IAKL,MAAM,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAAwB,GAAG,aAAa;IAS1E,IAAI,KAAK,IAAK,MAAM,CAKnB;IAED,IAAI,aAAa,IAAK,MAAM,CAE3B;IAED,IAAI,aAAa,IAAK,MAAM,CAE3B;IAED,IAAI,YAAY,IAAK,MAAM,CAE1B;IAED,IAAI,UAAU,IAAK,OAAO,CAEzB;IAED,WAAW,CAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,WAAW,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAI,GAAG,aAAa;IAqBjG,MAAM,CAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,aAAa;IAK/G,kBAAkB,IAAK,aAAa;IAOpC,YAAY,IAAK,aAAa;IAI9B,WAAW,CAAE,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW;IAI3D,UAAU,CAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa;IAItD,YAAY,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAAwB,EAAE,KAAK,CAAC,EAAE,YAAY,GAAG,MAAM;IAI/F,eAAe,CAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,SAAwB,GAAG,MAAM;IAiBhF,mBAAmB,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAAwB,GAAG,MAAM;IAIhF,UAAU,CAAE,KAAK,EAAE,WAAW,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO;IAK3E,QAAQ;IAIR,IAAI,KAAK,IAAK,2BAA2B,CAAC,IAAI,CAAC,CAO9C;IAED,IAAI,KAAK,CAAE,KAAK,EAAE,2BAA2B,CAAC,IAAI,CAAC,EAGlD;IAED,gBAAgB,CAAE,KAAK,CAAC,EAAE,WAAW,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,GAAG,WAAW;IAOtF,GAAG,CAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa;CAGzC"}

View file

@ -0,0 +1,187 @@
import createMask from '../factory.js';
import ChangeDetails from '../../core/change-details.js';
import { DIRECTION } from '../../core/utils.js';
import '../../core/holder.js';
class PatternInputDefinition {
/** */
/** */
/** */
/** */
/** */
/** */
/** */
/** */
constructor(opts) {
const {
parent,
isOptional,
placeholderChar,
displayChar,
lazy,
eager,
...maskOpts
} = opts;
this.masked = createMask(maskOpts);
Object.assign(this, {
parent,
isOptional,
placeholderChar,
displayChar,
lazy,
eager
});
}
reset() {
this.isFilled = false;
this.masked.reset();
}
remove(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.value.length;
}
if (fromPos === 0 && toPos >= 1) {
this.isFilled = false;
return this.masked.remove(fromPos, toPos);
}
return new ChangeDetails();
}
get value() {
return this.masked.value || (this.isFilled && !this.isOptional ? this.placeholderChar : '');
}
get unmaskedValue() {
return this.masked.unmaskedValue;
}
get rawInputValue() {
return this.masked.rawInputValue;
}
get displayValue() {
return this.masked.value && this.displayChar || this.value;
}
get isComplete() {
return Boolean(this.masked.value) || this.isOptional;
}
_appendChar(ch, flags) {
if (flags === void 0) {
flags = {};
}
if (this.isFilled) return new ChangeDetails();
const state = this.masked.state;
// simulate input
let details = this.masked._appendChar(ch, this.currentMaskFlags(flags));
if (details.inserted && this.doValidate(flags) === false) {
details = new ChangeDetails();
this.masked.state = state;
}
if (!details.inserted && !this.isOptional && !this.lazy && !flags.input) {
details.inserted = this.placeholderChar;
}
details.skip = !details.inserted && !this.isOptional;
this.isFilled = Boolean(details.inserted);
return details;
}
append(str, flags, tail) {
// TODO probably should be done via _appendChar
return this.masked.append(str, this.currentMaskFlags(flags), tail);
}
_appendPlaceholder() {
if (this.isFilled || this.isOptional) return new ChangeDetails();
this.isFilled = true;
return new ChangeDetails({
inserted: this.placeholderChar
});
}
_appendEager() {
return new ChangeDetails();
}
extractTail(fromPos, toPos) {
return this.masked.extractTail(fromPos, toPos);
}
appendTail(tail) {
return this.masked.appendTail(tail);
}
extractInput(fromPos, toPos, flags) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.value.length;
}
return this.masked.extractInput(fromPos, toPos, flags);
}
nearestInputPos(cursorPos, direction) {
if (direction === void 0) {
direction = DIRECTION.NONE;
}
const minPos = 0;
const maxPos = this.value.length;
const boundPos = Math.min(Math.max(cursorPos, minPos), maxPos);
switch (direction) {
case DIRECTION.LEFT:
case DIRECTION.FORCE_LEFT:
return this.isComplete ? boundPos : minPos;
case DIRECTION.RIGHT:
case DIRECTION.FORCE_RIGHT:
return this.isComplete ? boundPos : maxPos;
case DIRECTION.NONE:
default:
return boundPos;
}
}
totalInputPositions(fromPos, toPos) {
if (fromPos === void 0) {
fromPos = 0;
}
if (toPos === void 0) {
toPos = this.value.length;
}
return this.value.slice(fromPos, toPos).length;
}
doValidate(flags) {
return this.masked.doValidate(this.currentMaskFlags(flags)) && (!this.parent || this.parent.doValidate(this.currentMaskFlags(flags)));
}
doCommit() {
this.masked.doCommit();
}
get state() {
return {
_value: this.value,
_rawInputValue: this.rawInputValue,
masked: this.masked.state,
isFilled: this.isFilled
};
}
set state(state) {
this.masked.state = state.masked;
this.isFilled = state.isFilled;
}
currentMaskFlags(flags) {
var _flags$_beforeTailSta;
return {
...flags,
_beforeTailState: (flags == null || (_flags$_beforeTailSta = flags._beforeTailState) == null ? void 0 : _flags$_beforeTailSta.masked) || (flags == null ? void 0 : flags._beforeTailState)
};
}
pad(flags) {
return new ChangeDetails();
}
}
PatternInputDefinition.DEFAULT_DEFINITIONS = {
'0': /\d/,
'a': /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/,
// http://stackoverflow.com/a/22075070
'*': /./
};
export { PatternInputDefinition as default };

View file

@ -0,0 +1,15 @@
import { type FactoryArg, type FactoryReturnMasked } from './factory';
/** Mask pipe source and destination types */
export declare const PIPE_TYPE: {
readonly MASKED: "value";
readonly UNMASKED: "unmaskedValue";
readonly TYPED: "typedValue";
};
type ValueOf<T> = T[keyof T];
type TypedValueOf<Opts extends FactoryArg, Type extends ValueOf<typeof PIPE_TYPE>> = Type extends (typeof PIPE_TYPE.MASKED | typeof PIPE_TYPE.UNMASKED) ? string : FactoryReturnMasked<Opts>['typedValue'];
/** Creates new pipe function depending on mask type, source and destination options */
export declare function createPipe<Arg extends FactoryArg, From extends ValueOf<typeof PIPE_TYPE> = typeof PIPE_TYPE.MASKED, To extends ValueOf<typeof PIPE_TYPE> = typeof PIPE_TYPE.MASKED>(arg: Arg, from?: From, to?: To): (value: TypedValueOf<Arg, From>) => TypedValueOf<Arg, To>;
/** Pipes value through mask depending on mask type, source and destination options */
export declare function pipe<Arg extends FactoryArg, From extends ValueOf<typeof PIPE_TYPE> = typeof PIPE_TYPE.MASKED, To extends ValueOf<typeof PIPE_TYPE> = typeof PIPE_TYPE.MASKED>(value: TypedValueOf<Arg, From>, mask: Arg, from?: From, to?: To): TypedValueOf<Arg, To>;
export {};
//# sourceMappingURL=pipe.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"pipe.d.ts","sourceRoot":"","sources":["../../src/masked/pipe.ts"],"names":[],"mappings":"AAAA,OAAmB,EAAE,KAAK,UAAU,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAIlF,6CAA6C;AAC7C,eACA,MAAM,SAAS;;;;CAIL,CAAC;AAEX,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE7B,KAAK,YAAY,CACf,IAAI,SAAS,UAAU,EACvB,IAAI,SAAS,OAAO,CAAC,OAAO,SAAS,CAAC,IACpC,IAAI,SAAS,CAAC,OAAO,SAAS,CAAC,MAAM,GAAG,OAAO,SAAS,CAAC,QAAQ,CAAC,GACpE,MAAM,GACN,mBAAmB,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CACxC;AAED,uFAAuF;AACvF,wBACS,UAAU,CACjB,GAAG,SAAS,UAAU,EACtB,IAAI,SAAS,OAAO,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,MAAM,EAChE,EAAE,SAAS,OAAO,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,MAAM,EAE9D,GAAG,EAAE,GAAG,EACR,IAAI,GAAE,IAA6B,EACnC,EAAE,GAAE,EAAyB,WAGd,aAAa,GAAG,EAAE,IAAI,CAAC,2BAIvC;AAED,sFAAsF;AACtF,wBACS,IAAI,CACX,GAAG,SAAS,UAAU,EACtB,IAAI,SAAS,OAAO,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,MAAM,EAChE,EAAE,SAAS,OAAO,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,MAAM,EAE9D,KAAK,EAAE,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,EAC9B,IAAI,EAAE,GAAG,EACT,IAAI,CAAC,EAAE,IAAI,EACX,EAAE,CAAC,EAAE,EAAE,yBAGR"}

View file

@ -0,0 +1,34 @@
import createMask from './factory.js';
import IMask from '../core/holder.js';
import '../core/utils.js';
/** Mask pipe source and destination types */
const PIPE_TYPE = {
MASKED: 'value',
UNMASKED: 'unmaskedValue',
TYPED: 'typedValue'
};
/** Creates new pipe function depending on mask type, source and destination options */
function createPipe(arg, from, to) {
if (from === void 0) {
from = PIPE_TYPE.MASKED;
}
if (to === void 0) {
to = PIPE_TYPE.MASKED;
}
const masked = createMask(arg);
return value => masked.runIsolated(m => {
m[from] = value;
return m[to];
});
}
/** Pipes value through mask depending on mask type, source and destination options */
function pipe(value, mask, from, to) {
return createPipe(mask, from, to)(value);
}
IMask.PIPE_TYPE = PIPE_TYPE;
IMask.createPipe = createPipe;
IMask.pipe = pipe;
export { PIPE_TYPE, createPipe, pipe };

View file

@ -0,0 +1,29 @@
import ChangeDetails from '../core/change-details';
import { type AppendFlags } from './base';
import MaskedPattern, { MaskedPatternState, type MaskedPatternOptions } from './pattern';
type MaskedRangePatternOptions = MaskedPatternOptions & Pick<MaskedRange, 'from' | 'to'> & Partial<Pick<MaskedRange, 'maxLength'>>;
export type MaskedRangeOptions = Omit<MaskedRangePatternOptions, 'mask'>;
/** Pattern which accepts ranges */
export default class MaskedRange extends MaskedPattern {
/**
Optionally sets max length of pattern.
Used when pattern length is longer then `to` param length. Pads zeros at start in this case.
*/
maxLength: number;
/** Min bound */
from: number;
/** Max bound */
to: number;
get _matchFrom(): number;
constructor(opts?: MaskedRangeOptions);
updateOptions(opts: Partial<MaskedRangeOptions>): void;
_update(opts: Partial<MaskedRangeOptions>): void;
get isComplete(): boolean;
boundaries(str: string): [string, string];
doPrepareChar(ch: string, flags?: AppendFlags): [string, ChangeDetails];
_appendCharRaw(ch: string, flags?: AppendFlags<MaskedPatternState>): ChangeDetails;
doValidate(flags: AppendFlags): boolean;
pad(flags?: AppendFlags): ChangeDetails;
}
export {};
//# sourceMappingURL=range.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"range.d.ts","sourceRoot":"","sources":["../../src/masked/range.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,aAAa,EAAE,EAAE,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAGzF,KAAK,yBAAyB,GAAG,oBAAoB,GACnD,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;AAE1C,MAAM,MACD,kBAAkB,GAAG,IAAI,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;AAGlE,mCAAmC;AACnC,MAAM,CAAC,OAAO,OACR,WAAY,SAAQ,aAAa;IACrC;;;MAGE;IACM,SAAS,EAAE,MAAM,CAAC;IAC1B,gBAAgB;IACR,IAAI,EAAE,MAAM,CAAC;IACrB,gBAAgB;IACR,EAAE,EAAE,MAAM,CAAC;IAEnB,IAAI,UAAU,IAAK,MAAM,CAExB;gBAEY,IAAI,CAAC,EAAE,kBAAkB;IAI7B,aAAa,CAAE,IAAI,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAIhD,OAAO,CAAE,IAAI,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAuBnD,IAAa,UAAU,IAAK,OAAO,CAElC;IAED,UAAU,CAAE,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAejC,aAAa,CAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,WAAc,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC;IAS1E,cAAc,CAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,WAAW,CAAC,kBAAkB,CAAI,GAAG,aAAa;IAoBrF,UAAU,CAAE,KAAK,EAAE,WAAW,GAAG,OAAO;IAYxC,GAAG,CAAE,KAAK,CAAC,EAAE,WAAW,GAAG,aAAa;CAmBlD"}

View file

@ -0,0 +1,120 @@
import ChangeDetails from '../core/change-details.js';
import IMask from '../core/holder.js';
import MaskedPattern from './pattern.js';
import '../core/utils.js';
import './base.js';
import '../core/continuous-tail-details.js';
import './factory.js';
import './pattern/chunk-tail-details.js';
import './pattern/cursor.js';
import './pattern/fixed-definition.js';
import './pattern/input-definition.js';
import './regexp.js';
/** Pattern which accepts ranges */
class MaskedRange extends MaskedPattern {
/**
Optionally sets max length of pattern.
Used when pattern length is longer then `to` param length. Pads zeros at start in this case.
*/
/** Min bound */
/** Max bound */
get _matchFrom() {
return this.maxLength - String(this.from).length;
}
constructor(opts) {
super(opts); // mask will be created in _update
}
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
const {
to = this.to || 0,
from = this.from || 0,
maxLength = this.maxLength || 0,
autofix = this.autofix,
...patternOpts
} = opts;
this.to = to;
this.from = from;
this.maxLength = Math.max(String(to).length, maxLength);
this.autofix = autofix;
const fromStr = String(this.from).padStart(this.maxLength, '0');
const toStr = String(this.to).padStart(this.maxLength, '0');
let sameCharsCount = 0;
while (sameCharsCount < toStr.length && toStr[sameCharsCount] === fromStr[sameCharsCount]) ++sameCharsCount;
patternOpts.mask = toStr.slice(0, sameCharsCount).replace(/0/g, '\\0') + '0'.repeat(this.maxLength - sameCharsCount);
super._update(patternOpts);
}
get isComplete() {
return super.isComplete && Boolean(this.value);
}
boundaries(str) {
let minstr = '';
let maxstr = '';
const [, placeholder, num] = str.match(/^(\D*)(\d*)(\D*)/) || [];
if (num) {
minstr = '0'.repeat(placeholder.length) + num;
maxstr = '9'.repeat(placeholder.length) + num;
}
minstr = minstr.padEnd(this.maxLength, '0');
maxstr = maxstr.padEnd(this.maxLength, '9');
return [minstr, maxstr];
}
doPrepareChar(ch, flags) {
if (flags === void 0) {
flags = {};
}
let details;
[ch, details] = super.doPrepareChar(ch.replace(/\D/g, ''), flags);
if (!ch) details.skip = !this.isComplete;
return [ch, details];
}
_appendCharRaw(ch, flags) {
if (flags === void 0) {
flags = {};
}
if (!this.autofix || this.value.length + 1 > this.maxLength) return super._appendCharRaw(ch, flags);
const fromStr = String(this.from).padStart(this.maxLength, '0');
const toStr = String(this.to).padStart(this.maxLength, '0');
const [minstr, maxstr] = this.boundaries(this.value + ch);
if (Number(maxstr) < this.from) return super._appendCharRaw(fromStr[this.value.length], flags);
if (Number(minstr) > this.to) {
if (!flags.tail && this.autofix === 'pad' && this.value.length + 1 < this.maxLength) {
return super._appendCharRaw(fromStr[this.value.length], flags).aggregate(this._appendCharRaw(ch, flags));
}
return super._appendCharRaw(toStr[this.value.length], flags);
}
return super._appendCharRaw(ch, flags);
}
doValidate(flags) {
const str = this.value;
const firstNonZero = str.search(/[^0]/);
if (firstNonZero === -1 && str.length <= this._matchFrom) return true;
const [minstr, maxstr] = this.boundaries(str);
return this.from <= Number(maxstr) && Number(minstr) <= this.to && super.doValidate(flags);
}
pad(flags) {
const details = new ChangeDetails();
if (this.value.length === this.maxLength) return details;
const value = this.value;
const padLength = this.maxLength - this.value.length;
if (padLength) {
this.reset();
for (let i = 0; i < padLength; ++i) {
details.aggregate(super._appendCharRaw('0', flags));
}
// append tail
value.split('').forEach(ch => this._appendCharRaw(ch));
}
return details;
}
}
IMask.MaskedRange = MaskedRange;
export { MaskedRange as default };

View file

@ -0,0 +1,18 @@
import Masked, { type MaskedOptions } from './base';
export type MaskedRegExpOptions = MaskedOptions<MaskedRegExp>;
/** Masking by RegExp */
export default class MaskedRegExp extends Masked<string> {
/** */
mask: RegExp;
/** Enable characters overwriting */
overwrite?: boolean | 'shift' | undefined;
/** */
eager?: boolean | 'remove' | 'append' | undefined;
/** */
skipInvalid?: boolean | undefined;
/** */
autofix?: boolean | 'pad' | undefined;
updateOptions(opts: Partial<MaskedRegExpOptions>): void;
_update(opts: Partial<MaskedRegExpOptions>): void;
}
//# sourceMappingURL=regexp.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"regexp.d.ts","sourceRoot":"","sources":["../../src/masked/regexp.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,EAAE,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAIpD,MAAM,MACD,mBAAmB,GAAG,aAAa,CAAC,YAAY,CAAC,CAAC;AAEvD,wBAAwB;AACxB,MAAM,CAAC,OAAO,OACR,YAAa,SAAQ,MAAM,CAAC,MAAM,CAAC;IACvC,MAAM;IACE,IAAI,EAAE,MAAM,CAAC;IACrB,oCAAoC;IAC5B,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IAClD,MAAM;IACE,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1D,MAAM;IACE,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,MAAM;IACE,OAAO,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;IAErC,aAAa,CAAE,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAIjD,OAAO,CAAE,IAAI,EAAE,OAAO,CAAC,mBAAmB,CAAC;CAKrD"}

View file

@ -0,0 +1,30 @@
import Masked from './base.js';
import IMask from '../core/holder.js';
import '../core/change-details.js';
import '../core/continuous-tail-details.js';
import '../core/utils.js';
/** Masking by RegExp */
class MaskedRegExp extends Masked {
/** */
/** Enable characters overwriting */
/** */
/** */
/** */
updateOptions(opts) {
super.updateOptions(opts);
}
_update(opts) {
const mask = opts.mask;
if (mask) opts.validate = value => value.search(mask) >= 0;
super._update(opts);
}
}
IMask.MaskedRegExp = MaskedRegExp;
export { MaskedRegExp as default };

View file

@ -0,0 +1,28 @@
import ChangeDetails from '../core/change-details';
import { type AppendFlags } from './base';
import { type FactoryArg, type ExtendFactoryArgOptions, type UpdateOpts } from './factory';
import MaskedPattern, { type BlockExtraOptions, type MaskedPatternState } from './pattern';
import type PatternBlock from './pattern/block';
export type RepeatBlockExtraOptions = Pick<BlockExtraOptions, 'repeat'>;
export type RepeatBlockOptions = ExtendFactoryArgOptions<RepeatBlockExtraOptions>;
/** Pattern mask */
export default class RepeatBlock<M extends FactoryArg> extends MaskedPattern {
_blockOpts: M & {
repeat?: number;
};
repeat: Required<RepeatBlockExtraOptions>['repeat'];
get repeatFrom(): number;
get repeatTo(): number;
constructor(opts: RepeatBlockOptions);
updateOptions(opts: UpdateOpts<RepeatBlockOptions>): void;
_update(opts: UpdateOpts<M> & RepeatBlockExtraOptions): void;
_allocateBlock(bi: number): PatternBlock | undefined;
_appendCharRaw(ch: string, flags?: AppendFlags<MaskedPatternState>): ChangeDetails;
_trimEmptyTail(fromPos?: number, toPos?: number): void;
reset(): void;
remove(fromPos?: number, toPos?: number): ChangeDetails;
totalInputPositions(fromPos?: number, toPos?: number): number;
get state(): MaskedPatternState;
set state(state: MaskedPatternState);
}
//# sourceMappingURL=repeat.d.ts.map

View file

@ -0,0 +1 @@
{"version":3,"file":"repeat.d.ts","sourceRoot":"","sources":["../../src/masked/repeat.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAmB,EAAE,KAAK,UAAU,EAAiB,KAAK,uBAAuB,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACtH,OAAO,aAAa,EAAE,EAAE,KAAK,iBAAiB,EAA6B,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACtH,OAAO,KAAK,YAAY,MAAM,iBAAiB,CAAC;AAGhD,MAAM,MACD,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;AAEjE,MAAM,MACD,kBAAkB,GAAG,uBAAuB,CAAC,uBAAuB,CAAC,CAAC;AAG3E,mBAAmB;AACnB,MAAM,CAAC,OAAO,OACR,WAAW,CAAC,CAAC,SAAS,UAAU,CAAE,SAAQ,aAAa;IACnD,UAAU,EAAE,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,MAAM,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,CAAC;IAG5D,IAAI,UAAU,IAAK,MAAM,CAKxB;IAED,IAAI,QAAQ,IAAK,MAAM,CAEtB;gBAEY,IAAI,EAAE,kBAAkB;IAI5B,aAAa,CAAE,IAAI,EAAE,UAAU,CAAC,kBAAkB,CAAC;IAInD,OAAO,CAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,uBAAuB;IAkB/D,cAAc,CAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAS5C,cAAc,CAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,WAAW,CAAC,kBAAkB,CAAI,GAAG,aAAa;IA2B9F,cAAc,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI;IAiB/C,KAAK;IAKL,MAAM,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,GAAE,MAA+B,GAAG,aAAa;IAMjF,mBAAmB,CAAE,OAAO,GAAE,MAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAKxE,IAAa,KAAK,IAAK,kBAAkB,CAExC;IAED,IAAa,KAAK,CAAE,KAAK,EAAE,kBAAkB,EAI5C;CACF"}

Some files were not shown because too many files have changed in this diff Show more