Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@maskito/core

Package Overview
Dependencies
Maintainers
4
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@maskito/core - npm Package Compare versions

Comparing version 2.2.0 to 2.3.0

src/lib/types/maskito-element.d.ts

434

index.cjs.js

@@ -5,13 +5,231 @@ 'use strict';

const MASKITO_DEFAULT_ELEMENT_PREDICATE = e => e.querySelector('input,textarea') ||
e;
function getContentEditableSelection(element) {
const { anchorOffset = 0, focusOffset = 0 } = element.ownerDocument.getSelection() || {};
const from = Math.min(anchorOffset, focusOffset);
const to = Math.max(anchorOffset, focusOffset);
return [from, to];
}
const MASKITO_DEFAULT_OPTIONS = {
mask: /^.*$/,
preprocessors: [],
postprocessors: [],
plugins: [],
overwriteMode: 'shift',
function setContentEditableSelection(element, [from, to]) {
var _a, _b;
const document = element.ownerDocument;
const range = document.createRange();
range.setStart(element.firstChild || element, Math.min(from, ((_a = element.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0));
range.setEnd(element.lastChild || element, Math.min(to, ((_b = element.textContent) === null || _b === void 0 ? void 0 : _b.length) || 0));
const selection = document.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
}
}
class ContentEditableAdapter {
constructor(element) {
this.element = element;
this.maxLength = Infinity;
}
get value() {
return this.element.innerText.replace(/\n\n$/, '\n');
}
set value(value) {
// Setting into innerHTML of element with `white-space: pre;` style
this.element.innerHTML = value.replace(/\n$/, '\n\n');
}
get selectionStart() {
return getContentEditableSelection(this.element)[0];
}
get selectionEnd() {
return getContentEditableSelection(this.element)[1];
}
setSelectionRange(from, to) {
setContentEditableSelection(this.element, [from || 0, to || 0]);
}
}
function maskitoAdaptContentEditable(element) {
const adapter = new ContentEditableAdapter(element);
return new Proxy(element, {
get(target, prop) {
if (prop in adapter) {
return adapter[prop];
}
const nativeProperty = target[prop];
return typeof nativeProperty === 'function'
? nativeProperty.bind(target)
: nativeProperty;
},
set(target, prop, val, receiver) {
return Reflect.set(prop in adapter ? adapter : target, prop, val, receiver);
},
});
}
class EventListener {
constructor(element) {
this.element = element;
this.listeners = [];
}
listen(eventType, fn, options) {
const untypedFn = fn;
this.element.addEventListener(eventType, untypedFn, options);
this.listeners.push(() => this.element.removeEventListener(eventType, untypedFn));
}
destroy() {
this.listeners.forEach(stopListen => stopListen());
}
}
const HotkeyModifier = {
CTRL: 1 << 0,
ALT: 1 << 1,
SHIFT: 1 << 2,
META: 1 << 3,
};
// TODO add variants that can be processed correctly
const HotkeyCode = {
Y: 89,
Z: 90,
};
/**
* Checks if the passed keyboard event match the required hotkey.
*
* @example
* input.addEventListener('keydown', (event) => {
* if (isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z)) {
* // redo hotkey pressed
* }
* })
*
* @return will return `true` only if the {@link HotkeyCode} matches and only the necessary
* {@link HotkeyModifier modifiers} have been pressed
*/
function isHotkey(event, modifiers, hotkeyCode) {
return (event.ctrlKey === !!(modifiers & HotkeyModifier.CTRL) &&
event.altKey === !!(modifiers & HotkeyModifier.ALT) &&
event.shiftKey === !!(modifiers & HotkeyModifier.SHIFT) &&
event.metaKey === !!(modifiers & HotkeyModifier.META) &&
/**
* We intentionally use legacy {@link KeyboardEvent#keyCode `keyCode`} property. It is more
* "keyboard-layout"-independent than {@link KeyboardEvent#key `key`} or {@link KeyboardEvent#code `code`} properties.
* @see {@link https://github.com/taiga-family/maskito/issues/315 `KeyboardEvent#code` issue}
*/
// eslint-disable-next-line sonar/deprecation
event.keyCode === hotkeyCode);
}
function isRedo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Y) || // Windows
isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META | HotkeyModifier.SHIFT, HotkeyCode.Z) // macOS & iOS
);
}
function isUndo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META, HotkeyCode.Z) // macOS & iOS
);
}
/**
* Sets value to element, and dispatches input event
* if you passed ELementState, it also sets selection range
*
* @example
* maskitoUpdateElement(input, newValue);
* maskitoUpdateElement(input, elementState);
*
* @see {@link https://github.com/taiga-family/maskito/issues/804 issue}
*
* @return void
*/
function maskitoUpdateElement(element, valueOrElementState) {
var _a;
const initialValue = element.value;
if (typeof valueOrElementState === 'string') {
element.value = valueOrElementState;
}
else {
const [from, to] = valueOrElementState.selection;
element.value = valueOrElementState.value;
if (element.matches(':focus')) {
(_a = element.setSelectionRange) === null || _a === void 0 ? void 0 : _a.call(element, from, to);
}
}
if (element.value !== initialValue) {
element.dispatchEvent(new Event('input',
/**
* React handles this event only on bubbling phase
*
* here is the list of events that are processed in the capture stage, others are processed in the bubbling stage
* https://github.com/facebook/react/blob/cb2439624f43c510007f65aea5c50a8bb97917e4/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js#L222
*/
{ bubbles: true }));
}
}
function areElementValuesEqual(sampleState, ...states) {
return states.every(({ value }) => value === sampleState.value);
}
function areElementStatesEqual(sampleState, ...states) {
return states.every(({ value, selection }) => value === sampleState.value &&
selection[0] === sampleState.selection[0] &&
selection[1] === sampleState.selection[1]);
}
function getLineSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const nearestBreak = isForward
? value.slice(from).indexOf('\n') + 1 || value.length
: value.slice(0, to).lastIndexOf('\n') + 1;
const selectFrom = isForward ? from : nearestBreak;
const selectTo = isForward ? nearestBreak : to;
return [selectFrom, selectTo];
}
function getNotEmptySelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const notEmptySelection = isForward ? [from, to + 1] : [from - 1, to];
return notEmptySelection.map(x => Math.min(Math.max(x, 0), value.length));
}
const TRAILING_SPACES_REG = /\s+$/g;
const LEADING_SPACES_REG = /^\s+/g;
const SPACE_REG = /\s/;
function getWordSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
if (isForward) {
const valueAfterSelectionStart = value.slice(from);
const [leadingSpaces] = valueAfterSelectionStart.match(LEADING_SPACES_REG) || [
'',
];
const nearestWordEndIndex = valueAfterSelectionStart
.trimStart()
.search(SPACE_REG);
return [
from,
nearestWordEndIndex !== -1
? from + leadingSpaces.length + nearestWordEndIndex
: value.length,
];
}
const valueBeforeSelectionEnd = value.slice(0, to);
const [trailingSpaces] = valueBeforeSelectionEnd.match(TRAILING_SPACES_REG) || [''];
const selectedWordLength = valueBeforeSelectionEnd
.trimEnd()
.split('')
.reverse()
.findIndex(char => char.match(SPACE_REG));
return [
selectedWordLength !== -1 ? to - trailingSpaces.length - selectedWordLength : 0,
to,
];
}
class MaskHistory {

@@ -59,11 +277,2 @@ constructor() {

function areElementValuesEqual(sampleState, ...states) {
return states.every(({ value }) => value === sampleState.value);
}
function areElementStatesEqual(sampleState, ...states) {
return states.every(({ value, selection }) => value === sampleState.value &&
selection[0] === sampleState.selection[0] &&
selection[1] === sampleState.selection[1]);
}
function applyOverwriteMode({ value, selection }, newCharacters, mode) {

@@ -261,162 +470,2 @@ const [from, to] = selection;

class EventListener {
constructor(element) {
this.element = element;
this.listeners = [];
}
listen(eventType, fn, options) {
const untypedFn = fn;
this.element.addEventListener(eventType, untypedFn, options);
this.listeners.push(() => this.element.removeEventListener(eventType, untypedFn));
}
destroy() {
this.listeners.forEach(stopListen => stopListen());
}
}
const HotkeyModifier = {
CTRL: 1 << 0,
ALT: 1 << 1,
SHIFT: 1 << 2,
META: 1 << 3,
};
// TODO add variants that can be processed correctly
const HotkeyCode = {
Y: 89,
Z: 90,
};
/**
* Checks if the passed keyboard event match the required hotkey.
*
* @example
* input.addEventListener('keydown', (event) => {
* if (isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z)) {
* // redo hotkey pressed
* }
* })
*
* @return will return `true` only if the {@link HotkeyCode} matches and only the necessary
* {@link HotkeyModifier modifiers} have been pressed
*/
function isHotkey(event, modifiers, hotkeyCode) {
return (event.ctrlKey === !!(modifiers & HotkeyModifier.CTRL) &&
event.altKey === !!(modifiers & HotkeyModifier.ALT) &&
event.shiftKey === !!(modifiers & HotkeyModifier.SHIFT) &&
event.metaKey === !!(modifiers & HotkeyModifier.META) &&
/**
* We intentionally use legacy {@link KeyboardEvent#keyCode `keyCode`} property. It is more
* "keyboard-layout"-independent than {@link KeyboardEvent#key `key`} or {@link KeyboardEvent#code `code`} properties.
* @see {@link https://github.com/taiga-family/maskito/issues/315 `KeyboardEvent#code` issue}
*/
// eslint-disable-next-line sonar/deprecation
event.keyCode === hotkeyCode);
}
function isRedo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Y) || // Windows
isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META | HotkeyModifier.SHIFT, HotkeyCode.Z) // macOS & iOS
);
}
function isUndo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META, HotkeyCode.Z) // macOS & iOS
);
}
/**
* Sets value to element, and dispatches input event
* if you passed ELementState, it also sets selection range
*
* @example
* maskitoUpdateElement(input, newValue);
* maskitoUpdateElement(input, elementState);
*
* @see {@link https://github.com/taiga-family/maskito/issues/804 issue}
*
* @return void
*/
function maskitoUpdateElement(element, valueOrElementState) {
var _a;
const initialValue = element.value;
if (typeof valueOrElementState === 'string') {
element.value = valueOrElementState;
}
else {
const [from, to] = valueOrElementState.selection;
element.value = valueOrElementState.value;
if (element.matches(':focus')) {
(_a = element.setSelectionRange) === null || _a === void 0 ? void 0 : _a.call(element, from, to);
}
}
if (element.value !== initialValue) {
element.dispatchEvent(new Event('input',
/**
* React handles this event only on bubbling phase
*
* here is the list of events that are processed in the capture stage, others are processed in the bubbling stage
* https://github.com/facebook/react/blob/cb2439624f43c510007f65aea5c50a8bb97917e4/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js#L222
*/
{ bubbles: true }));
}
}
function getLineSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const nearestBreak = isForward
? value.slice(from).indexOf('\n') + 1 || value.length
: value.slice(0, to).lastIndexOf('\n') + 1;
const selectFrom = isForward ? from : nearestBreak;
const selectTo = isForward ? nearestBreak : to;
return [selectFrom, selectTo];
}
function getNotEmptySelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const notEmptySelection = isForward ? [from, to + 1] : [from - 1, to];
return notEmptySelection.map(x => Math.min(Math.max(x, 0), value.length));
}
const TRAILING_SPACES_REG = /\s+$/g;
const LEADING_SPACES_REG = /^\s+/g;
const SPACE_REG = /\s/;
function getWordSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
if (isForward) {
const valueAfterSelectionStart = value.slice(from);
const [leadingSpaces] = valueAfterSelectionStart.match(LEADING_SPACES_REG) || [
'',
];
const nearestWordEndIndex = valueAfterSelectionStart
.trimStart()
.search(SPACE_REG);
return [
from,
nearestWordEndIndex !== -1
? from + leadingSpaces.length + nearestWordEndIndex
: value.length,
];
}
const valueBeforeSelectionEnd = value.slice(0, to);
const [trailingSpaces] = valueBeforeSelectionEnd.match(TRAILING_SPACES_REG) || [''];
const selectedWordLength = valueBeforeSelectionEnd
.trimEnd()
.split('')
.reverse()
.findIndex(char => char.match(SPACE_REG));
return [
selectedWordLength !== -1 ? to - trailingSpaces.length - selectedWordLength : 0,
to,
];
}
/* eslint-disable @typescript-eslint/ban-types */

@@ -479,2 +528,15 @@ /**

const MASKITO_DEFAULT_ELEMENT_PREDICATE = e => e.isContentEditable
? maskitoAdaptContentEditable(e)
: e.querySelector('input,textarea') ||
e;
const MASKITO_DEFAULT_OPTIONS = {
mask: /^.*$/,
preprocessors: [],
postprocessors: [],
plugins: [],
overwriteMode: 'shift',
};
class Maskito extends MaskHistory {

@@ -503,2 +565,3 @@ constructor(element, maskitoOptions) {

this.eventListener.listen('beforeinput', event => {
var _a;
const isForward = event.inputType.includes('Forward');

@@ -543,2 +606,3 @@ this.updateHistory(this.elementState);

case 'insertLineBreak':
case 'insertParagraph':
return this.handleEnter(event);

@@ -549,3 +613,7 @@ case 'insertFromPaste':

default:
return this.handleInsert(event, event.data || '');
return this.handleInsert(event, event.data ||
(
// `event.data` for `contentEditable` is always `null` for paste/drop events
(_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text/plain')) ||
'');
}

@@ -629,3 +697,5 @@ });

initialState.value.slice(initialTo);
if (newPossibleValue === newElementState.value && !force) {
if (newPossibleValue === newElementState.value &&
!force &&
!this.element.isContentEditable) {
return;

@@ -665,3 +735,4 @@ }

}
if (newPossibleValue !== newElementState.value) {
if (newPossibleValue !== newElementState.value ||
this.element.isContentEditable) {
event.preventDefault();

@@ -676,3 +747,3 @@ this.updateElementState(newElementState, {

handleEnter(event) {
if (this.isTextArea) {
if (this.isTextArea || this.element.isContentEditable) {
this.handleInsert(event, '\n');

@@ -686,2 +757,3 @@ }

exports.Maskito = Maskito;
exports.maskitoAdaptContentEditable = maskitoAdaptContentEditable;
exports.maskitoInitialCalibrationPlugin = maskitoInitialCalibrationPlugin;

@@ -688,0 +760,0 @@ exports.maskitoPipe = maskitoPipe;

@@ -1,12 +0,230 @@

const MASKITO_DEFAULT_ELEMENT_PREDICATE = e => e.querySelector('input,textarea') ||
e;
function getContentEditableSelection(element) {
const { anchorOffset = 0, focusOffset = 0 } = element.ownerDocument.getSelection() || {};
const from = Math.min(anchorOffset, focusOffset);
const to = Math.max(anchorOffset, focusOffset);
return [from, to];
}
const MASKITO_DEFAULT_OPTIONS = {
mask: /^.*$/,
preprocessors: [],
postprocessors: [],
plugins: [],
overwriteMode: 'shift',
function setContentEditableSelection(element, [from, to]) {
var _a, _b;
const document = element.ownerDocument;
const range = document.createRange();
range.setStart(element.firstChild || element, Math.min(from, ((_a = element.textContent) === null || _a === void 0 ? void 0 : _a.length) || 0));
range.setEnd(element.lastChild || element, Math.min(to, ((_b = element.textContent) === null || _b === void 0 ? void 0 : _b.length) || 0));
const selection = document.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
}
}
class ContentEditableAdapter {
constructor(element) {
this.element = element;
this.maxLength = Infinity;
}
get value() {
return this.element.innerText.replace(/\n\n$/, '\n');
}
set value(value) {
// Setting into innerHTML of element with `white-space: pre;` style
this.element.innerHTML = value.replace(/\n$/, '\n\n');
}
get selectionStart() {
return getContentEditableSelection(this.element)[0];
}
get selectionEnd() {
return getContentEditableSelection(this.element)[1];
}
setSelectionRange(from, to) {
setContentEditableSelection(this.element, [from || 0, to || 0]);
}
}
function maskitoAdaptContentEditable(element) {
const adapter = new ContentEditableAdapter(element);
return new Proxy(element, {
get(target, prop) {
if (prop in adapter) {
return adapter[prop];
}
const nativeProperty = target[prop];
return typeof nativeProperty === 'function'
? nativeProperty.bind(target)
: nativeProperty;
},
set(target, prop, val, receiver) {
return Reflect.set(prop in adapter ? adapter : target, prop, val, receiver);
},
});
}
class EventListener {
constructor(element) {
this.element = element;
this.listeners = [];
}
listen(eventType, fn, options) {
const untypedFn = fn;
this.element.addEventListener(eventType, untypedFn, options);
this.listeners.push(() => this.element.removeEventListener(eventType, untypedFn));
}
destroy() {
this.listeners.forEach(stopListen => stopListen());
}
}
const HotkeyModifier = {
CTRL: 1 << 0,
ALT: 1 << 1,
SHIFT: 1 << 2,
META: 1 << 3,
};
// TODO add variants that can be processed correctly
const HotkeyCode = {
Y: 89,
Z: 90,
};
/**
* Checks if the passed keyboard event match the required hotkey.
*
* @example
* input.addEventListener('keydown', (event) => {
* if (isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z)) {
* // redo hotkey pressed
* }
* })
*
* @return will return `true` only if the {@link HotkeyCode} matches and only the necessary
* {@link HotkeyModifier modifiers} have been pressed
*/
function isHotkey(event, modifiers, hotkeyCode) {
return (event.ctrlKey === !!(modifiers & HotkeyModifier.CTRL) &&
event.altKey === !!(modifiers & HotkeyModifier.ALT) &&
event.shiftKey === !!(modifiers & HotkeyModifier.SHIFT) &&
event.metaKey === !!(modifiers & HotkeyModifier.META) &&
/**
* We intentionally use legacy {@link KeyboardEvent#keyCode `keyCode`} property. It is more
* "keyboard-layout"-independent than {@link KeyboardEvent#key `key`} or {@link KeyboardEvent#code `code`} properties.
* @see {@link https://github.com/taiga-family/maskito/issues/315 `KeyboardEvent#code` issue}
*/
// eslint-disable-next-line sonar/deprecation
event.keyCode === hotkeyCode);
}
function isRedo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Y) || // Windows
isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META | HotkeyModifier.SHIFT, HotkeyCode.Z) // macOS & iOS
);
}
function isUndo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META, HotkeyCode.Z) // macOS & iOS
);
}
/**
* Sets value to element, and dispatches input event
* if you passed ELementState, it also sets selection range
*
* @example
* maskitoUpdateElement(input, newValue);
* maskitoUpdateElement(input, elementState);
*
* @see {@link https://github.com/taiga-family/maskito/issues/804 issue}
*
* @return void
*/
function maskitoUpdateElement(element, valueOrElementState) {
var _a;
const initialValue = element.value;
if (typeof valueOrElementState === 'string') {
element.value = valueOrElementState;
}
else {
const [from, to] = valueOrElementState.selection;
element.value = valueOrElementState.value;
if (element.matches(':focus')) {
(_a = element.setSelectionRange) === null || _a === void 0 ? void 0 : _a.call(element, from, to);
}
}
if (element.value !== initialValue) {
element.dispatchEvent(new Event('input',
/**
* React handles this event only on bubbling phase
*
* here is the list of events that are processed in the capture stage, others are processed in the bubbling stage
* https://github.com/facebook/react/blob/cb2439624f43c510007f65aea5c50a8bb97917e4/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js#L222
*/
{ bubbles: true }));
}
}
function areElementValuesEqual(sampleState, ...states) {
return states.every(({ value }) => value === sampleState.value);
}
function areElementStatesEqual(sampleState, ...states) {
return states.every(({ value, selection }) => value === sampleState.value &&
selection[0] === sampleState.selection[0] &&
selection[1] === sampleState.selection[1]);
}
function getLineSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const nearestBreak = isForward
? value.slice(from).indexOf('\n') + 1 || value.length
: value.slice(0, to).lastIndexOf('\n') + 1;
const selectFrom = isForward ? from : nearestBreak;
const selectTo = isForward ? nearestBreak : to;
return [selectFrom, selectTo];
}
function getNotEmptySelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const notEmptySelection = isForward ? [from, to + 1] : [from - 1, to];
return notEmptySelection.map(x => Math.min(Math.max(x, 0), value.length));
}
const TRAILING_SPACES_REG = /\s+$/g;
const LEADING_SPACES_REG = /^\s+/g;
const SPACE_REG = /\s/;
function getWordSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
if (isForward) {
const valueAfterSelectionStart = value.slice(from);
const [leadingSpaces] = valueAfterSelectionStart.match(LEADING_SPACES_REG) || [
'',
];
const nearestWordEndIndex = valueAfterSelectionStart
.trimStart()
.search(SPACE_REG);
return [
from,
nearestWordEndIndex !== -1
? from + leadingSpaces.length + nearestWordEndIndex
: value.length,
];
}
const valueBeforeSelectionEnd = value.slice(0, to);
const [trailingSpaces] = valueBeforeSelectionEnd.match(TRAILING_SPACES_REG) || [''];
const selectedWordLength = valueBeforeSelectionEnd
.trimEnd()
.split('')
.reverse()
.findIndex(char => char.match(SPACE_REG));
return [
selectedWordLength !== -1 ? to - trailingSpaces.length - selectedWordLength : 0,
to,
];
}
class MaskHistory {

@@ -54,11 +272,2 @@ constructor() {

function areElementValuesEqual(sampleState, ...states) {
return states.every(({ value }) => value === sampleState.value);
}
function areElementStatesEqual(sampleState, ...states) {
return states.every(({ value, selection }) => value === sampleState.value &&
selection[0] === sampleState.selection[0] &&
selection[1] === sampleState.selection[1]);
}
function applyOverwriteMode({ value, selection }, newCharacters, mode) {

@@ -256,162 +465,2 @@ const [from, to] = selection;

class EventListener {
constructor(element) {
this.element = element;
this.listeners = [];
}
listen(eventType, fn, options) {
const untypedFn = fn;
this.element.addEventListener(eventType, untypedFn, options);
this.listeners.push(() => this.element.removeEventListener(eventType, untypedFn));
}
destroy() {
this.listeners.forEach(stopListen => stopListen());
}
}
const HotkeyModifier = {
CTRL: 1 << 0,
ALT: 1 << 1,
SHIFT: 1 << 2,
META: 1 << 3,
};
// TODO add variants that can be processed correctly
const HotkeyCode = {
Y: 89,
Z: 90,
};
/**
* Checks if the passed keyboard event match the required hotkey.
*
* @example
* input.addEventListener('keydown', (event) => {
* if (isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z)) {
* // redo hotkey pressed
* }
* })
*
* @return will return `true` only if the {@link HotkeyCode} matches and only the necessary
* {@link HotkeyModifier modifiers} have been pressed
*/
function isHotkey(event, modifiers, hotkeyCode) {
return (event.ctrlKey === !!(modifiers & HotkeyModifier.CTRL) &&
event.altKey === !!(modifiers & HotkeyModifier.ALT) &&
event.shiftKey === !!(modifiers & HotkeyModifier.SHIFT) &&
event.metaKey === !!(modifiers & HotkeyModifier.META) &&
/**
* We intentionally use legacy {@link KeyboardEvent#keyCode `keyCode`} property. It is more
* "keyboard-layout"-independent than {@link KeyboardEvent#key `key`} or {@link KeyboardEvent#code `code`} properties.
* @see {@link https://github.com/taiga-family/maskito/issues/315 `KeyboardEvent#code` issue}
*/
// eslint-disable-next-line sonar/deprecation
event.keyCode === hotkeyCode);
}
function isRedo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Y) || // Windows
isHotkey(event, HotkeyModifier.CTRL | HotkeyModifier.SHIFT, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META | HotkeyModifier.SHIFT, HotkeyCode.Z) // macOS & iOS
);
}
function isUndo(event) {
return (isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META, HotkeyCode.Z) // macOS & iOS
);
}
/**
* Sets value to element, and dispatches input event
* if you passed ELementState, it also sets selection range
*
* @example
* maskitoUpdateElement(input, newValue);
* maskitoUpdateElement(input, elementState);
*
* @see {@link https://github.com/taiga-family/maskito/issues/804 issue}
*
* @return void
*/
function maskitoUpdateElement(element, valueOrElementState) {
var _a;
const initialValue = element.value;
if (typeof valueOrElementState === 'string') {
element.value = valueOrElementState;
}
else {
const [from, to] = valueOrElementState.selection;
element.value = valueOrElementState.value;
if (element.matches(':focus')) {
(_a = element.setSelectionRange) === null || _a === void 0 ? void 0 : _a.call(element, from, to);
}
}
if (element.value !== initialValue) {
element.dispatchEvent(new Event('input',
/**
* React handles this event only on bubbling phase
*
* here is the list of events that are processed in the capture stage, others are processed in the bubbling stage
* https://github.com/facebook/react/blob/cb2439624f43c510007f65aea5c50a8bb97917e4/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js#L222
*/
{ bubbles: true }));
}
}
function getLineSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const nearestBreak = isForward
? value.slice(from).indexOf('\n') + 1 || value.length
: value.slice(0, to).lastIndexOf('\n') + 1;
const selectFrom = isForward ? from : nearestBreak;
const selectTo = isForward ? nearestBreak : to;
return [selectFrom, selectTo];
}
function getNotEmptySelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
const notEmptySelection = isForward ? [from, to + 1] : [from - 1, to];
return notEmptySelection.map(x => Math.min(Math.max(x, 0), value.length));
}
const TRAILING_SPACES_REG = /\s+$/g;
const LEADING_SPACES_REG = /^\s+/g;
const SPACE_REG = /\s/;
function getWordSelection({ value, selection }, isForward) {
const [from, to] = selection;
if (from !== to) {
return [from, to];
}
if (isForward) {
const valueAfterSelectionStart = value.slice(from);
const [leadingSpaces] = valueAfterSelectionStart.match(LEADING_SPACES_REG) || [
'',
];
const nearestWordEndIndex = valueAfterSelectionStart
.trimStart()
.search(SPACE_REG);
return [
from,
nearestWordEndIndex !== -1
? from + leadingSpaces.length + nearestWordEndIndex
: value.length,
];
}
const valueBeforeSelectionEnd = value.slice(0, to);
const [trailingSpaces] = valueBeforeSelectionEnd.match(TRAILING_SPACES_REG) || [''];
const selectedWordLength = valueBeforeSelectionEnd
.trimEnd()
.split('')
.reverse()
.findIndex(char => char.match(SPACE_REG));
return [
selectedWordLength !== -1 ? to - trailingSpaces.length - selectedWordLength : 0,
to,
];
}
/* eslint-disable @typescript-eslint/ban-types */

@@ -474,2 +523,15 @@ /**

const MASKITO_DEFAULT_ELEMENT_PREDICATE = e => e.isContentEditable
? maskitoAdaptContentEditable(e)
: e.querySelector('input,textarea') ||
e;
const MASKITO_DEFAULT_OPTIONS = {
mask: /^.*$/,
preprocessors: [],
postprocessors: [],
plugins: [],
overwriteMode: 'shift',
};
class Maskito extends MaskHistory {

@@ -498,2 +560,3 @@ constructor(element, maskitoOptions) {

this.eventListener.listen('beforeinput', event => {
var _a;
const isForward = event.inputType.includes('Forward');

@@ -538,2 +601,3 @@ this.updateHistory(this.elementState);

case 'insertLineBreak':
case 'insertParagraph':
return this.handleEnter(event);

@@ -544,3 +608,7 @@ case 'insertFromPaste':

default:
return this.handleInsert(event, event.data || '');
return this.handleInsert(event, event.data ||
(
// `event.data` for `contentEditable` is always `null` for paste/drop events
(_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData('text/plain')) ||
'');
}

@@ -624,3 +692,5 @@ });

initialState.value.slice(initialTo);
if (newPossibleValue === newElementState.value && !force) {
if (newPossibleValue === newElementState.value &&
!force &&
!this.element.isContentEditable) {
return;

@@ -660,3 +730,4 @@ }

}
if (newPossibleValue !== newElementState.value) {
if (newPossibleValue !== newElementState.value ||
this.element.isContentEditable) {
event.preventDefault();

@@ -671,3 +742,3 @@ this.updateElementState(newElementState, {

handleEnter(event) {
if (this.isTextArea) {
if (this.isTextArea || this.element.isContentEditable) {
this.handleInsert(event, '\n');

@@ -678,2 +749,2 @@ }

export { MASKITO_DEFAULT_ELEMENT_PREDICATE, MASKITO_DEFAULT_OPTIONS, Maskito, maskitoInitialCalibrationPlugin, maskitoPipe, maskitoStrictCompositionPlugin, maskitoTransform, maskitoUpdateElement };
export { MASKITO_DEFAULT_ELEMENT_PREDICATE, MASKITO_DEFAULT_OPTIONS, Maskito, maskitoAdaptContentEditable, maskitoInitialCalibrationPlugin, maskitoPipe, maskitoStrictCompositionPlugin, maskitoTransform, maskitoUpdateElement };
{
"name": "@maskito/core",
"version": "2.2.0",
"version": "2.3.0",
"description": "The main zero-dependency and framework-agnostic Maskito's package to create an input mask",

@@ -5,0 +5,0 @@ "keywords": [

export { MASKITO_DEFAULT_ELEMENT_PREDICATE, MASKITO_DEFAULT_OPTIONS, } from './lib/constants';
export { Maskito } from './lib/mask';
export { MaskitoElementPredicate, MaskitoMask, MaskitoMaskExpression, MaskitoOptions, MaskitoPlugin, MaskitoPostprocessor, MaskitoPreprocessor, } from './lib/types';
export { maskitoInitialCalibrationPlugin, maskitoPipe, maskitoStrictCompositionPlugin, maskitoTransform, maskitoUpdateElement, } from './lib/utils';
export { MaskitoElement, MaskitoElementPredicate, MaskitoMask, MaskitoMaskExpression, MaskitoOptions, MaskitoPlugin, MaskitoPostprocessor, MaskitoPreprocessor, } from './lib/types';
export { maskitoAdaptContentEditable, maskitoInitialCalibrationPlugin, maskitoPipe, maskitoStrictCompositionPlugin, maskitoTransform, maskitoUpdateElement, } from './lib/utils';
//# sourceMappingURL=index.d.ts.map
import { MaskHistory } from './classes';
import type { ElementState, MaskitoOptions, TypedInputEvent } from './types';
import type { ElementState, MaskitoElement, MaskitoOptions, TypedInputEvent } from './types';
export declare class Maskito extends MaskHistory {

@@ -12,3 +12,3 @@ private readonly element;

private readonly teardowns;
constructor(element: HTMLInputElement | HTMLTextAreaElement, maskitoOptions: MaskitoOptions);
constructor(element: MaskitoElement, maskitoOptions: MaskitoOptions);
private get elementState();

@@ -15,0 +15,0 @@ private get maxLength();

@@ -1,2 +0,3 @@

export type MaskitoElementPredicate = (element: HTMLElement) => HTMLInputElement | HTMLTextAreaElement | Promise<HTMLInputElement | HTMLTextAreaElement>;
import type { MaskitoElement } from './maskito-element';
export type MaskitoElementPredicate = (element: HTMLElement) => MaskitoElement | Promise<MaskitoElement>;
//# sourceMappingURL=element-predicate.d.ts.map

@@ -6,2 +6,3 @@ export * from './element-predicate';

export * from './mask-processors';
export * from './maskito-element';
export * from './plugin';

@@ -8,0 +9,0 @@ export * from './selection-range';

import type { MaskitoOptions } from './mask-options';
export type MaskitoPlugin = (element: HTMLInputElement | HTMLTextAreaElement, options: Required<MaskitoOptions>) => (() => void) | void;
import type { MaskitoElement } from './maskito-element';
export type MaskitoPlugin = (element: MaskitoElement, options: Required<MaskitoOptions>) => (() => void) | void;
//# sourceMappingURL=plugin.d.ts.map
export interface TypedInputEvent extends InputEvent {
inputType: 'deleteByCut' | 'deleteContentBackward' | 'deleteContentForward' | 'deleteHardLineBackward' | 'deleteHardLineForward' | 'deleteSoftLineBackward' | 'deleteSoftLineForward' | 'deleteWordBackward' | 'deleteWordForward' | 'historyRedo' | 'historyUndo' | 'insertCompositionText' | 'insertFromDrop' | 'insertFromPaste' | 'insertLineBreak' | 'insertReplacementText' | 'insertText';
inputType: 'deleteByCut' | 'deleteContentBackward' | 'deleteContentForward' | 'deleteHardLineBackward' | 'deleteHardLineForward' | 'deleteSoftLineBackward' | 'deleteSoftLineForward' | 'deleteWordBackward' | 'deleteWordForward' | 'historyRedo' | 'historyUndo' | 'insertCompositionText' | 'insertFromDrop' | 'insertFromPaste' | 'insertLineBreak' | 'insertParagraph' | 'insertReplacementText' | 'insertText';
}
//# sourceMappingURL=typed-input-event.d.ts.map

@@ -1,2 +0,2 @@

import type { ElementState } from '../../types';
import type { ElementState, MaskitoElement } from '../../types';
/**

@@ -14,3 +14,3 @@ * Sets value to element, and dispatches input event

*/
export declare function maskitoUpdateElement(element: HTMLInputElement | HTMLTextAreaElement, valueOrElementState: ElementState | string): void;
export declare function maskitoUpdateElement(element: MaskitoElement, valueOrElementState: ElementState | string): void;
//# sourceMappingURL=update-element.d.ts.map

@@ -0,3 +1,6 @@

export * from './content-editable';
export * from './dom/event-listener';
export * from './dom/get-content-editable-selection';
export * from './dom/history-events';
export * from './dom/set-content-editable-selection';
export * from './dom/update-element';

@@ -4,0 +7,0 @@ export * from './element-states-equality';

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc