Showing preview only (1,898K chars total). Download the full file or copy to clipboard to get everything.
Repository: Tinkoff/maskito
Branch: main
Commit: f79688db8ac1
Files: 757
Total size: 1.6 MB
Directory structure:
gitextract_lbehwmqa/
├── .cspell.json
├── .editorconfig
├── .firebaserc
├── .github/
│ ├── CODEOWNERS
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── 1-bug-report.yml
│ │ ├── 2-feature-request.yml
│ │ └── 3-documentation.yml
│ ├── renovate.json
│ └── workflows/
│ ├── assign-author.yml
│ ├── auto-merge.yml
│ ├── build.yml
│ ├── deploy-preview.yml
│ ├── deploy.yml
│ ├── e2e.yml
│ ├── lint.yml
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .husky/
│ ├── commit-msg
│ └── pre-commit
├── .npmrc
├── .release-it.js
├── .ws-context
├── CHANGELOG.md
├── LICENSE
├── README.md
├── codecov.yml
├── eslint.config.ts
├── firebase.json
├── jest.config.ts
├── jest.preset.js
├── nx.json
├── package.json
├── projects/
│ ├── angular/
│ │ ├── README.md
│ │ ├── jest.config.ts
│ │ ├── ng-package.json
│ │ ├── package.json
│ │ ├── project.json
│ │ ├── src/
│ │ │ ├── index.ts
│ │ │ ├── lib/
│ │ │ │ ├── maskito.directive.ts
│ │ │ │ ├── maskito.pipe.ts
│ │ │ │ ├── pattern.directive.ts
│ │ │ │ └── tests/
│ │ │ │ ├── maskito.directive.spec.ts
│ │ │ │ └── maskito.spec.ts
│ │ │ └── test-setup.ts
│ │ └── tsconfig.lib.prod.json
│ ├── core/
│ │ ├── README.md
│ │ ├── jest.config.ts
│ │ ├── package.json
│ │ ├── project.json
│ │ └── src/
│ │ ├── index.ts
│ │ └── lib/
│ │ ├── classes/
│ │ │ ├── index.ts
│ │ │ ├── mask-history.ts
│ │ │ └── mask-model/
│ │ │ ├── mask-model.ts
│ │ │ ├── tests/
│ │ │ │ ├── dynamic-mask.spec.ts
│ │ │ │ └── mask-model-fixed-characters.spec.ts
│ │ │ └── utils/
│ │ │ ├── apply-overwrite-mode.ts
│ │ │ ├── calibrate-value-by-mask.ts
│ │ │ ├── get-leading-fixed-characters.ts
│ │ │ ├── guess-valid-value-by-pattern.ts
│ │ │ ├── guess-valid-value-by-reg-exp.ts
│ │ │ ├── is-fixed-character.ts
│ │ │ ├── remove-fixed-mask-characters.ts
│ │ │ └── validate-value-with-mask.ts
│ │ ├── constants/
│ │ │ ├── default-element-predicate.ts
│ │ │ ├── default-options.ts
│ │ │ └── index.ts
│ │ ├── mask.ts
│ │ ├── plugins/
│ │ │ ├── broken-prevent-default.plugin.ts
│ │ │ ├── change-event-plugin.ts
│ │ │ ├── double-space.plugin.ts
│ │ │ ├── index.ts
│ │ │ ├── initial-calibration-plugin.ts
│ │ │ └── strict-composition-plugin.ts
│ │ ├── types/
│ │ │ ├── element-predicate.ts
│ │ │ ├── element-state.ts
│ │ │ ├── index.ts
│ │ │ ├── mask-options.ts
│ │ │ ├── mask-processors.ts
│ │ │ ├── mask.ts
│ │ │ ├── maskito-element.ts
│ │ │ ├── plugin.ts
│ │ │ ├── selection-range.ts
│ │ │ └── typed-input-event.ts
│ │ └── utils/
│ │ ├── content-editable.ts
│ │ ├── dom/
│ │ │ ├── event-listener.ts
│ │ │ ├── get-content-editable-selection.ts
│ │ │ ├── history-events.ts
│ │ │ ├── hotkey.ts
│ │ │ ├── set-content-editable-selection.ts
│ │ │ └── update-element.ts
│ │ ├── element-states-equality.ts
│ │ ├── get-line-selection.ts
│ │ ├── get-not-empty-selection.ts
│ │ ├── get-word-selection.ts
│ │ ├── index.ts
│ │ ├── pipe.ts
│ │ ├── test/
│ │ │ ├── get-not-empty-selection.spec.ts
│ │ │ ├── get-word-selection.spec.ts
│ │ │ ├── pipe.spec.ts
│ │ │ └── transform.spec.ts
│ │ └── transform.ts
│ ├── demo/
│ │ ├── .gitignore
│ │ ├── esbuild-plugins/
│ │ │ ├── maskito-as-taiga-ui-dep.plugin.js
│ │ │ └── vue-esm.plugin.js
│ │ ├── jest.config.ts
│ │ ├── package.json
│ │ ├── project.json
│ │ ├── src/
│ │ │ ├── app/
│ │ │ │ ├── app.component.html
│ │ │ │ ├── app.component.spec.ts
│ │ │ │ ├── app.component.ts
│ │ │ │ ├── app.config.ts
│ │ │ │ ├── app.routes.ts
│ │ │ │ ├── app.style.less
│ │ │ │ ├── constants/
│ │ │ │ │ ├── demo-path.ts
│ │ │ │ │ ├── doc-example-primary-tab.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── modules/
│ │ │ │ │ ├── example-primary-tabs-icons/
│ │ │ │ │ │ ├── angular-logo.component.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── javascript-logo.component.ts
│ │ │ │ │ │ ├── react-logo.component.ts
│ │ │ │ │ │ └── vue-logo.component.ts
│ │ │ │ │ └── logo/
│ │ │ │ │ ├── logo.component.ts
│ │ │ │ │ ├── logo.style.less
│ │ │ │ │ └── logo.template.html
│ │ │ │ ├── server-error-handler.ts
│ │ │ │ └── utils/
│ │ │ │ ├── add-default-tabs-processor/
│ │ │ │ │ ├── add-default-tabs-processor.ts
│ │ │ │ │ └── default-tabs/
│ │ │ │ │ ├── angular-default-tab.ts
│ │ │ │ │ ├── js-default-tab.ts
│ │ │ │ │ ├── react-default-tab.ts
│ │ │ │ │ └── vue-default-tab.ts
│ │ │ │ └── index.ts
│ │ │ ├── assets/
│ │ │ │ └── manifest.webmanifest
│ │ │ ├── environments/
│ │ │ │ ├── environment.prod.ts
│ │ │ │ └── environment.ts
│ │ │ ├── index.html
│ │ │ ├── main.server.ts
│ │ │ ├── main.ts
│ │ │ ├── pages/
│ │ │ │ ├── documentation/
│ │ │ │ │ ├── browser-support/
│ │ │ │ │ │ ├── browser-support.component.ts
│ │ │ │ │ │ └── browser-support.template.html
│ │ │ │ │ ├── core-concepts-overview/
│ │ │ │ │ │ ├── core-concepts-overview.component.ts
│ │ │ │ │ │ ├── core-concepts-overview.styles.less
│ │ │ │ │ │ ├── core-concepts-overview.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ └── maskito-public-api-demo.md
│ │ │ │ │ ├── element-state/
│ │ │ │ │ │ ├── element-state.component.ts
│ │ │ │ │ │ ├── element-state.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ └── element-state-demo.md
│ │ │ │ │ ├── mask-expression/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── basic-time-example.md
│ │ │ │ │ │ │ ├── dynamic-mask-expression-demo.md
│ │ │ │ │ │ │ └── reg-exp-mask-expression-demo.md
│ │ │ │ │ │ ├── mask-expression.component.ts
│ │ │ │ │ │ └── mask-expression.template.html
│ │ │ │ │ ├── maskito-libraries/
│ │ │ │ │ │ ├── maskito-libraries.component.ts
│ │ │ │ │ │ └── maskito-libraries.template.html
│ │ │ │ │ ├── next-steps/
│ │ │ │ │ │ ├── next-steps.component.ts
│ │ │ │ │ │ └── next-steps.template.html
│ │ │ │ │ ├── overwrite-mode/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── dynamic/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── replace/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── shift/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── overwrite-mode.component.ts
│ │ │ │ │ │ └── overwrite-mode.template.html
│ │ │ │ │ ├── plugins/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-initial-calibration/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ ├── index.md
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 2-strict-composition/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 3-change-event/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── oversimplified-number-mask.md
│ │ │ │ │ │ │ └── pads-zero-plugin.ts
│ │ │ │ │ │ ├── plugins.component.ts
│ │ │ │ │ │ ├── plugins.style.less
│ │ │ │ │ │ └── plugins.template.html
│ │ │ │ │ ├── processors/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── postprocessor-in-action.md
│ │ │ │ │ │ │ ├── preprocessor-first-arg-demo.md
│ │ │ │ │ │ │ ├── preprocessor-in-action-demo.md
│ │ │ │ │ │ │ └── processor-second-arg-demo.md
│ │ │ │ │ │ ├── processors.component.ts
│ │ │ │ │ │ └── processors.template.html
│ │ │ │ │ ├── real-world-form/
│ │ │ │ │ │ ├── index.html
│ │ │ │ │ │ ├── index.less
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── supported-input-types/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── password/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── search/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── tel/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── text/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── url/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── supported-input-types.component.ts
│ │ │ │ │ │ └── supported-input-types.template.html
│ │ │ │ │ ├── transformer/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ └── utility-in-action-demo.md
│ │ │ │ │ │ ├── transformer.component.ts
│ │ │ │ │ │ └── transformer.template.html
│ │ │ │ │ └── what-is-maskito/
│ │ │ │ │ ├── what-is-maskito.component.ts
│ │ │ │ │ ├── what-is-maskito.style.less
│ │ │ │ │ └── what-is-maskito.template.html
│ │ │ │ ├── frameworks/
│ │ │ │ │ ├── angular/
│ │ │ │ │ │ ├── angular-doc.component.ts
│ │ │ │ │ │ ├── angular-doc.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ ├── 1-nested/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── template.html
│ │ │ │ │ │ ├── 2-nested/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── template.html
│ │ │ │ │ │ ├── 3-programmatically/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── template.html
│ │ │ │ │ │ ├── 4-pipe/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── template.html
│ │ │ │ │ │ ├── 5-custom-unmask-handler/
│ │ │ │ │ │ │ ├── index.html
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── unmask.directive.ts
│ │ │ │ │ │ ├── 6-pattern/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── template.html
│ │ │ │ │ │ ├── basic-directive-approach.md
│ │ │ │ │ │ ├── custom-input-example.md
│ │ │ │ │ │ └── import-maskito.md
│ │ │ │ │ ├── react/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-use-maskito-basic-usage/
│ │ │ │ │ │ │ │ ├── example.component.tsx
│ │ │ │ │ │ │ │ └── useMaskitoBasicUsage.tsx
│ │ │ │ │ │ │ ├── 2-element-predicate/
│ │ │ │ │ │ │ │ ├── awesomeInput.tsx
│ │ │ │ │ │ │ │ ├── example.component.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── 3-merge-ref/
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── 3-react-hook-form/
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── with-maskito-register.ts
│ │ │ │ │ │ │ ├── best-bad-practice.md
│ │ │ │ │ │ │ ├── controlled-input.md
│ │ │ │ │ │ │ └── merge-ref.md
│ │ │ │ │ │ ├── react-doc.component.ts
│ │ │ │ │ │ ├── react-doc.style.less
│ │ │ │ │ │ └── react-doc.template.html
│ │ │ │ │ └── vue/
│ │ │ │ │ ├── examples/
│ │ │ │ │ │ ├── best-bad-practice.md
│ │ │ │ │ │ ├── query-nested-input.md
│ │ │ │ │ │ ├── use-maskito-basic-usage.md
│ │ │ │ │ │ └── vue-1/
│ │ │ │ │ │ └── component.ts
│ │ │ │ │ ├── vue-doc.component.ts
│ │ │ │ │ └── vue-doc.template.html
│ │ │ │ ├── kit/
│ │ │ │ │ ├── date/
│ │ │ │ │ │ ├── date-mask-doc.component.ts
│ │ │ │ │ │ ├── date-mask-doc.style.less
│ │ │ │ │ │ ├── date-mask-doc.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ ├── 1-localization/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 2-min-max/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ └── maskito-parse-stringify-date-demo.md
│ │ │ │ │ ├── date-range/
│ │ │ │ │ │ ├── date-range-mask-doc.component.ts
│ │ │ │ │ │ ├── date-range-mask-doc.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ ├── 1-date-localization/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 2-min-max/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 3-min-max-length/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ └── 4-range-separator/
│ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ └── mask.ts
│ │ │ │ │ ├── date-time/
│ │ │ │ │ │ ├── date-time-mask-doc.component.ts
│ │ │ │ │ │ ├── date-time-mask-doc.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ ├── 1-date-time-localization/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 2-date-time-separator/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 3-min-max/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 4-time-step/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 5-am-pm/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ └── maskito-parse-stringify-date-time-demo.md
│ │ │ │ │ ├── number/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-high-precision/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 2-separators/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 3-postfix/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 4-decimal-zero-padding/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 5-custom-minus-sign/
│ │ │ │ │ │ │ │ ├── components.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 6-minus-before-prefix/
│ │ │ │ │ │ │ │ ├── components.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 7-dynamic-decimal-zero-padding/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 8-thousand-separator-pattern/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 9-thousand-separator-pattern-intl/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── helpers/
│ │ │ │ │ │ │ ├── parse-number-as-bigint-type.md
│ │ │ │ │ │ │ ├── parse-number-as-number-type.md
│ │ │ │ │ │ │ ├── parse-number-invalid-usage.md
│ │ │ │ │ │ │ └── stringify-number.md
│ │ │ │ │ │ ├── number-mask-doc.component.ts
│ │ │ │ │ │ └── number-mask-doc.template.html
│ │ │ │ │ ├── plugins/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-selection-handler/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 2-caret-guard/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 3-event-handlers/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 4-reject/
│ │ │ │ │ │ │ ├── animation.css
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ ├── index.md
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── kit-plugins-doc.component.ts
│ │ │ │ │ │ └── kit-plugins-doc.template.html
│ │ │ │ │ └── time/
│ │ │ │ │ ├── examples/
│ │ │ │ │ │ ├── 1-modes/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 2-am-pm/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 3-step/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 4-affixes/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 5-time-segments-min-max/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ └── maskito-parse-stringify-time-demo.md
│ │ │ │ │ ├── time-mask-doc.component.ts
│ │ │ │ │ ├── time-mask-doc.style.less
│ │ │ │ │ └── time-mask-doc.template.html
│ │ │ │ ├── pages.ts
│ │ │ │ ├── phone/
│ │ │ │ │ ├── examples/
│ │ │ │ │ │ ├── 1-basic/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 2-validation/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 3-non-strict/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 4-lazy-metadata/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── simple.md
│ │ │ │ │ │ ├── 5-focus-blur-events/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ └── 6-national-format/
│ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ └── mask.ts
│ │ │ │ │ ├── phone-doc.component.ts
│ │ │ │ │ ├── phone-doc.style.less
│ │ │ │ │ └── phone-doc.template.html
│ │ │ │ ├── recipes/
│ │ │ │ │ ├── card/
│ │ │ │ │ │ ├── card-doc.component.ts
│ │ │ │ │ │ ├── card-doc.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ └── 1-basic/
│ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ ├── style.less
│ │ │ │ │ │ └── template.html
│ │ │ │ │ ├── content-editable/
│ │ │ │ │ │ ├── content-editable-doc.component.ts
│ │ │ │ │ │ ├── content-editable-doc.template.html
│ │ │ │ │ │ └── examples/
│ │ │ │ │ │ ├── 1-time/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── 2-multi-line/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── maskito-with-content-editable.md
│ │ │ │ │ │ └── vanilla-js-tab.md
│ │ │ │ │ ├── network-address/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-ipv6/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 2-ipv4/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 3-mac/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── network-address-doc.component.ts
│ │ │ │ │ │ └── network-address-doc.template.html
│ │ │ │ │ ├── phone/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-us-phone/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 2-kz-phone/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ ├── mask.ts
│ │ │ │ │ │ │ └── template.html
│ │ │ │ │ │ ├── phone-doc.component.ts
│ │ │ │ │ │ └── phone-doc.template.html
│ │ │ │ │ ├── placeholder/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-cvc-code/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ ├── 2-phone/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 3-date/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── placeholder-doc.component.ts
│ │ │ │ │ │ └── placeholder-doc.template.html
│ │ │ │ │ ├── postfix/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-pattern-mask/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 2-postprocessor/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── postfix-doc.component.ts
│ │ │ │ │ │ └── postfix-doc.template.html
│ │ │ │ │ ├── prefix/
│ │ │ │ │ │ ├── examples/
│ │ │ │ │ │ │ ├── 1-pattern-mask/
│ │ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ │ └── 2-postprocessor/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ ├── prefix-doc.component.ts
│ │ │ │ │ │ └── prefix-doc.template.html
│ │ │ │ │ └── textarea/
│ │ │ │ │ ├── examples/
│ │ │ │ │ │ ├── 1-latin/
│ │ │ │ │ │ │ ├── component.ts
│ │ │ │ │ │ │ └── mask.ts
│ │ │ │ │ │ └── maskito-with-textarea.md
│ │ │ │ │ ├── textarea-doc.component.ts
│ │ │ │ │ └── textarea-doc.template.html
│ │ │ │ └── stackblitz/
│ │ │ │ ├── components/
│ │ │ │ │ ├── stackblitz-edit-button/
│ │ │ │ │ │ ├── stackblitz-edit-button.component.ts
│ │ │ │ │ │ └── stackblitz-edit-button.style.less
│ │ │ │ │ └── stackblitz-starter/
│ │ │ │ │ ├── stackblitz-starter.component.ts
│ │ │ │ │ └── stackblitz-starter.style.less
│ │ │ │ ├── files/
│ │ │ │ │ ├── example.ts.md
│ │ │ │ │ ├── starter.ts.md
│ │ │ │ │ └── styles.css
│ │ │ │ ├── index.ts
│ │ │ │ └── stackblitz.service.ts
│ │ │ ├── server.ts
│ │ │ ├── styles.less
│ │ │ ├── test-setup.ts
│ │ │ └── typings.d.ts
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.typecheck.json
│ ├── demo-integrations/
│ │ ├── cypress-react.config.ts
│ │ ├── cypress.config.ts
│ │ ├── package.json
│ │ ├── project.json
│ │ ├── src/
│ │ │ ├── fixtures/
│ │ │ │ └── example.json
│ │ │ ├── plugins/
│ │ │ │ └── index.js
│ │ │ ├── support/
│ │ │ │ ├── assertions/
│ │ │ │ │ ├── have-ng-control-value.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── commands/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── paste.ts
│ │ │ │ │ └── smart-tick.ts
│ │ │ │ ├── component-index.html
│ │ │ │ ├── component-react.ts
│ │ │ │ ├── component.ts
│ │ │ │ ├── constants/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── real-events-support.ts
│ │ │ │ └── e2e.ts
│ │ │ └── tests/
│ │ │ ├── addons/
│ │ │ │ └── phone/
│ │ │ │ ├── phone-basic.cy.ts
│ │ │ │ ├── phone-national-trunk-prefix.cy.ts
│ │ │ │ ├── phone-non-strict.cy.ts
│ │ │ │ ├── phone-separator.cy.ts
│ │ │ │ └── phone-strict.cy.ts
│ │ │ ├── angular/
│ │ │ │ ├── form-control-changes.cy.ts
│ │ │ │ └── unmask-handler.cy.ts
│ │ │ ├── component-testing/
│ │ │ │ ├── angular/
│ │ │ │ │ ├── disable-mask-on-null.cy.ts
│ │ │ │ │ └── pattern.cy.ts
│ │ │ │ ├── angular-predicate/
│ │ │ │ │ ├── angular-predicate.cy.ts
│ │ │ │ │ └── multi-test.component.ts
│ │ │ │ ├── change-event-plugin/
│ │ │ │ │ └── change-event-plugin.cy.ts
│ │ │ │ ├── initial-calibration-plugin/
│ │ │ │ │ └── dispatch-event.cy.ts
│ │ │ │ ├── multi-character-date-segment-separator/
│ │ │ │ │ └── multi-character-date-segment-separator.cy.ts
│ │ │ │ ├── native-max-length/
│ │ │ │ │ └── native-maxlength-attribute.cy.ts
│ │ │ │ ├── native-select-method/
│ │ │ │ │ └── native-select-method.cy.ts
│ │ │ │ ├── number/
│ │ │ │ │ ├── alone-decimal-separator.cy.ts
│ │ │ │ │ ├── min-max-bigint.cy.ts
│ │ │ │ │ ├── mirrored-prefix-postfix.cy.ts
│ │ │ │ │ ├── mirrored-value-postfix.cy.ts
│ │ │ │ │ ├── multi-character-prefix.cy.ts
│ │ │ │ │ ├── overwrite-selection-range.cy.ts
│ │ │ │ │ ├── postfix-multi-character.cy.ts
│ │ │ │ │ ├── postfix-with-point.cy.ts
│ │ │ │ │ ├── runtime-postfix-changes/
│ │ │ │ │ │ ├── runtime-postfix-changes.cy.ts
│ │ │ │ │ │ └── sandbox.component.ts
│ │ │ │ │ └── with-initial-value.cy.ts
│ │ │ │ ├── overwrite-mode/
│ │ │ │ │ └── overwrite-mode-replace.cy.ts
│ │ │ │ ├── paste/
│ │ │ │ │ └── cy-paste-utility.cy.ts
│ │ │ │ ├── phone/
│ │ │ │ │ ├── phone-national-format.cy.ts
│ │ │ │ │ └── phone-with-initial-value.cy.ts
│ │ │ │ ├── placeholder/
│ │ │ │ │ ├── placeholder-dispatch-input-events.cy.ts
│ │ │ │ │ ├── placeholder-has-same-characters-as-textfield.cy.ts
│ │ │ │ │ └── placeholder-partial-removal-on-blur.cy.ts
│ │ │ │ ├── react/
│ │ │ │ │ ├── async-predicate-options-race/
│ │ │ │ │ │ ├── reactApp.tsx
│ │ │ │ │ │ └── reactAsyncPredicateOptionsRace.cy.tsx
│ │ │ │ │ ├── async-predicates-race/
│ │ │ │ │ │ ├── reactApp.tsx
│ │ │ │ │ │ └── reactAsyncPredicatesRace.cy.tsx
│ │ │ │ │ ├── awesomeInput.tsx
│ │ │ │ │ └── change-event/
│ │ │ │ │ └── changeEvent.cy.tsx
│ │ │ │ └── utils.ts
│ │ │ ├── kit/
│ │ │ │ ├── date/
│ │ │ │ │ ├── date-basic.cy.ts
│ │ │ │ │ ├── date-fullwidth-to-halfwidth.cy.ts
│ │ │ │ │ ├── date-min-max.cy.ts
│ │ │ │ │ ├── date-mode.cy.ts
│ │ │ │ │ ├── date-segments-zero-padding.cy.ts
│ │ │ │ │ └── date-separator.cy.ts
│ │ │ │ ├── date-range/
│ │ │ │ │ ├── date-range-basic.cy.ts
│ │ │ │ │ ├── date-range-custom-range-separator.cy.ts
│ │ │ │ │ ├── date-range-fullwidth-to-halfwidth.cy.ts
│ │ │ │ │ ├── date-range-min-max-length.cy.ts
│ │ │ │ │ ├── date-range-min-max.cy.ts
│ │ │ │ │ ├── date-range-mode.cy.ts
│ │ │ │ │ ├── date-range-segments-zero-padding.cy.ts
│ │ │ │ │ └── date-range-separator.cy.ts
│ │ │ │ ├── date-time/
│ │ │ │ │ ├── date-time-basic.cy.ts
│ │ │ │ │ ├── date-time-date-time-separator.cy.ts
│ │ │ │ │ ├── date-time-fullwidth-to-halfwidth.cy.ts
│ │ │ │ │ ├── date-time-meridiem.cy.ts
│ │ │ │ │ ├── date-time-min-max.cy.ts
│ │ │ │ │ ├── date-time-mode.cy.ts
│ │ │ │ │ ├── date-time-separator.cy.ts
│ │ │ │ │ └── date-time-time-step.cy.ts
│ │ │ │ ├── number/
│ │ │ │ │ ├── number-basic.cy.ts
│ │ │ │ │ ├── number-bigint.cy.ts
│ │ │ │ │ ├── number-decimal-separator.cy.ts
│ │ │ │ │ ├── number-decimal-zero-padding.cy.ts
│ │ │ │ │ ├── number-examples.cy.ts
│ │ │ │ │ ├── number-fullwidth-to-halfwidth.cy.ts
│ │ │ │ │ ├── number-max-validation.cy.ts
│ │ │ │ │ ├── number-min-validation.cy.ts
│ │ │ │ │ ├── number-minus-before-prefix.cy.ts
│ │ │ │ │ ├── number-minus-sign.cy.ts
│ │ │ │ │ ├── number-precision.cy.ts
│ │ │ │ │ ├── number-prefix-postfix.cy.ts
│ │ │ │ │ ├── number-thousand-separator.cy.ts
│ │ │ │ │ ├── number-zero-integer-part.cy.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ └── time/
│ │ │ │ ├── time-affixes.cy.ts
│ │ │ │ ├── time-basic.cy.ts
│ │ │ │ ├── time-fullwidth-to-halfwidth.cy.ts
│ │ │ │ ├── time-meridiem.cy.ts
│ │ │ │ ├── time-mode.cy.ts
│ │ │ │ ├── time-segment-max-values.cy.ts
│ │ │ │ └── time-step.cy.ts
│ │ │ ├── react/
│ │ │ │ └── element-predicate.cy.ts
│ │ │ ├── recipes/
│ │ │ │ ├── card/
│ │ │ │ │ └── card.cy.ts
│ │ │ │ ├── content-editable/
│ │ │ │ │ ├── multi-line.cy.ts
│ │ │ │ │ └── single-line-time-mask.cy.ts
│ │ │ │ ├── network-address/
│ │ │ │ │ ├── ipv4.cy.ts
│ │ │ │ │ ├── ipv6.cy.ts
│ │ │ │ │ └── mac.cy.ts
│ │ │ │ ├── phone/
│ │ │ │ │ └── phone.cy.ts
│ │ │ │ ├── placeholder/
│ │ │ │ │ ├── date.cy.ts
│ │ │ │ │ ├── us-phone.cy.ts
│ │ │ │ │ └── сvc-code.cy.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ └── reject.cy.ts
│ │ │ │ ├── postfix/
│ │ │ │ │ ├── percentage.cy.ts
│ │ │ │ │ └── postprocessor.cy.ts
│ │ │ │ ├── prefix/
│ │ │ │ │ ├── dynamic-pattern-mask-expression.cy.ts
│ │ │ │ │ └── postprocessor.cy.ts
│ │ │ │ └── textarea/
│ │ │ │ └── textarea-latin-letters-digits.cy.ts
│ │ │ ├── ssr/
│ │ │ │ └── ssr.cy.ts
│ │ │ ├── utils.ts
│ │ │ └── vue/
│ │ │ └── vue.cy.ts
│ │ ├── tsconfig.json
│ │ └── vite.config.ts
│ ├── kit/
│ │ ├── README.md
│ │ ├── jest.config.ts
│ │ ├── package.json
│ │ ├── project.json
│ │ └── src/
│ │ ├── index.ts
│ │ └── lib/
│ │ ├── constants/
│ │ │ ├── date-segment-max-values.ts
│ │ │ ├── default-decimal-pseudo-separators.ts
│ │ │ ├── default-min-max-dates.ts
│ │ │ ├── default-pseudo-minuses.ts
│ │ │ ├── default-time-segment-bounds.ts
│ │ │ ├── index.ts
│ │ │ ├── meridiem.ts
│ │ │ ├── time-fixed-characters.ts
│ │ │ ├── time-segment-value-lengths.ts
│ │ │ └── unicode-characters.ts
│ │ ├── masks/
│ │ │ ├── date/
│ │ │ │ ├── date-mask.ts
│ │ │ │ ├── date-params.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── tests/
│ │ │ │ │ └── date-mask.spec.ts
│ │ │ │ └── utils/
│ │ │ │ ├── index.ts
│ │ │ │ ├── parse-date.ts
│ │ │ │ ├── stringify-date.ts
│ │ │ │ ├── tests/
│ │ │ │ │ ├── parse-date.spec.ts
│ │ │ │ │ └── stringify-date.spec.ts
│ │ │ │ └── to-date-segments.ts
│ │ │ ├── date-range/
│ │ │ │ ├── constants.ts
│ │ │ │ ├── date-range-mask.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── processors/
│ │ │ │ │ ├── min-max-range-length-postprocessor.ts
│ │ │ │ │ └── swap-dates-postprocessor.ts
│ │ │ │ └── tests/
│ │ │ │ ├── date-segments-zero-padding.spec.ts
│ │ │ │ └── pseudo-range-separators.spec.ts
│ │ │ ├── date-time/
│ │ │ │ ├── constants/
│ │ │ │ │ ├── date-time-separator.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── date-time-mask.ts
│ │ │ │ ├── date-time-params.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── postprocessors/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── min-max-date-time-postprocessor.ts
│ │ │ │ ├── preprocessors/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── valid-date-time-preprocessor.ts
│ │ │ │ ├── tests/
│ │ │ │ │ ├── date-segments-zero-padding.spec.ts
│ │ │ │ │ ├── date-time-separator.spec.ts
│ │ │ │ │ └── pseudo-date-end-separator.spec.ts
│ │ │ │ └── utils/
│ │ │ │ ├── index.ts
│ │ │ │ ├── is-date-time-string-complete.ts
│ │ │ │ ├── parse-date-time.ts
│ │ │ │ ├── split-date-time-string.ts
│ │ │ │ ├── stringify-date-time.ts
│ │ │ │ └── tests/
│ │ │ │ ├── parse-date-time.spec.ts
│ │ │ │ ├── split-date-time-string.spec.ts
│ │ │ │ └── stringify-date-time.spec.ts
│ │ │ ├── number/
│ │ │ │ ├── index.ts
│ │ │ │ ├── number-mask.ts
│ │ │ │ ├── number-params.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── leading-zeroes-validation.plugin.ts
│ │ │ │ │ ├── min-max.plugin.ts
│ │ │ │ │ └── not-empty-integer.plugin.ts
│ │ │ │ ├── processors/
│ │ │ │ │ ├── affixes-filter-preprocessor.ts
│ │ │ │ │ ├── decimal-zero-padding-postprocessor.ts
│ │ │ │ │ ├── empty-postprocessor.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── initialization-only-preprocessor.ts
│ │ │ │ │ ├── leading-minus-deletion-preprocessor.ts
│ │ │ │ │ ├── leading-zeroes-validation-postprocessor.ts
│ │ │ │ │ ├── min-max-postprocessor.ts
│ │ │ │ │ ├── non-removable-chars-deletion-preprocessor.ts
│ │ │ │ │ ├── not-empty-integer-part-preprocessor.ts
│ │ │ │ │ ├── number-prefix-postprocessor.ts
│ │ │ │ │ ├── pseudo-character-preprocessor.ts
│ │ │ │ │ ├── repeated-decimal-separator-preprocessor.ts
│ │ │ │ │ ├── tests/
│ │ │ │ │ │ ├── leading-zeroes-validation-postprocessor.spec.ts
│ │ │ │ │ │ └── not-empty-integer-part-preprocessor.spec.ts
│ │ │ │ │ ├── thousand-separator-postprocessor.ts
│ │ │ │ │ └── zero-precision-preprocessor.ts
│ │ │ │ ├── tests/
│ │ │ │ │ └── number-mask.spec.ts
│ │ │ │ └── utils/
│ │ │ │ ├── extract-affixes.ts
│ │ │ │ ├── generate-mask-expression.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── number-parts.ts
│ │ │ │ ├── parse-number.ts
│ │ │ │ ├── stringify-number-without-exp.ts
│ │ │ │ ├── stringify-number.ts
│ │ │ │ ├── tests/
│ │ │ │ │ ├── parse-number.spec.ts
│ │ │ │ │ ├── stringify-number-without-exp.spec.ts
│ │ │ │ │ ├── stringify-number.spec.ts
│ │ │ │ │ ├── to-number-parts.spec.ts
│ │ │ │ │ └── validate-decimal-pseudo-separators.spec.ts
│ │ │ │ ├── validate-decimal-pseudo-separators.ts
│ │ │ │ └── with-number-defaults.ts
│ │ │ └── time/
│ │ │ ├── index.ts
│ │ │ ├── time-mask.ts
│ │ │ ├── time-params.ts
│ │ │ └── utils/
│ │ │ ├── index.ts
│ │ │ ├── parse-time.ts
│ │ │ ├── stringify-time.ts
│ │ │ └── tests/
│ │ │ ├── parse-time.spec.ts
│ │ │ └── stringify-time.spec.ts
│ │ ├── plugins/
│ │ │ ├── add-on-focus.ts
│ │ │ ├── caret-guard.ts
│ │ │ ├── event-handler.ts
│ │ │ ├── index.ts
│ │ │ ├── reject-event.ts
│ │ │ ├── remove-on-blur.ts
│ │ │ ├── selection-change.ts
│ │ │ └── time/
│ │ │ ├── meridiem-stepping.ts
│ │ │ └── time-segments-stepping.ts
│ │ ├── processors/
│ │ │ ├── colon-convert-preprocessor.ts
│ │ │ ├── date-segments-zero-padding-postprocessor.ts
│ │ │ ├── first-date-end-separator-preprocessor.ts
│ │ │ ├── fullwidth-to-halfwidth-preprocessor.ts
│ │ │ ├── index.ts
│ │ │ ├── invalid-time-segment-insertion-preprocessor.ts
│ │ │ ├── meridiem-processors.ts
│ │ │ ├── min-max-date-postprocessor.ts
│ │ │ ├── normalize-date-preprocessor.ts
│ │ │ ├── postfix-postprocessor.ts
│ │ │ ├── prefix-postprocessor.ts
│ │ │ ├── tests/
│ │ │ │ ├── first-date-end-separator-preprocessor.spec.ts
│ │ │ │ ├── normalize-date-preprocessor.spec.ts
│ │ │ │ ├── postfix-postprocessor.spec.ts
│ │ │ │ ├── prefix-postprocessor.spec.ts
│ │ │ │ ├── valid-date-preprocessor.spec.ts
│ │ │ │ └── with-placeholder.spec.ts
│ │ │ ├── valid-date-preprocessor.ts
│ │ │ ├── with-placeholder.ts
│ │ │ └── zero-placeholders-preprocessor.ts
│ │ ├── types/
│ │ │ ├── date-mode.ts
│ │ │ ├── date-segments.ts
│ │ │ ├── index.ts
│ │ │ ├── time-mode.ts
│ │ │ └── time-segments.ts
│ │ └── utils/
│ │ ├── clamp.ts
│ │ ├── count-digits.ts
│ │ ├── date/
│ │ │ ├── append-date.ts
│ │ │ ├── date-segment-value-length.ts
│ │ │ ├── date-to-segments.ts
│ │ │ ├── get-date-segments-order.ts
│ │ │ ├── get-first-complete-date.ts
│ │ │ ├── is-date-string-complete.ts
│ │ │ ├── parse-date-range-string.ts
│ │ │ ├── parse-date-string.ts
│ │ │ ├── raise-segment-value-to-min.ts
│ │ │ ├── segments-to-date.ts
│ │ │ ├── tests/
│ │ │ │ ├── append-date.spec.ts
│ │ │ │ ├── get-date-segment-value-length.spec.ts
│ │ │ │ └── parse-date-range-string.spec.ts
│ │ │ ├── to-date-string.ts
│ │ │ └── validate-date-string.ts
│ │ ├── dummy.ts
│ │ ├── escape-reg-exp.ts
│ │ ├── find-common-beginning-substr.ts
│ │ ├── index.ts
│ │ ├── is-empty.ts
│ │ ├── pad-with-zeroes-until-valid.ts
│ │ ├── tests/
│ │ │ ├── clamp.spec.ts
│ │ │ ├── escape-reg-exp.spec.ts
│ │ │ ├── find-common-beginning-substr.spec.ts
│ │ │ ├── get-first-complete-date.spec.ts
│ │ │ ├── is-empty.spec.ts
│ │ │ ├── to-half-width-colon.spec.ts
│ │ │ └── to-half-width-number.spec.ts
│ │ ├── time/
│ │ │ ├── create-time-mask-expression.ts
│ │ │ ├── enrich-time-segments-with-zeroes.ts
│ │ │ ├── index.ts
│ │ │ ├── pad-end-time-segments.ts
│ │ │ ├── pad-start-time-segments.ts
│ │ │ ├── pad-time-segments.ts
│ │ │ ├── parse-time-string.ts
│ │ │ ├── tests/
│ │ │ │ ├── enrich-time-segments-with-zeroes.spec.ts
│ │ │ │ ├── parse-time-string.spec.ts
│ │ │ │ └── to-time-string.spec.ts
│ │ │ └── to-time-string.ts
│ │ ├── to-half-width-colon.ts
│ │ └── to-half-width-number.ts
│ ├── phone/
│ │ ├── README.md
│ │ ├── jest.config.ts
│ │ ├── package.json
│ │ ├── project.json
│ │ └── src/
│ │ ├── index.ts
│ │ └── lib/
│ │ └── masks/
│ │ ├── index.ts
│ │ └── phone/
│ │ ├── constants/
│ │ │ ├── index.ts
│ │ │ └── template-filler.ts
│ │ ├── index.ts
│ │ ├── phone-mask-non-strict.ts
│ │ ├── phone-mask-strict.ts
│ │ ├── phone-mask.ts
│ │ ├── processors/
│ │ │ ├── browser-autofill-preprocessor.ts
│ │ │ ├── cut-init-country-code-preprocessor.ts
│ │ │ ├── index.ts
│ │ │ ├── paste-non-strict-phone-preprocessor.ts
│ │ │ ├── paste-strict-phone-preprocessor.ts
│ │ │ ├── phone-length-postprocessor.ts
│ │ │ └── sanitize-phone-preprocessor.ts
│ │ ├── tests/
│ │ │ ├── get-phone-template.spec.ts
│ │ │ └── phone-mask.spec.ts
│ │ └── utils/
│ │ ├── cut-phone-by-valid-length.ts
│ │ ├── generate-phone-mask.ts
│ │ ├── get-country-from-number.ts
│ │ ├── get-phone-template.ts
│ │ ├── index.ts
│ │ └── select-template.ts
│ ├── react/
│ │ ├── .babelrc
│ │ ├── README.md
│ │ ├── jest.config.ts
│ │ ├── package.json
│ │ ├── project.json
│ │ └── src/
│ │ ├── index.ts
│ │ └── lib/
│ │ ├── adaptControlledElement.tsx
│ │ ├── tests/
│ │ │ ├── controlledInput.spec.tsx
│ │ │ ├── elementPredicate.spec.tsx
│ │ │ └── useMaskito.spec.tsx
│ │ ├── useIsomorphicLayoutEffect.tsx
│ │ └── useMaskito.tsx
│ └── vue/
│ ├── README.md
│ ├── jest.config.ts
│ ├── package.json
│ ├── project.json
│ └── src/
│ ├── index.ts
│ └── lib/
│ ├── maskito.spec.ts
│ └── maskito.ts
├── tsconfig.build.json
├── tsconfig.json
└── tsconfig.spec.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .cspell.json
================================================
{
"$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/master/cspell.schema.json",
"import": ["@taiga-ui/cspell-config"],
"files": ["*/*.*"],
"ignorePaths": [
".git",
".gitignore",
".npmrc",
".cspell.json",
"**/dist/**",
"**/assets/**",
"**/node_modules/**",
"**/demo/server.ts",
"**/demo-integrations/src/tests/**",
"*.{log,svg,snap,png,ogv,yml}",
"**/package.json",
"**/tsconfig*.json"
],
"ignoreWords": ["Acpekt", "WHATWG", "prebundle"]
}
================================================
FILE: .editorconfig
================================================
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
================================================
FILE: .firebaserc
================================================
{
"projects": {
"default": "maskito"
}
}
================================================
FILE: .github/CODEOWNERS
================================================
* @taiga-family/core-team
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making
participation in our project and our community a harassment-free experience for everyone, regardless of age, body size,
disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education,
socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take
appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any
contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the
project or its community. Examples of representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed representative at an online or offline
event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project at
opensource@acpekt.ru. All complaints will be reviewed and investigated and will result in a response that is deemed
necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to
the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent
repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing
> Thank you for considering contributing to our project. Your help if very welcome!
When contributing, it's better to first discuss the change you wish to make via issue, email, or any other method with
the owners of this repository before making a change.
All members of our community are expected to follow our [Code of Conduct](.github/CODE_OF_CONDUCT.md). Please make sure
you are welcoming and friendly in all of our spaces.
## Getting started
In order to make your contribution please make a fork of the repository. After you've pulled the code, follow these
steps to kick-start the development:
1. Run `npm ci` to install dependencies
2. Run `npm start` to launch demo project where you could test your changes
3. Use following commands to ensure code quality
```bash
npm run lint
npm run build
npm run test
npm run cy:run
```
## Pull Request Process
1. We follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.4/) in our commit messages, i.e.
`feat(core): improve typing`
2. Update [demo](projects/demo) application to reflect changes related to public API and everything relevant
3. Make sure you cover all code changes with unit tests and/or [Cypress](https://www.cypress.io) tests
4. When you are ready, create Pull Request of your fork into original repository
================================================
FILE: .github/ISSUE_TEMPLATE/1-bug-report.yml
================================================
name: '🐞 - Bug Report'
title: '🐞 - '
description: Report a bug in the Maskito
labels: ['bug']
type: Bug
body:
- type: dropdown
id: affected-packages
attributes:
label: Which package(s) are the source of the bug?
options:
- '@maskito/core'
- '@maskito/kit'
- '@maskito/phone'
- '@maskito/angular'
- '@maskito/react'
- '@maskito/vue'
- Don't known / other
multiple: true
validations:
required: true
- type: input
id: playground-link
attributes:
label: Playground Link
description: |
Link to an isolated reproduction in our [StackBlitz playground](https://maskito.dev/stackblitz).
If either of the following holds true:
- You can't reproduce the issue in the playground
- Your issue requires some complex setup - such as multiple files or a specific folder structure.
So you can use any link that might help for reproduction bug: github repo, demo url, etc.
***Help us to help you!***
placeholder: https://stackblitz.com/edit/...
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
placeholder: |
Please provide the exception or error you saw.
How do you trigger this bug?
Please walk us through it step by step.
Please provide a screenshot if possible.
validations:
required: true
- type: input
id: maskito-version
attributes:
label: Maskito version
placeholder: x.y.z
validations:
required: true
- type: checkboxes
id: browser-specific
attributes:
label: Which browsers have you used?
description: You may select more than one.
options:
- label: Chrome
- label: Firefox
- label: Safari
- label: Edge
- type: checkboxes
id: operating-systems
attributes:
label: Which operating systems have you used?
description: You may select more than one.
options:
- label: macOS
- label: Windows
- label: Linux
- label: iOS
- label: Android
================================================
FILE: .github/ISSUE_TEMPLATE/2-feature-request.yml
================================================
name: '🚀 - Feature Request'
title: '🚀 - '
description: Suggest a feature for Maskito
labels: ['feature']
type: Feature
body:
- type: dropdown
id: affected-packages
attributes:
label: Which package(s) are relevant/related to the feature request?
options:
- '@maskito/core'
- '@maskito/kit'
- '@maskito/phone'
- '@maskito/angular'
- '@maskito/react'
- '@maskito/vue'
- Don't known / other
multiple: true
- type: textarea
id: description
attributes:
label: Description
placeholder: |
Proposed solution.
Alternatives considered.
validations:
required: true
================================================
FILE: .github/ISSUE_TEMPLATE/3-documentation.yml
================================================
name: '📚 - Documentation'
title: '📚 - '
description: Report an issue in Maskito's documentation
labels: ['documentation']
type: Documentation
body:
- type: input
id: affected-url
attributes:
label: What is the affected URL?
- type: textarea
id: description
attributes:
label: Description
placeholder: |
How do you trigger this bug?
Please walk us through it step by step.
Please provide a screenshot if possible.
validations:
required: true
- type: checkboxes
id: browser-specific
attributes:
label: Which browsers have you used?
description: You may select more than one.
options:
- label: Chrome
- label: Firefox
- label: Safari
- label: Edge
- type: checkboxes
id: operating-systems
attributes:
label: Which operating systems have you used?
description: You may select more than one.
options:
- label: macOS
- label: Windows
- label: Linux
- label: iOS
- label: Android
================================================
FILE: .github/renovate.json
================================================
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>taiga-family/renovate-config"],
"packageRules": [
{
"enabled": false,
"matchPackageNames": [
"/^@nx.*/",
"/^nx$/",
"cypress"
]
},
{
"enabled": false,
"matchPackageNames": ["jest-preset-angular"]
}
]
}
================================================
FILE: .github/workflows/assign-author.yml
================================================
name: 🤖 PR author as an assignee
on:
pull_request:
types: [opened]
jobs:
assign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: toshimaru/auto-author-assign@v3.0.1
continue-on-error: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/auto-merge.yml
================================================
name: 🤖 PR auto merge
on:
pull_request:
env:
PR_JOBS_NAME: '[ "Packages", "Demo", "Firebase", "Lint result", "tests", "E2E result" ]'
jobs:
setup:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.matrix.outputs.value }}
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- id: matrix
run: echo "value=$PR_JOBS_NAME" >> $GITHUB_OUTPUT
wait:
needs: [setup]
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
value: ${{ fromJSON(needs.setup.outputs.matrix) }}
steps:
- uses: taiga-family/ci/actions/run/wait-job@v1.201.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
job: ${{ matrix.value }}
approve:
needs: [wait]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/auto/approve/double@v1.201.0
if: env.IS_TAIGA_FAMILY_BOT_PR_AUTHOR == 'true'
with:
token1: ${{ secrets.GITHUB_TOKEN }}
token2: ${{ secrets.TAIGA_FAMILY_APPROVE_BOT_PAT }}
- uses: taiga-family/ci/actions/run/merge@v1.201.0
if: env.IS_TAIGA_FAMILY_BOT_PR_AUTHOR == 'true'
with:
token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on:
pull_request:
push:
branches: [main]
jobs:
build-packages:
name: Packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npx nx run-many --target build --all --exclude=demo
build-demo:
name: Demo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npx nx build-gh-pages
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/deploy-preview.yml
================================================
name: Deploy / preview
on: pull_request
jobs:
build_and_preview:
name: Firebase
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npx nx run-many --target build --all --exclude=demo
- run: npx nx run demo:build:typecheck
- name: Debug output
run: tree dist/demo/browser -P '*.html'
- name: Deploy preview
uses: FirebaseExtended/action-hosting-deploy@v0.10.0
if: env.IS_OWNER_MODE == 'true'
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_MASKITO }}
projectId: maskito
expires: 1d
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/deploy.yml
================================================
name: Deploy
on:
workflow_dispatch:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' || contains(github.event.head_commit.message, 'chore(release)') }}
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npx nx build-gh-pages
- uses: JamesIves/github-pages-deploy-action@v4.8.0
with:
branch: gh-pages
folder: dist/demo/browser
silent: false
clean: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/e2e.yml
================================================
name: E2E
on: [pull_request]
env:
CACHE_DIST_KEY: dist-${{ github.ref }}-${{ github.sha }}
CYPRESS_CACHE_FOLDER: ./node_modules/cache-cypress
UNIVERSAL_SERVER: http://localhost:4000
STATIC_SERVER: http://localhost:8080
jobs:
build-demo:
name: Build demo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
with:
fetch-depth: 10
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npx tsc --project projects/demo-integrations/tsconfig.json
- name: Mark demo-app directory for persist in cache
uses: actions/cache@v5
with:
path: dist/demo
key: ${{ env.CACHE_DIST_KEY }}
- name: Build demo
# --optimization false to keep `window.ng` inside Cypress tests
run: npm run build -- --optimization false
e2e-kit:
needs: [build-demo]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
project: [date, date-range, date-time, number, time]
name: Kit / ${{ matrix.project }}
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- uses: taiga-family/ci/actions/setup/cypress@v1.201.0
- name: Download demo build from cache
uses: actions/cache@v5
with:
path: dist/demo
key: ${{ env.CACHE_DIST_KEY }}
- name: Serving SSR server
run: |
npm run serve:ssr -- --ci & sleep 5
curl -X GET -I -f "${{ env.UNIVERSAL_SERVER }}"
- name: Run Cypress tests
run:
npx nx e2e demo-integrations --spec="**/kit/${{ matrix.project }}/**/*.cy.ts" --baseUrl=${{
env.UNIVERSAL_SERVER}}
e2e-recipes:
needs: [build-demo]
runs-on: ubuntu-latest
name: Recipes
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- uses: taiga-family/ci/actions/setup/cypress@v1.201.0
- name: Download demo build from cache
uses: actions/cache@v5
with:
path: dist/demo
key: ${{ env.CACHE_DIST_KEY }}
- name: Serving SSR server
run: |
npm run serve:ssr -- --ci & sleep 5
curl -X GET -I -f "${{ env.UNIVERSAL_SERVER }}"
- name: Run Cypress tests
run: npx nx e2e demo-integrations --spec="**/recipes/**/*.cy.ts" --baseUrl=${{ env.UNIVERSAL_SERVER}}
e2e-others:
needs: [build-demo]
runs-on: ubuntu-latest
name: Others
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- uses: taiga-family/ci/actions/setup/cypress@v1.201.0
- name: Download demo build from cache
uses: actions/cache@v5
with:
path: dist/demo
key: ${{ env.CACHE_DIST_KEY }}
- name: Serving SSR server
run: |
npm run serve:ssr -- --ci & sleep 5
curl -X GET -I -f "${{ env.UNIVERSAL_SERVER }}"
- name: Run Cypress tests
# Replace with npm run cy:run -- --spec "**/!(kit|recipes)/*.cy.ts" --config baseUrl="${{ env.UNIVERSAL_SERVER }}"
# After this issue fix: https://github.com/cypress-io/cypress/issues/22407
run:
npx nx e2e demo-integrations --spec="**/(angular|react|ssr|addons|others)/**/*.cy.ts" --baseUrl=${{
env.UNIVERSAL_SERVER}}
component-testing:
runs-on: ubuntu-latest
name: Component Testing
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- uses: taiga-family/ci/actions/setup/cypress@v1.201.0
- name: Run Cypress tests
run:
npx nx component-test demo-integrations --browser=chrome && npx nx ct-react demo-integrations --browser=chrome
result:
needs: [build-demo, e2e-kit, e2e-recipes, e2e-others, component-testing]
runs-on: ubuntu-latest
name: E2E result
steps:
- run: echo "Success"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/lint.yml
================================================
name: Lint
on: [pull_request]
jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npm run typecheck
cspell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npm run cspell -- --no-progress
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npm run prettier ${{ env.SUPPORT_AUTO_PUSH == 'true' && '-- --write' || '-- --check' }}
- uses: taiga-family/ci/actions/auto/push@v1.201.0
with:
token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }}
stylelint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npm run stylelint ${{ env.SUPPORT_AUTO_PUSH == 'true' && '-- --fix' || '' }}
- uses: taiga-family/ci/actions/auto/push@v1.201.0
with:
token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }}
eslint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
with:
persist-credentials: false
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- run: npm run lint ${{ env.SUPPORT_AUTO_PUSH == 'true' && '-- --fix' || '' }}
- uses: taiga-family/ci/actions/auto/push@v1.201.0
with:
token: ${{ secrets.TAIGA_FAMILY_BOT_PAT }}
result:
needs: [typecheck, cspell, prettier, stylelint, eslint]
runs-on: ubuntu-latest
name: Lint result
steps:
- run: echo "Success"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/release.yml
================================================
name: ⚠️ Release
on:
workflow_dispatch:
inputs:
mode:
type: choice
description: Bump version as requested
required: true
options:
- patch
- minor
- alpha
- major
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- uses: taiga-family/ci/actions/run/release-it@v1.201.0
id: release-it
with:
ref: ${{ github.ref }}
mode: ${{ github.event.inputs.mode }}
npmToken: ${{ secrets.NPM_TOKEN }}
githubToken: ${{ secrets.TAIGA_FAMILY_BOT_PAT }}
- uses: taiga-family/ci/actions/run/read-package-json@v1.201.0
id: info
- name: Announce to Telegram
if: steps.release-it.outputs.released == 'true'
uses: taiga-family/ci/actions/messenger/telegram/announce@v1.201.0
with:
chatId: ${{ secrets.TAIGA_TELEGRAM_CHAT_ID }}
topicId: ${{ secrets.TAIGA_TELEGRAM_CHAT_THREAD_ID }}
token: ${{ secrets.TAIGA_TELEGRAM_BOT_TOKEN }}
version: v${{ steps.info.outputs.version }}
textLink: '@maskito/core'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .github/workflows/test.yml
================================================
name: Tests
on:
pull_request:
push:
branches:
- main
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: taiga-family/ci/actions/setup/variables@v1.201.0
- uses: taiga-family/ci/actions/setup/node@v1.201.0
- name: Run tests
run: npx nx run-many --target test --all --coverage
- name: Archive coverage artifacts
uses: actions/upload-artifact@v7.0.1
with:
name: coverage-${{ github.workflow }}-${{ github.run_id }}
path: coverage
codecov:
name: Collect coverage
needs: [tests]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/download-artifact@v8.0.1
with:
name: coverage-${{ github.workflow }}-${{ github.run_id }}
path: coverage
- name: Display structure of coverage files
run: tree -L 2 ./coverage -P 'lcov.info'
- uses: codecov/codecov-action@v6.0.0
with:
directory: ./coverage/core/
flags: summary,core
name: core
- uses: codecov/codecov-action@v6.0.0
with:
directory: ./coverage/kit/
flags: summary,kit
name: kit
- uses: codecov/codecov-action@v6.0.0
with:
directory: ./coverage/phone/
flags: summary,phone
name: phone
- uses: codecov/codecov-action@v6.0.0
with:
directory: ./coverage/angular/
flags: summary,angular
name: angular
- uses: codecov/codecov-action@v6.0.0
with:
directory: ./coverage/react/
flags: summary,react
name: react
- uses: codecov/codecov-action@v6.0.0
with:
directory: ./coverage/vue/
flags: summary,vue
name: vue
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
================================================
FILE: .gitignore
================================================
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
**/node_modules/
# profiling files
chrome-profiler-events.json
speed-measure-plugin.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
*.iml
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
# cypress
**/cypress/**/screenshots/**
projects/demo-integrations/cypress
.nx
.ssl
RELEASE_BODY.md
.cursor/rules/nx-rules.mdc
.github/instructions/nx.instructions.md
.rollup.cache
================================================
FILE: .husky/commit-msg
================================================
npx --no -- commitlint --edit $1
================================================
FILE: .husky/pre-commit
================================================
npx lint-staged
npm run typecheck
================================================
FILE: .npmrc
================================================
engine-strict=true
loglevel=error
================================================
FILE: .release-it.js
================================================
module.exports = require('@taiga-ui/release-it-config');
================================================
FILE: .ws-context
================================================
{
"framework": "angular",
"projects/vue/**": {
"framework": "vue"
},
"projects/react/**": {
"framework": "react"
}
}
================================================
FILE: CHANGELOG.md
================================================
### [5.2.2](https://github.com/taiga-family/maskito/compare/v5.2.1...v5.2.2) (2026-03-31)
### 🐞 Bug Fixes
- **kit**: `Number` with `negativePattern=minusFirst` + `prefix` has unexpected caret shift on minus insertion (#2616)
[(1d7bc77)](https://github.com/taiga-family/maskito/commit/1d7bc7761f1e4c7dad3b01b6c651295dd6d31bc4)
- **kit**: `Number` should ignore digits in affixes for `min`/`max` validation (#2615)
[(227a860)](https://github.com/taiga-family/maskito/commit/227a860453b4d0cee42a96e8ef06d155a44cce06)
### [5.2.1](https://github.com/taiga-family/maskito/compare/v5.2.0...v5.2.1) (2026-03-27)
### 🐞 Bug Fixes
- **react**: omitted `d.ts` files (#2607)
[(a10e118)](https://github.com/taiga-family/maskito/commit/a10e1187c81cfd4af8935edd7d459c3e6b5c6cc4)
- **kit**: `maskitoParseNumber` incorrectly parses postfix containing digits (#2600)
[(4805166)](https://github.com/taiga-family/maskito/commit/48051666d3235fe72c5bc90d83405175905ec7fa)
### [5.2.0](https://github.com/taiga-family/maskito/compare/v5.1.2...v5.2.0) (2026-03-25)
### 🚀 Features
- **kit**: `Number` supports `thousandSeparatorPattern` (#2584)
[(f4e1340)](https://github.com/taiga-family/maskito/commit/f4e1340ddedd8abf04c181c8db31edf420564845)
### 🐞 Bug Fixes
- **kit**: validate digit count in time segment for `maskitoParseDateTime` (#2581)
[(9c3e9bc)](https://github.com/taiga-family/maskito/commit/9c3e9bccc046be9e9a91ea05255bf55985144df1)
### [5.1.2](https://github.com/taiga-family/maskito/compare/v5.1.1...v5.1.2) (2026-03-13)
### 🐞 Bug Fixes
- **kit**: `maskitoParseDate` & `maskitoParseDateTime` supports parsing of dates in formats `mm/dd`, `dd/mm` (#2577)
[(a0f073b)](https://github.com/taiga-family/maskito/commit/a0f073b26b3be0d6bf776d970adc65c745cb3d41)
- **kit**: `maskitoParseDate` should return `null` for invalid `Date` string (#2561)
[(cf2b5f2)](https://github.com/taiga-family/maskito/commit/cf2b5f206a6679d2171bfd25fdc969ffee6dad7f)
### [5.1.1](https://github.com/taiga-family/maskito/compare/v5.1.0...v5.1.1) (2026-02-16)
### 🐞 Bug Fixes
- **kit**: `maskitoStringifyDate` incorrectly formats year with leading zeroes (#2538)
[(9817f08)](https://github.com/taiga-family/maskito/commit/9817f084dd34628afd1bebe8070189edf8f3fd1f)
- **kit**: `Number` deletes the previous non-selected character on the first deletion (#2537)
[(40ef2e0)](https://github.com/taiga-family/maskito/commit/40ef2e03b8ecaf564a1d4f055b8d629ba8932370)
- **phone**: `Phone` preserves previously entered digits on new digits paste (#2481)
[(f836f4f)](https://github.com/taiga-family/maskito/commit/f836f4f5ec94d865a2bcb44960161cfe25fe3a64)
## [5.1.0](https://github.com/taiga-family/maskito/compare/v5.0.1...v5.1.0) (2026-01-22)
### 🚀 Features
- **phone:** `Phone` supports national format ([#2461](https://github.com/taiga-family/maskito/issues/2461))
([c90bca2](https://github.com/taiga-family/maskito/commit/c90bca2c2f0f3bc3746a2559fc84bd688075c1be))
### 🐞Bug Fixes
- **kit:** `Number` fails to dynamically change postfix ([#2501](https://github.com/taiga-family/maskito/issues/2501))
([cd73d6a](https://github.com/taiga-family/maskito/commit/cd73d6a729068e4b301509b12def6e149a7b5d66))
- **kit:** `Number` throws `Failed to parse String to BigInt` error
([#2509](https://github.com/taiga-family/maskito/issues/2509))
([7b80f79](https://github.com/taiga-family/maskito/commit/7b80f79140740462d3d924ba49993e1376d2b6e3))
- **react:** `useMaskito` should destroy Maskito instance if element is detached from the DOM
([#2507](https://github.com/taiga-family/maskito/issues/2507))
([1cdb203](https://github.com/taiga-family/maskito/commit/1cdb20359aaf4fa479420638d76bc7b238a6cb4c))
### [5.0.1](https://github.com/taiga-family/maskito/compare/v5.0.0...v5.0.1) (2025-12-26)
### 🐞 Bug Fixes
- **phone**: `Phone` removes last digit if pasted without '+' (#2480)
[(5d709ca)](https://github.com/taiga-family/maskito/commit/5d709ca9c2e4a8abbe99a38c47551a9e6b2d8d36)
- **kit**: `maskitoStringifyNumber` supports extremal exponent values (#2463)
[(1340257)](https://github.com/taiga-family/maskito/commit/1340257486a86499f94c96dbe67949ada32ebae4)
- **phone**: `Phone` with initial value has problems with the first time delete action (#2455)
[(fa596fa)](https://github.com/taiga-family/maskito/commit/fa596fa101333b519bc3d760d6f4969151178e1a)
## [5.0.0](https://github.com/taiga-family/maskito/compare/v4.0.1...v5.0.0) (2025-12-03)
### ⚠ BREAKING CHANGES
- Bump Safari browser support (#2439)
| | < 5.0.0 | ≥ 5.0.0 |
| -------------- | ------- | ------- |
| Safari Desktop | 13.1+ | 14.1+ |
| Safari Mobile | 13.4+ | 14.5+ |
- **kit**: `Number` supports `BigInt` (#2431)
[(2d2f86d)](https://github.com/taiga-family/maskito/commit/2d2f86dafb1524528305908af27b4df37d9e1330)
New default values for `maskitoNumberOptionsGenerator` / `maskitoStringifyNumber`:
| MaskitoNumberParams | < 5.0.0 | ≥ 5.0.0 |
| ------------------- | ------------------------- | ----------- |
| `min` | `Number.MIN_SAFE_INTEGER` | `-Infinity` |
| `max` | `Number.MAX_SAFE_INTEGER` | `Infinity` |
### [4.0.1](https://github.com/taiga-family/maskito/compare/v4.0.0...v4.0.1) (2025-11-14)
### 🐞 Bug Fixes
- **kit**: `Time` with `[step]` ignores `timeSegmentMinValues` on arrow stepping (#2420)
[(398a5c1)](https://github.com/taiga-family/maskito/commit/398a5c163d03502d413ca15c8756f41891b75197)
- **kit**: `DateRange` with `[minLength]` & `[maxLength]` incorrectly appends month in backward direction (#2369)
[(3c80959)](https://github.com/taiga-family/maskito/commit/3c80959773a4c44b29e70a420bc1fc6e074030b9)
## [4.0.0](https://github.com/taiga-family/maskito/compare/v3.11.1...v4.0.0) (2025-10-13)
### ⚠ BREAKING CHANGES
- **kit**: delete deprecated `precision` & `decimalZeroPadding` parameters from `Number` mask (#2354)
**Previous behavior:**
```ts
import {maskitoNumberOptionsGenerator} from '@maskito/kit';
const options = maskitoNumberOptionsGenerator({
precision: 2, // ---> Use `maximumFractionDigits` instead
decimalZeroPadding: true, // ---> Use `minimumFractionDigits` instead
});
```
<p align="center">⬇️ </p>
**New behavior**:
```ts
import {maskitoNumberOptionsGenerator} from '@maskito/kit';
const options = maskitoNumberOptionsGenerator({
maximumFractionDigits: 2,
minimumFractionDigits: 2,
});
```
- **kit**: `maskitoParseNumber` accepts only `MaskitoNumberParams` as the 2nd argument (#2355)
**Previous behavior:**
```ts
import {maskitoParseNumber} from '@maskito/kit';
maskitoParseNumber(
'0,42',
',', // decimalSeparator
);
```
<p align="center">⬇️ </p>
**New behavior**:
```ts
import {maskitoParseNumber} from '@maskito/kit';
maskitoParseNumber(
'0,42',
{decimalSeparator: ','}, // MaskitoNumberParams
);
```
- **kit**: remove invalid `MM.SS.MSS` type from `MaskitoTimeMode` (use `MM:SS.MSS` instead) (#2365)
- **angular**: bump minimum required Angular version (16+ => 19+) (#2347) (#2348) (#2349)
- **angular**: `MaskitoDirective` uses model inputs (#2363)
### [3.11.1](https://github.com/taiga-family/maskito/compare/v3.11.0...v3.11.1) (2025-09-30)
### 🐞 Bug Fixes
- **kit**: resolve circular dependencies inside `Number` mask (#2344)
[(efb3039)](https://github.com/taiga-family/maskito/commit/efb303980905c33bfe58e0163b74c72da5f83fcd)
- **kit**: `Number` fails to clear initial value (by selecting all + Backspace/Delete) (#2343)
[(63f6e72)](https://github.com/taiga-family/maskito/commit/63f6e725af215dc492ddca02d30123de0dd026de)
- **kit**: `Number` has broken support for postfix with leading point (#2337)
[(e9a3598)](https://github.com/taiga-family/maskito/commit/e9a3598c9ce7f5c39f932d4e6b3c0ffabcde3741)
### [3.11.0](https://github.com/taiga-family/maskito/compare/v3.10.3...v3.11.0) (2025-09-23)
### 🚀 Features
- **kit**: `Number` supports minus before prefix (#2281)
[(480c1fd)](https://github.com/taiga-family/maskito/commit/480c1fde7693b62df768364c0df00fc7328cb4e6)
- **kit**: `Number` uses `toNumberParts` / `fromNumberParts` approach (#2270)
[(891780a)](https://github.com/taiga-family/maskito/commit/891780a8f179345a49dbe8b8036e639ae0a98cbd)
### 🐞 Bug Fixes
- **kit**: `PostfixPostprocessor` duplicates postfix on paste of value with incompleted postfix (#2267)
[(2707771)](https://github.com/taiga-family/maskito/commit/27077719ffc8628758664638e802e1ad3c9f8e27)
- **kit**: `maskitoStringifyTime` and `maskitoParseTime` should support `AM` / `PM` formats (#2260)
[(a0aea6f)](https://github.com/taiga-family/maskito/commit/a0aea6f741fea3139f4e7d7c8f84ce46c1738c26)
- **angular**: use `@Input` setters instead of `ngOnChanges` to handle programmatic changes (#2257)
[(cb8c129)](https://github.com/taiga-family/maskito/commit/cb8c129f1afd196a38f87dd4b36328ddea3b60a5)
### [3.10.3](https://github.com/taiga-family/maskito/compare/v3.10.2...v3.10.3) (2025-08-06)
### 🐞 Bug Fixes
- **kit**: `DateRange` + `minLength` / `maxLength` has incorrect limits (#2210)
[(e8917e0)](https://github.com/taiga-family/maskito/commit/e8917e0a124b26ffc9806f74c5c70016084f5280)
- **kit**: `maskitoStringifyNumber` fails to stringify number with exponential notation (#2224)
[(9fe0b08)](https://github.com/taiga-family/maskito/commit/9fe0b080b2703a72674a25b8ce352486cc274663)
### [3.10.2](https://github.com/taiga-family/maskito/compare/v3.10.1...v3.10.2) (2025-07-28)
### 🐞 Bug Fixes
- **kit**: `Number` with `input[maxlength]` is incompatible with `document.execCommand('delete')` (#2217)
[(2604d2c)](https://github.com/taiga-family/maskito/commit/2604d2ce8dc60e16f464a3fc4328f907bef58d55)
### [3.10.1](https://github.com/taiga-family/maskito/compare/v3.10.0...v3.10.1) (2025-07-18)
### 🐞 Bug Fixes
- **core**: dynamic mask switching to mask without fixed character fails on new character insertion (#2207)
[(50e68d4)](https://github.com/taiga-family/maskito/commit/50e68d4bb8f6e5330bda76c67806514a7fa53294)
### [3.10.0](https://github.com/taiga-family/maskito/compare/v3.9.1...v3.10.0) (2025-07-04)
### 🚀 Features
- **kit**: `Time` supports `prefix` & `postfix` parameters (#2185)
[(2cc7462)](https://github.com/taiga-family/maskito/commit/2cc7462583a2fe372d0cad312fb5f0d90ca0fe8e)
### 🐞 Bug Fixes
- **core**: invalid behavior of dynamic mask expression with trailing fixed characters (#2184)
[(cecf9d6)](https://github.com/taiga-family/maskito/commit/cecf9d69468e56de8ff4f39af7ebc07d5a686fe8)
- **core**: do not insert fixed character on attempt to enter invalid character at its position (#2181)
[(7a51702)](https://github.com/taiga-family/maskito/commit/7a51702361237a41cd9bbdcdbb8e46d0bfa2e4bc)
- **kit**: date-related mask with month-first mode has incorrect zero-padding logic (#2166)
[(26294e8)](https://github.com/taiga-family/maskito/commit/26294e8250591c727f99ccec563e8492df7c1068)
### [3.9.1](https://github.com/taiga-family/maskito/compare/v3.9.0...v3.9.1) (2025-06-23)
### 🐞 Bug Fixes
- **kit**: `Number` with custom `minusSign` has broken `min`/`max` behavior (#2164)
[(52ed25d)](https://github.com/taiga-family/maskito/commit/52ed25debaa2838a0b360983a508a3d627c78277)
- **core**: Android with Microsoft SwiftKey Keyboard ignores `preventDefault()` for `beforeinput` event on backspace
(#2163) [(722d9af)](https://github.com/taiga-family/maskito/commit/722d9afc265df8392613c770759df3bb8955e08e)
### [3.9.0](https://github.com/taiga-family/maskito/compare/v3.8.0...v3.9.0) (2025-06-05)
### 🚀 Features
- **react**: add support for React-specific `onChange` event handler (#2153)
[(e941847)](https://github.com/taiga-family/maskito/commit/e941847990662835343c4e25d3f2b2e64ab54345)
### 🐞 Bug Fixes
- **core**: do not unnecessarily trigger element's `value` setter on every keystroke (#2152)
[(fd3449b)](https://github.com/taiga-family/maskito/commit/fd3449b69f88dbcab5b06b03ff19273b511bcd64)
### [3.8.0](https://github.com/taiga-family/maskito/compare/v3.7.2...v3.8.0) (2025-05-13)
### 🚀 Features
- **angular**: new `MaskitoPattern` directive (#2081)
[(c3f7142)](https://github.com/taiga-family/maskito/commit/c3f7142245b603af9136541de9d181189e01a7a3)
### 🐞 Bug Fixes
- **kit**: update the first digit zero-padding logic for date-related mask (#2117)
[(b5b2598)](https://github.com/taiga-family/maskito/commit/b5b2598f455f3ad3438c3bd89b81009aca82f17c)
- **core**: incorrect handle of paste event for `<input />` with `maxlength` attribute (#2090)
[(e20e50b)](https://github.com/taiga-family/maskito/commit/e20e50bb92aca9d70bc483f9fc66904264a64c35)
- **kit**: `Number` should support non-erasable minus (as `prefix`) for `max <= 0` (#2087)
[(3910914)](https://github.com/taiga-family/maskito/commit/39109144075d58734d1545be888cbd03c5b6286e)
### [3.7.2](https://github.com/taiga-family/maskito/compare/v3.7.1...v3.7.2) (2025-04-22)
### 🐞 Bug Fixes
- **kit**: missing export of `maskitoParseDateTime` & `maskitoStringifyDateTime` utilities (#2074)
[(6aa34aa)](https://github.com/taiga-family/maskito/commit/6aa34aa610cf140248bc7a691beb5aaba1f0e0cd)
### [3.7.1](https://github.com/taiga-family/maskito/compare/v3.7.0...v3.7.1) (2025-04-16)
### 🐞 Bug Fixes
- **core**: updated selection range (even if textfield value is untouched) should not be ignored (#2069)
[(9276117)](https://github.com/taiga-family/maskito/commit/927611775e8d23eb89663150cd84e7981b12d2e7)
### [3.7.0](https://github.com/taiga-family/maskito/compare/v3.6.0...v3.7.0) (2025-04-15)
### 🚀 Features
- **kit**: new `maskitoParseDateTime` and `maskitoStringifyDateTime` helpers (#2055)
[(5028084)](https://github.com/taiga-family/maskito/commit/5028084f9be876cf8b1dc2607956cd4906285c43)
### 🐞 Bug Fixes
- **core**: add possibility to overwrites `selection` property in processors (#2053)
[(de354f4)](https://github.com/taiga-family/maskito/commit/de354f4fbeed7a632e23c0e1d00809effbb0229b)
### [3.6.0](https://github.com/taiga-family/maskito/compare/v3.5.0...v3.6.0) (2025-04-08)
### 🚀 Features
- **kit**: `Number` supports new properties `minimumFractionDigits` & `maximumFractionDigits` (#2022)
[(8719b9e)](https://github.com/taiga-family/maskito/commit/8719b9e30d6463deff4aed213cba774189ddd305)
### 🐞 Bug Fixes
- **core**: double space bar removes characters (#2040)
[(ccbebd8)](https://github.com/taiga-family/maskito/commit/ccbebd878ae7ba92da0a8d25d5b9d0b5c3ed3bcf)
### [3.5.0](https://github.com/taiga-family/maskito/compare/v3.4.0...v3.5.0) (2025-03-21)
### 🚀 Features
- **kit**: `Time` supports `MM:SS` mode (#2008)
[(b93ad1e)](https://github.com/taiga-family/maskito/commit/b93ad1ecc71f608dd68de01b43487153b8e89d95)
### 🐞 Bug Fixes
- **kit**: `maskitoParseDate` should return `null` for incompleted date string (#2009)
[(9eec35b)](https://github.com/taiga-family/maskito/commit/9eec35b878411a79fec84986cbea94fbdc9f24d8)
### [3.4.0](https://github.com/taiga-family/maskito/compare/v3.3.0...v3.4.0) (2025-03-10)
### 🚀 Features
- **kit**: new `maskitoStringifyNumber` helper (#1987)
[(cbfd4bc)](https://github.com/taiga-family/maskito/commit/cbfd4bc4bb6ca56bf12667bb3626c55ae1b04c48)
### 🐞 Bug Fixes
- **phone**: `Phone` should accept incomplete phone number of selected country (even with `strict=true`) (#1982)
[(965d735)](https://github.com/taiga-family/maskito/commit/965d7358ad39888d3844c121dd6934ee66cdc541)
### [3.3.0](https://github.com/taiga-family/maskito/compare/v3.2.1...v3.3.0) (2025-02-28)
### 🚀 Features
- **kit**: new `maskitoParseDate` and `maskitoStringifyDate` helpers (#1973)
[(208a4ab)](https://github.com/taiga-family/maskito/commit/208a4abc8018b368d3154ebc26a81504b6abec3d)
- **kit**: `Date` supports `dd/mm` and `mm/dd` modes (#1939)
[(bc290af)](https://github.com/taiga-family/maskito/commit/bc290affdcdc1cd6e088a32a60dc5e74fd00a1d8)
### 🐞 Bug Fixes
- **kit**: `SelectionChangeHandler` does not work for Safari after programmatic update of textfield value (#1930)
[(34c11d0)](https://github.com/taiga-family/maskito/commit/34c11d0ee88b861ab21d54113aff21f3091a053f)
### [3.2.1](https://github.com/taiga-family/maskito/compare/v3.2.0...v3.2.1) (2024-12-26)
### 🚀 Features
- **kit**: remove circular import (#1861)
[(15ff0b8)](https://github.com/taiga-family/maskito/commit/15ff0b8558bc954ac6eda07bdb13d087fc2f3491)
### 🐞 Bug Fixes
- **kit**: `Number` should ignore `[decimalSeparator]` value if `[precision]=0` (#1908)
[(19effe2)](https://github.com/taiga-family/maskito/commit/19effe2c7218646335b2f08c53a1ed3c3f0d89a1)
- **kit**: `Number` + postfix (with leading space) adds unnecessary spaces on paste value with trailing spaces (#1865)
[(c37b1d6)](https://github.com/taiga-family/maskito/commit/c37b1d636fefee1cba17b4aa07ccdd30edc5ff66)
- **kit**: `DateRange` should accept single character date segment paste even if date and range separators are equal
(#1796) [(be6a4c3)](https://github.com/taiga-family/maskito/commit/be6a4c3c57132cf320ec462372fd8536dca4781a)
### [3.2.0](https://github.com/taiga-family/maskito/compare/v3.1.2...v3.2.0) (2024-10-29)
### 🚀 Features
- **kit**: new `maskitoSelectionChangeHandler` plugin (#1794)
[(c6e9a4d)](https://github.com/taiga-family/maskito/commit/c6e9a4d9b1a2e75bc44aaecbda840b84f786d065)
### [3.1.2](https://github.com/taiga-family/maskito/compare/v3.1.1...v3.1.2) (2024-10-22)
### 🐞 Bug Fixes
- **kit**: `Time` & `DateTime` has conflicts between `step` & `AM/PM` features (#1791)
[(805f70b)](https://github.com/taiga-family/maskito/commit/805f70b74e04fb3b8613f89d84e771c734438dab)
- **kit**: `Number` incorrectly shift caret for 1st time insertion into textfield with initial value (#1792)
[(0049d91)](https://github.com/taiga-family/maskito/commit/0049d91a0a498977bb5f4cba9fbf9f02cb74dae9)
### [3.1.1](https://github.com/taiga-family/maskito/compare/v3.1.0...v3.1.1) (2024-10-17)
### 🐞 Bug Fixes
- **kit**: `Number` fails to prevent user insertion of extra spaces on invalid positions (#1789)
[(a40445c)](https://github.com/taiga-family/maskito/commit/a40445cf4d852328a9310a55cf38801e17525476)
- **kit**: `DateTime` fails to process value without any separators (paste from clipboard) (#1779)
[(1733422)](https://github.com/taiga-family/maskito/commit/1733422b803fda3de9b40a9fa675ef6bb8b5195e)
### [3.1.0](https://github.com/taiga-family/maskito/compare/v3.0.3...v3.1.0) (2024-10-09)
### 🚀 Features
- **kit**: `Time` & `DateTime` support `AM` / `PM` formats (#1708)
[(98ce35e)](https://github.com/taiga-family/maskito/commit/98ce35e8fd3318a750959d840f36caaf427fe8f0)
- **kit**: simplify some code logic for `Time` mask (#1688)
[(8c608b8)](https://github.com/taiga-family/maskito/commit/8c608b8cb5eaeca1166b78c6691d38303eb67c6c)
### 🐞 Bug Fixes
- **core**: `overwriteMode: replace` has incorrect behavior on attempt to insert invalid characters (#1772)
[(5aeb074)](https://github.com/taiga-family/maskito/commit/5aeb0741fa82ad6e43e862059a17b2e78ee9831b)
### [3.0.3](https://github.com/taiga-family/maskito/compare/v3.0.2...v3.0.3) (2024-09-25)
### 🐞 Bug Fixes
- **angular**: race condition when `[maskitoOptions]` are changed before long element predicate is resolved (#1696)
[(9f9bad3)](https://github.com/taiga-family/maskito/commit/9f9bad3036774fa51350c3c8402cf57f15e789d6)
- **kit**: `Time` has invalid segment separator for `MM:SS.MSS` mode (#1687)
[(93972be)](https://github.com/taiga-family/maskito/commit/93972be370e1abf4278497b11f61d3c923ae5caa)
- **core**: incorrect behavior of `overwriteMode = replace` if selection contains several characters (#1685)
[(67c3c10)](https://github.com/taiga-family/maskito/commit/67c3c10704f62efff4c47f1ad802859d54257752)
- **react**: race condition when `options` are changed before long element predicate is resolved (#1651)
[(f2932ce)](https://github.com/taiga-family/maskito/commit/f2932ce10ec80a1080befaee9e5c235bc41a1b16)
### [3.0.2](https://github.com/taiga-family/maskito/compare/v3.0.1...v3.0.2) (2024-09-20)
### 🐞 Bug Fixes
- **core:** `Time` with `[step]` has unexpected cursor jump to the next segment on `ArrowUp`/`ArrowDown`
([#1478](https://github.com/taiga-family/maskito/issues/1478))
([59a5927](https://github.com/taiga-family/maskito/commit/59a5927822e2c20691dc0948c438d67d497b6381))
- **core:** fix scroll for masked narrow textfields ([#1645](https://github.com/taiga-family/maskito/issues/1645))
([c6d2828](https://github.com/taiga-family/maskito/commit/c6d282873f10892ecb3536b878d919fc57f5c921))
### [3.0.1](https://github.com/taiga-family/maskito/compare/v3.0.0...v3.0.1) (2024-08-19)
### 🐞 Bug Fixes
- **kit:** `maskitoStringifyTime` was adding `0` on the wrong side
([#1401](https://github.com/taiga-family/maskito/issues/1401))
([b28ee12](https://github.com/taiga-family/maskito/commit/b28ee12f923b86eb3a8c32d17cd401e9222cfc30))
- **kit:** `Placeholder` should support partial programmatic removal of placeholder's characters
([#1441](https://github.com/taiga-family/maskito/issues/1441))
([146a557](https://github.com/taiga-family/maskito/commit/146a55723ec4a1ac8b9cfba254056b84173326c9))
- **kit:** `Time` incorrectly validates value if `timeSegmentMaxValues` includes single digit
([#1402](https://github.com/taiga-family/maskito/issues/1402))
([26670f4](https://github.com/taiga-family/maskito/commit/26670f4dbdfb84495ea0faa127868185d7bb0765))
## [3.0.0](https://github.com/taiga-family/maskito/compare/v2.5.0...v3.0.0) (2024-07-18)
### ⚠ BREAKING CHANGES
- **phone:** remove built-in `RemoveOnBlur` / `AddOnFocus` plugins from `@maskito/phone`
([#1352](https://github.com/taiga-family/maskito/issues/1352))
Learn more: https://maskito.dev/addons/phone#focus-blur
- **angular:** bump minimum required Angular version (15+ => 16+)
([#1328](https://github.com/taiga-family/maskito/issues/1328))
- **angular:** delete deprecated `MaskitoModule` & `MaskitoCVA`
([#1391](https://github.com/taiga-family/maskito/issues/1391))
### 🚀 Features
- **core:** new built-in `maskitoChangeEventPlugin` ([#1338](https://github.com/taiga-family/maskito/issues/1338))
Learn more: https://maskito.dev/core-concepts/plugins#change-event
## [2.5.0](https://github.com/taiga-family/maskito/compare/v2.4.0...v2.5.0) (2024-06-24)
### 🚀 Features
- **kit:** new `maskitoParseTime` and `maskitoStringifyTime` utils
([#1302](https://github.com/taiga-family/maskito/issues/1302))
([d0f9b13](https://github.com/taiga-family/maskito/commit/d0f9b1331f3bb18403691ac7c513c31f5123cf78))
### 🐞 Bug Fixes
- **core:** correct handling of browser autofill/suggestion in Firefox
([#1326](https://github.com/taiga-family/maskito/issues/1326))
([a049207](https://github.com/taiga-family/maskito/commit/a049207b355da72092948a8c556020062fb7c819))
- **kit:** `Date`, `DateRange`, `DateTime` supports multi-character date segments separator
([#1306](https://github.com/taiga-family/maskito/issues/1306))
([cdf2fae](https://github.com/taiga-family/maskito/commit/cdf2faee4c16cd3963557a511d4ec053e2d41fc0))
- **kit:** move caret after attempt to erase fixed character in a mask with `Placeholder`
([#1307](https://github.com/taiga-family/maskito/issues/1307))
([87ae431](https://github.com/taiga-family/maskito/commit/87ae431ded798e3c31d6247f965a00c27ddad3f1))
## [2.4.0](https://github.com/taiga-family/maskito/compare/v2.3.2...v2.4.0) (2024-06-03)
### 🚀 Features
- **kit:** `Time` & `DateTime` support increment / decrement of time segment via `ArrowUp` / `ArrowDown`
([#1223](https://github.com/taiga-family/maskito/issues/1223))
([af961b8](https://github.com/taiga-family/maskito/commit/af961b84f8765e7d2147c80210e3a8ac6ed30597))
- **kit:** `Time` supports `SS.MSS` & `MM.SS.MSS` modes ([#1224](https://github.com/taiga-family/maskito/issues/1224))
([7bed4bc](https://github.com/taiga-family/maskito/commit/7bed4bcaac14908e7e445b277f5b4b6e5b0fd281))
### 🐞 Bug Fixes
- **core:** add `.select()`-method support for `MaskitoElement`
([#1268](https://github.com/taiga-family/maskito/issues/1268))
([51f5934](https://github.com/taiga-family/maskito/commit/51f5934f382b7862a6653412b687c46fd318b0bb))
- **kit:** `Number` should support float `min`/`max`-parameters in range -1 < x < 1
([#1280](https://github.com/taiga-family/maskito/issues/1280))
([b44013e](https://github.com/taiga-family/maskito/commit/b44013e0a45ffcfa69564f13d634a79d45b4d926))
### [2.3.2](https://github.com/taiga-family/maskito/compare/v2.3.1...v2.3.2) (2024-05-16)
### 🐞 Bug Fixes
- **kit:** `Number` pads integer part with zero if user selects all and then types decimal separator
([#1220](https://github.com/taiga-family/maskito/issues/1220))
([8371e45](https://github.com/taiga-family/maskito/commit/8371e45767150ebc4db03a2b74c68afd6fe1e593))
- **phone:** revert mistakenly fixated `libphonenumber-js` peer-dependency to just `>=1.0.0`
([#1234](https://github.com/taiga-family/maskito/issues/1234))
([27ee4a1](https://github.com/taiga-family/maskito/commit/27ee4a1264c0a70a5a06427368b8d18ed0e25bd4))
- **react:** revert mistakenly fixated `react` & `react-demo` peer-dependencies to just `>=16.8`
([#1231](https://github.com/taiga-family/maskito/issues/1231))
([ae89d6f](https://github.com/taiga-family/maskito/commit/ae89d6ff549dfb21d7db56b26e3c1f3a7044a817))
- **vue:** revert mistakenly fixated `vue` peer-dependency to just `>=3.0.0`
([#1232](https://github.com/taiga-family/maskito/issues/1232))
([22d84e2](https://github.com/taiga-family/maskito/commit/22d84e2f731ae8798f457466be7c9538d2f40fd9))
### [2.3.1](https://github.com/taiga-family/maskito/compare/v2.3.0...v2.3.1) (2024-04-23)
### 🐞 Bug Fixes
- **kit:** `Number` should drop decimal separator if all digits are erased
([#1211](https://github.com/taiga-family/maskito/issues/1211))
([5836c96](https://github.com/taiga-family/maskito/commit/5836c965d6ce5ad497aaa59118204adc3e8625d8))
- **kit:** `Number` with `decimalZeroPadding=true` should erase everything on `.00`
([#1207](https://github.com/taiga-family/maskito/issues/1207))
([d72f225](https://github.com/taiga-family/maskito/commit/d72f2257cec1a023aa81bb7de62e9543404630bd))
- **kit:** `Placeholder` can have now the same character as textfield's value
([#1209](https://github.com/taiga-family/maskito/issues/1209))
([ed06936](https://github.com/taiga-family/maskito/commit/ed06936c41297cbd2e8ed308558914e9ad6c2eda))
## [2.3.0](https://github.com/taiga-family/maskito/compare/v2.2.0...v2.3.0) (2024-04-16)
### 🚀 Features
- **core:** add `contenteditable` support ([#1039](https://github.com/taiga-family/maskito/issues/1039))
([0d5bb31](https://github.com/taiga-family/maskito/commit/0d5bb319225fb61f3ac7643c21208122b4a2a2ae))
- **kit:** `DateTime` supports configurable parameter `dateTimeSeparator`
([#1143](https://github.com/taiga-family/maskito/issues/1143))
([ec86284](https://github.com/taiga-family/maskito/commit/ec8628467814cff7dfae22668370236f402d8146))
### 🐞 Bug Fixes
- **kit:** `Date` formatting errors for `mm/yyyy`, `yyyy/mm`, `mm/yy` modes
([#1177](https://github.com/taiga-family/maskito/issues/1177))
([948a350](https://github.com/taiga-family/maskito/commit/948a35098da2233bc78793eb7e83b7c5136becbd))
## [2.2.0](https://github.com/taiga-family/maskito/compare/v2.1.0...v2.2.0) (2024-03-07)
### 🚀 Features
- **kit:** `Number` supports new configurable parameter `minusSign`
([#1118](https://github.com/taiga-family/maskito/issues/1118))
([a7bec35](https://github.com/taiga-family/maskito/commit/a7bec35f19d7dfa4023ad83fa36a935b2d636fc7))
### 🐞 Bug Fixes
- totally disable `Maskito` if nullable options are passed inside `@maskito/{angular,react,vue}`
([#1117](https://github.com/taiga-family/maskito/issues/1117))
([8cbadcf](https://github.com/taiga-family/maskito/commit/8cbadcfdf9af283dc687b131361f7bb19a7f9b02))
## [2.1.0](https://github.com/taiga-family/maskito/compare/v2.0.2...v2.1.0) (2024-03-04)
### 🚀 Features
- **kit:** `Date` & `DateRange` & `DateTime` has improved zero-padding support for browser autofill & IME composition
([#1027](https://github.com/taiga-family/maskito/issues/1027))
([77ac01c](https://github.com/taiga-family/maskito/commit/77ac01ca0b5e61d36dc3240a35c3dc93ce5fe93c))
- **kit:** add full-width numbers support for `Time`, `Date`, `DateTime`, `DateRange`
([#1043](https://github.com/taiga-family/maskito/issues/1043))
([434c9c5](https://github.com/taiga-family/maskito/commit/434c9c5f349ab3c19e11722e95313c5763203b08))
### 🐞 Bug Fixes
- **kit:** `maskitoParseNumber` should interpret japanese prolonged sound mark as pseudo minus
([#1115](https://github.com/taiga-family/maskito/issues/1115))
([b152698](https://github.com/taiga-family/maskito/commit/b152698fda8ac671286eb5f4a29de62562934fa2))
### [2.0.2](https://github.com/taiga-family/maskito/compare/v2.0.1...v2.0.2) (2024-02-01)
### 🐞 Bug Fixes
- **kit:** `Number` with initial value has problems with the first time input
([#986](https://github.com/taiga-family/maskito/issues/986))
([e40d3ff](https://github.com/taiga-family/maskito/commit/e40d3ff93c668c8afa60cd347faa7ebec76d0e6a))
- **react:** `@maskito/react` includes again missing `cjs` module format
([#991](https://github.com/taiga-family/maskito/issues/991))
([18e3e0c](https://github.com/taiga-family/maskito/commit/18e3e0cf8911fa764a73e2e937081186f1dcde79))
### [2.0.1](https://github.com/taiga-family/maskito/compare/v2.0.0...v2.0.1) (2024-01-31)
### 🐞 Bug Fixes
- **core:** `maskitoUpdateElement` should not dispatch `InputEvent` if value is not changed
([#977](https://github.com/taiga-family/maskito/issues/977))
([2410b64](https://github.com/taiga-family/maskito/commit/2410b6478c88f4d530b4469d7d50b1e4663d1572))
- **core:** don't execute `setSelectionRange` if element is not focused
([#937](https://github.com/taiga-family/maskito/issues/937))
([92f288b](https://github.com/taiga-family/maskito/commit/92f288b677dbe77f7978308dd7b1612d6bfd68fb))
- **kit:** `Number` rejects the first time input of full width digits
([#955](https://github.com/taiga-family/maskito/issues/955))
([c416884](https://github.com/taiga-family/maskito/commit/c41688488630e83d69eba795580916145e5fe17c))
- **react:** `@maskito/react` library should not include `core-js` imports
([#962](https://github.com/taiga-family/maskito/issues/962))
([3b7e401](https://github.com/taiga-family/maskito/commit/3b7e4014029fae206020723c18762f08e92b8c41))
## [2.0.0](https://github.com/taiga-family/maskito/compare/v1.9.0...v2.0.0) (2024-01-22)
### ⚠ BREAKING CHANGES
- **core:** merge `MaskitoElementPredicate` & `MaskitoElementPredicateAsync` into single type
([#757](https://github.com/taiga-family/maskito/issues/757))
- **core:** remove value's calibration on initialization + new `maskitoInitialCalibrationPlugin`
([#778](https://github.com/taiga-family/maskito/issues/778))
- **core:** bump Firefox browser support (55+ => 87+) ([#876](https://github.com/taiga-family/maskito/issues/876)) and
drop legacy fallbacks for `Firefox` ([#756](https://github.com/taiga-family/maskito/issues/756))
- **kit:** delete deprecated `separator` for `DateRange` (use `dateSeparator` instead)
([#790](https://github.com/taiga-family/maskito/issues/790))
- **angular:** bump minimum required Angular version (12+ => 15+)
([#710](https://github.com/taiga-family/maskito/issues/710))
([#720](https://github.com/taiga-family/maskito/issues/720))
([#725](https://github.com/taiga-family/maskito/issues/725))
- **angular:** deprecate `MaskitoModule` (use standalone `MaskitoDirective`, `MaskitoCVA`, `MaskitoPipe`)
([#754](https://github.com/taiga-family/maskito/issues/754))
### 🚀 More features
- **core:** new built-in `maskitoStrictCompositionPlugin` ([#881](https://github.com/taiga-family/maskito/issues/881))
- **kit:** `Number` allows to enter full width numbers ([#864](https://github.com/taiga-family/maskito/issues/864))
### 🐞 Bug Fixes
- **core:** drop some excess dispatches of `Input`-event ([#882](https://github.com/taiga-family/maskito/issues/882))
- **kit:** add `{bubbles:true}` for `input` events inside all built-in plugins to support `ReactSyntheticEvent`
([#806](https://github.com/taiga-family/maskito/issues/806))
- **kit:** `Number` has problems when prefix/postfix includes `decimalSeparator` symbol
([#874](https://github.com/taiga-family/maskito/issues/874))
([#816](https://github.com/taiga-family/maskito/issues/816))
([#921](https://github.com/taiga-family/maskito/issues/921))
- **kit:** `Placeholder` is not compatible with `maskitoEventHandler` + `focus`/`blur` events
([#928](https://github.com/taiga-family/maskito/pull/928))
## [1.9.0](https://github.com/taiga-family/maskito/compare/v1.8.2...v1.9.0) (2023-11-23)
### 🚀 Features
- **phone:** add ability to configure the separator ([#685](https://github.com/taiga-family/maskito/issues/685))
([ab6bb11](https://github.com/taiga-family/maskito/commit/ab6bb11b1b40e069d31598b676c04456329aaf64))
### [1.8.2](https://github.com/taiga-family/maskito/compare/v1.8.1...v1.8.2) (2023-11-16)
### 🐞 Bug Fixes
- **kit:** `PrefixPostprocessor` has problems with multi-character prefix
([#669](https://github.com/taiga-family/maskito/issues/669))
([be459e5](https://github.com/taiga-family/maskito/commit/be459e51f3cbf028fa36b1b6a57e47d7fe8482a3))
### [1.8.1](https://github.com/taiga-family/maskito/compare/v1.8.0...v1.8.1) (2023-10-19)
### 🐞 Bug Fixes
- **kit:** `Date` accept single character date segment during paste
([#610](https://github.com/taiga-family/maskito/issues/610))
([e493198](https://github.com/taiga-family/maskito/commit/e4931987c2fad37894ea07f658f08e35152040df))
## [1.8.0](https://github.com/taiga-family/maskito/compare/v1.7.0...v1.8.0) (2023-10-18)
### 🚀 Features
- **angular:** allow nullable options ([#605](https://github.com/taiga-family/maskito/issues/605))
([21eaa7c](https://github.com/taiga-family/maskito/commit/21eaa7c0c0e7d5173c6f070f5222ba6492e196a6))
### 🐞 Bug Fixes
- **kit:** `Number` has broken zero padding when `decimalSeparator` equals to non-default value
([#586](https://github.com/taiga-family/maskito/issues/586))
([7241761](https://github.com/taiga-family/maskito/commit/72417614dd4974c22854dfacc2ee35044c080074))
## [1.7.0](https://github.com/taiga-family/maskito/compare/v1.6.0...v1.7.0) (2023-09-15)
### 🚀 Features
New `@maskito/phone` library ([#425](https://github.com/taiga-family/maskito/pull/425))
([#482](https://github.com/taiga-family/maskito/issues/482))
Learn more: https://maskito.dev/addons/phone
## [1.6.0](https://github.com/taiga-family/maskito/compare/v1.5.1...v1.6.0) (2023-09-15)
### 🚀 Features
- **react:** `elementPredicate` can accept asynchronous predicate
([#502](https://github.com/taiga-family/maskito/issues/502))
([4bbf758](https://github.com/taiga-family/maskito/commit/4bbf758107ed4b2fdbde5a241f22c0f363c22104))
### 🐞 Bug Fixes
- **kit:** `Number` should accept all types of spaces as interchangeable characters for `thousandSeparator`
([#505](https://github.com/taiga-family/maskito/issues/505))
([73975bb](https://github.com/taiga-family/maskito/commit/73975bbc676487330359056c367f73e32ea6eaf4))
### [1.5.1](https://github.com/taiga-family/maskito/compare/v1.5.0...v1.5.1) (2023-09-08)
### 🐞 Bug Fixes
- **vue:** `elementPredicate` should accept `MaskitoElementPredicateAsync` type
([#487](https://github.com/taiga-family/maskito/issues/487))
([fe7e9dc](https://github.com/taiga-family/maskito/commit/fe7e9dcb468bf3ab30978c947d8fa21cc0e51a75))
## [1.5.0](https://github.com/taiga-family/maskito/compare/v1.4.0...v1.5.0) (2023-09-04)
### 🚀 Features
- **core:** add IME composition support ([#467](https://github.com/taiga-family/maskito/issues/467))
([e7d664b](https://github.com/taiga-family/maskito/commit/e7d664b66a008a742c0a532e341b0e0bb0a0f759))
- **demo:** documentation is now available at https://maskito.dev
([#392](https://github.com/taiga-family/maskito/issues/392))
([355f87f](https://github.com/taiga-family/maskito/commit/355f87fd536758bc2db59f760ed114d28264122a))
### 🐞 Bug Fixes
- **kit:** `maskitoCaretGuard` doesn't work after focus on `<select />`
([#462](https://github.com/taiga-family/maskito/issues/462))
([9f456da](https://github.com/taiga-family/maskito/commit/9f456dad7f7f9d02db4eb5993ecb5fb5aabfe613))
- **kit:** `Number` should drop items from `decimalPseudoSeparators` if any is equal to `thousandSeparator`
([#390](https://github.com/taiga-family/maskito/issues/390))
([2107adc](https://github.com/taiga-family/maskito/commit/2107adc445ed26ce1507c5e0c534b668d7ae5b12))
## [1.4.0](https://github.com/taiga-family/maskito/compare/v1.3.0...v1.4.0) (2023-07-27)
### 🚀 Features
- **kit:** `Date` & `DateRange` support new modes `yyyy`, `mm/yyyy`, `yyyy/mm`
([#384](https://github.com/taiga-family/maskito/issues/384))
([7886d50](https://github.com/taiga-family/maskito/commit/7886d50012a76fec872816b6d5e2b7e67c931dd7))
- **kit:** `Time` supports new mode `HH` ([#385](https://github.com/taiga-family/maskito/issues/385))
([3c7a3f6](https://github.com/taiga-family/maskito/commit/3c7a3f65a0013152473ba57af8da28012cb58f32))
## [1.3.0](https://github.com/taiga-family/maskito/compare/v1.2.2...v1.3.0) (2023-07-24)
### 🚀 Features
- **kit:** `DateRange` add configurable parameter `rangeSeparator`
([#376](https://github.com/taiga-family/maskito/issues/376))
([d904842](https://github.com/taiga-family/maskito/commit/d90484214da76f4c73ad925eef5fe391a154c499))
### 🐞 Bug Fixes
- **kit:** `Number` has problems with run-time updates of postfix
([#380](https://github.com/taiga-family/maskito/issues/380))
([8210896](https://github.com/taiga-family/maskito/commit/8210896d2095a44e79a27a38e4c8745e2beccdb7))
### [1.2.2](https://github.com/taiga-family/maskito/compare/v1.2.1...v1.2.2) (2023-07-19)
### 🐞 Bug Fixes
- **kit:** `maskitoCaretGuard` should wait for `mouseup` before execution
([#372](https://github.com/taiga-family/maskito/issues/372))
([8554fea](https://github.com/taiga-family/maskito/commit/8554fead2a2474104f0674fb597cf86467274943))
- **kit:** `Number` should remove repeated leading zeroes for integer part only on `blur`-event
([#373](https://github.com/taiga-family/maskito/issues/373))
([7cf4938](https://github.com/taiga-family/maskito/commit/7cf4938853ccbd049b89482f8eb22ab4e71fe01f))
### [1.2.1](https://github.com/taiga-family/maskito/compare/v1.2.0...v1.2.1) (2023-07-11)
### 🐞 Bug Fixes
- **kit:** `Number` with `postfix` should be compatible with `decimalZeroPadding`
([#364](https://github.com/taiga-family/maskito/issues/364))
([501cf9c](https://github.com/taiga-family/maskito/commit/501cf9c747229d1776fb62cc04fbc8879990c617))
- **kit:** `Prefix`/`Postfix` is incompatible if they end/start with the same character
([#366](https://github.com/taiga-family/maskito/issues/366))
([06afbcb](https://github.com/taiga-family/maskito/commit/06afbcb4a2c5c15e2ef9dc81db4309adf01aa8ef))
## [1.2.0](https://github.com/taiga-family/maskito/compare/v1.1.1...v1.2.0) (2023-07-03)
### 🚀 Features
- **kit:** `maskitoCaretGuard`'s function has the 2nd argument with current selection range
([#358](https://github.com/taiga-family/maskito/issues/358))
([eedc4d6](https://github.com/taiga-family/maskito/commit/eedc4d610efaf36b98a4049f5c5334561b5b21c5))
### 🐞 Bug Fixes
- **kit:** `maskitoCaretGuard` incorrectly validates the left side of constraints
([#356](https://github.com/taiga-family/maskito/issues/356))
([17ee90f](https://github.com/taiga-family/maskito/commit/17ee90fe055f6a8370d6ea75ff2b236fd498441e))
- **kit:** `Number` should skip min/max validation if value does not contain any digits
([#359](https://github.com/taiga-family/maskito/issues/359))
([ed8221e](https://github.com/taiga-family/maskito/commit/ed8221e14eca62334af41b4c8e571eb86ed68247))
### [1.1.1](https://github.com/taiga-family/maskito/compare/v1.1.0...v1.1.1) (2023-06-29)
### 🐞 Bug Fixes
- **core:** don't ignore native attribute `maxlength` ([#350](https://github.com/taiga-family/maskito/issues/350))
([8504f49](https://github.com/taiga-family/maskito/commit/8504f497152931da06dd745763be2505587f97b4))
- **kit:** `Number` should ignore new typed decimal separator if it already exists in text field
([#351](https://github.com/taiga-family/maskito/issues/351))
([4ccfdc8](https://github.com/taiga-family/maskito/commit/4ccfdc86ff08bcebfd18c04403aa9c9c83cbbd02))
## [1.1.0](https://github.com/taiga-family/maskito/compare/v1.0.0...v1.1.0) (2023-06-23)
### 🚀 Features
- **kit:** `maskitoEventHandler` accepts `AddEventListenerOptions` as the 3d optional argument
([#346](https://github.com/taiga-family/maskito/issues/346))
([1d5866e](https://github.com/taiga-family/maskito/commit/1d5866efa5e0e4736dd735ae006e027e9bd01e31))
- **kit:** use capturing phase for `focus`/`blur` events in plugins
([#347](https://github.com/taiga-family/maskito/issues/347))
([ef539e1](https://github.com/taiga-family/maskito/commit/ef539e160f601023e513036d704f7daff9689286))
### 🐞 Bug Fixes
- **kit:** `Date` allows to replace the whole selection range with zero
([#345](https://github.com/taiga-family/maskito/issues/345))
([98fd21d](https://github.com/taiga-family/maskito/commit/98fd21d50899db365b864faf597fad9a21a3db06))
## [1.0.0](https://github.com/taiga-family/maskito/compare/v0.16.0...v1.0.0) (2023-06-21)
### ⚠ BREAKING CHANGES
- **core:** delete deprecated `preprocessor` & `postprocessor` from `MaskitoOptions`
([#337](https://github.com/taiga-family/maskito/issues/337))
([0b6aad2](https://github.com/taiga-family/maskito/commit/0b6aad2622ed152d12c91f8ca64b767709ecdbc2))
- **kit:** delete deprecated `isNegativeAllowed` parameter from `Number` mask
([#338](https://github.com/taiga-family/maskito/issues/338))
([9fd3005](https://github.com/taiga-family/maskito/commit/9fd30055b3157072076f7a8567045fac05b6af9e))
## [0.16.0](https://github.com/taiga-family/maskito/compare/v0.15.0...v0.16.0) (2023-06-20)
### 🚀 Features
- **vue:** support async predicate ([#336](https://github.com/taiga-family/maskito/issues/336))
([d1452b5](https://github.com/taiga-family/maskito/commit/d1452b5f1b2f8a252dfd05a5c1eb04ba971a1970))
### 🐞 Bug Fixes
- **kit:** `Number` fails to parse small number on blur (exponential notation problem)
([#339](https://github.com/taiga-family/maskito/issues/339))
([7f83a7f](https://github.com/taiga-family/maskito/commit/7f83a7f170906c1911eb4444da2d636c0338ed4a))
## [0.15.0](https://github.com/taiga-family/maskito/compare/v0.14.0...v0.15.0) (2023-06-14)
### 🚀 Features
- **core:** add new parameters `preprocessors` & `postprocessors` and deprecate `preprocessor` & `postprocessor`
([#333](https://github.com/taiga-family/maskito/issues/333))
([0137775](https://github.com/taiga-family/maskito/commit/01377751a9875143257930934b1e2a9143b6da03))
### 🐞 Bug Fixes
- **kit:** `maskitoParseNumber` should return `NaN` for all strings with no digits
([#331](https://github.com/taiga-family/maskito/issues/331))
([d1ebcec](https://github.com/taiga-family/maskito/commit/d1ebceceedf418b21a68082f7350002d09159ebf))
- **kit:** `Number` incorrectly implements `min`/`max` behaviour
([#334](https://github.com/taiga-family/maskito/issues/334))
([9876d88](https://github.com/taiga-family/maskito/commit/9876d885f98f86d18db04d723460b468bca3837d))
## [0.14.0](https://github.com/taiga-family/maskito/compare/v0.13.0...v0.14.0) (2023-06-09)
### 🚀 Features
- **angular:** `[maskitoElement]` can accept asynchronous predicate
([#316](https://github.com/taiga-family/maskito/issues/316))
([3d8949e](https://github.com/taiga-family/maskito/commit/3d8949e878e644079b7f5404cb9ebf6c5eadab86))
- **kit:** `Number` pads empty integer part with zero on blur (if decimal part exists)
([#328](https://github.com/taiga-family/maskito/issues/328))
([bd01967](https://github.com/taiga-family/maskito/commit/bd01967fba38be26a3c8f0d2f23c0ced12d3b1c2))
## [0.13.0](https://github.com/taiga-family/maskito/compare/v0.12.1...v0.13.0) (2023-06-02)
### 🚀 Features
- **core:** better layout-independent way to detect `Undo` and `Redo`
([#320](https://github.com/taiga-family/maskito/issues/320))
([4c5a7f6](https://github.com/taiga-family/maskito/commit/4c5a7f64b9a8ac209584c75e17ec022674b87c1b))
- **vue:** add dedicated Vue package ([#321](https://github.com/taiga-family/maskito/issues/321))
([f6ffb24](https://github.com/taiga-family/maskito/commit/f6ffb24eca5f1a1a57a93103b9e74cdf410e4132))
### [0.12.1](https://github.com/taiga-family/maskito/compare/v0.12.0...v0.12.1) (2023-05-25)
### 🐞 Bug Fixes
- **kit:** `DateTime` validate min / max if date is complete
([#314](https://github.com/taiga-family/maskito/issues/314))
([5783e76](https://github.com/taiga-family/maskito/commit/5783e766a657abcf0fc7f8a8d12ac1bf412dc18a))
- **kit:** `Time` & `DateTime` should accept time segment separator typed by user
([#317](https://github.com/taiga-family/maskito/issues/317))
([3bcac7f](https://github.com/taiga-family/maskito/commit/3bcac7f6566043991a9211f04db744a5ec6f019f))
## [0.12.0](https://github.com/taiga-family/maskito/compare/v0.11.1...v0.12.0) (2023-05-19)
### 🚀 Features
- **core:** add `plugins` to `MaskitoOptions` ([#305](https://github.com/taiga-family/maskito/issues/305))
([b512ae2](https://github.com/taiga-family/maskito/commit/b512ae2c64b2a2c6560e2e5c68d8c72952474c71))
- **core:** expose `MaskitoMask`, `MaskitoPreprocessor`, `MaskitoPostprocessor` and `MaskitoPlugin`
([#307](https://github.com/taiga-family/maskito/issues/307))
([9315a9f](https://github.com/taiga-family/maskito/commit/9315a9f4620b3be86cf3b7af993861664f281a19))
- **kit:** new `maskitoWithPlaceholder` utility ([#299](https://github.com/taiga-family/maskito/issues/299))
([21eb69c](https://github.com/taiga-family/maskito/commit/21eb69cfeb73bbe645d5a5879659ab8b6aadbf0c))
### [0.11.1](https://github.com/taiga-family/maskito/compare/v0.11.0...v0.11.1) (2023-05-11)
### 🐞 Bug Fixes
- **core:** `insertFromDrop` action behaves now in the same way as `insertFromPaste`
([#291](https://github.com/taiga-family/maskito/issues/291))
([58e0fcc](https://github.com/taiga-family/maskito/commit/58e0fccb7ddd3c741ffa3c8b99efbcf4571aab37))
- **kit:** `Time` doesn't validate time segments on `drop` event
([#289](https://github.com/taiga-family/maskito/issues/289))
([0c6d1b9](https://github.com/taiga-family/maskito/commit/0c6d1b9917d0c86a98c0d215c38a0e2076ff5680))
## [0.11.0](https://github.com/taiga-family/maskito/compare/v0.10.0...v0.11.0) (2023-05-02)
### 🚀 Features
- **react:** new library `@maskito/react` ([#273](https://github.com/taiga-family/maskito/issues/273))
([4c2f755](https://github.com/taiga-family/maskito/commit/4c2f755bac9513689964af7fdb7f4deec56bfb52))
## [0.10.0](https://github.com/taiga-family/maskito/compare/v0.9.0...v0.10.0) (2023-04-25)
### 🚀 Features
- **kit:** `Number` keeps untouched decimal part if `precision: Infinity`
([#253](https://github.com/taiga-family/maskito/issues/253))
([261779e](https://github.com/taiga-family/maskito/commit/261779ead327397a61b27e634bc827ee70b718f4))
- **kit:** `Number` supports new `prefix` & `postfix` parameters
([#264](https://github.com/taiga-family/maskito/issues/264))
([6e78581](https://github.com/taiga-family/maskito/commit/6e785818dabcde623d8c1c40a584166a0a66f5b6))
- **kit:** new `maskitoPostfixPostprocessorGenerator` ([#257](https://github.com/taiga-family/maskito/issues/257))
([fdc86db](https://github.com/taiga-family/maskito/commit/fdc86dbad368bfc17efd1047b7d68d9622968bb0))
### 🐞 Bug Fixes
- **kit:** `Number` fails to trim leading zeroes after deleting of leading digit
([#268](https://github.com/taiga-family/maskito/issues/268))
([4ae0010](https://github.com/taiga-family/maskito/commit/4ae0010ef2149694d22d7ae9eb8c9880120c8c75))
- **kit:** `Number` should trim redundant thousand separators
([#267](https://github.com/taiga-family/maskito/issues/267))
([100b793](https://github.com/taiga-family/maskito/commit/100b79317a420103ca98a3b43fe646a6f77d19d5))
- **kit:** fix first zero in short-format date-mask ([#251](https://github.com/taiga-family/maskito/issues/251))
([08bdfd2](https://github.com/taiga-family/maskito/commit/08bdfd26727777c3a6fc870e433003be2b64cc0e))
## [0.9.0](https://github.com/taiga-family/maskito/compare/v0.8.1...v0.9.0) (2023-03-31)
### 🚀 Features
- **kit:** new `maskitoPrefixPostprocessorGenerator` ([#235](https://github.com/taiga-family/maskito/issues/235))
([50f0d58](https://github.com/taiga-family/maskito/commit/50f0d58ccbfa22d15174d76479a9d642687db099))
### 🐞 Bug Fixes
- **angular:** Jest throws `Class constructor DefaultValueAccessor cannot be invoked without 'new'`
([#232](https://github.com/taiga-family/maskito/issues/232))
([5089612](https://github.com/taiga-family/maskito/commit/508961288898a5fdd21cc0e26b23ecc8845f9068))
### [0.8.1](https://github.com/taiga-family/maskito/compare/v0.8.0...v0.8.1) (2023-03-27)
### 🐞 Bug Fixes
- `@maskito/core` & `@maskito/kit` now include both `UMD` and `ESM` module formats
([#227](https://github.com/taiga-family/maskito/issues/227))
([fa1c514](https://github.com/taiga-family/maskito/commit/fa1c514a5753e3bca20e8b0994e4bf9f1c0ab6a4))
## [0.8.0](https://github.com/taiga-family/maskito/compare/v0.7.2...v0.8.0) (2023-03-23)
### 🚀 Features
- **kit:** `DateRange` swaps dates if the 2nd date is less than the 1st one
([#212](https://github.com/taiga-family/maskito/issues/212))
([3efbb42](https://github.com/taiga-family/maskito/commit/3efbb42f2dd5c4e43ff514da7a82abfc7c4b3a38))
### 🐞 Bug Fixes
- **core:** incorrect order of actions during update of native element
([#225](https://github.com/taiga-family/maskito/issues/225))
([394d5d9](https://github.com/taiga-family/maskito/commit/394d5d996bdb9d21229ea0301eb3f776bee05d30))
### [0.7.2](https://github.com/taiga-family/maskito/compare/v0.7.1...v0.7.2) (2023-03-23)
### 🐞 Bug Fixes
- **angular:** `@maskito/angular` should not depend on `@maskito/kit`
([#221](https://github.com/taiga-family/maskito/issues/221))
([0ae7b20](https://github.com/taiga-family/maskito/commit/0ae7b2089ec0436caa8dbb14d5c696ae93e9e7ed))
- **angular:** `npm i @maskito/angular` throws `unable to resolve dependency tree`
([#220](https://github.com/taiga-family/maskito/issues/220))
([8b4d6e6](https://github.com/taiga-family/maskito/commit/8b4d6e6186db47f97d328186b7afd9af75a3889b))
### [0.7.1](https://github.com/taiga-family/maskito/compare/v0.7.0...v0.7.1) (2023-03-22)
### 🐞 Bug Fixes
- **angular:** use `@nrwl/angular:package` executor instead of `@nrwl/angular:ng-packagr-lite`
([#216](https://github.com/taiga-family/maskito/issues/216))
([164d015](https://github.com/taiga-family/maskito/commit/164d015c2f18a279e195b45329e84c0d023c9483))
- **kit:** `Number` broken `Delete`-button navigation if `decimalZeroPadding=true`
([#211](https://github.com/taiga-family/maskito/issues/211))
([1b750d1](https://github.com/taiga-family/maskito/commit/1b750d135ebd53bfeda2ca734425de08a808b1af))
## [0.7.0](https://github.com/taiga-family/maskito/compare/v0.6.0...v0.7.0) (2023-03-20)
### 🚀 Features
- **core:** add `deleteSoftLineBackward` & `deleteSoftLineForward` support
([#207](https://github.com/taiga-family/maskito/issues/207))
([cbd5479](https://github.com/taiga-family/maskito/commit/cbd5479c04c07113804eee6ea6c9838ee8681597))
- **kit:** use 1 as min segment value in `Date`-related masks
([#197](https://github.com/taiga-family/maskito/issues/197))
([c85ca23](https://github.com/taiga-family/maskito/commit/c85ca2355cb0b6fcef73f3e7497f7c31fa82c87c))
### 🐞 Bug Fixes
- **core:** `Maskito` losses valid characters on invalid insertion (`overwriteMode: replace`)
([#208](https://github.com/taiga-family/maskito/issues/208))
([ef183b4](https://github.com/taiga-family/maskito/commit/ef183b454e4a7db5b2cb48cbe26129bf303f676a))
- **kit:** `Number` should drop leading zeroes for negative numbers
([#204](https://github.com/taiga-family/maskito/issues/204))
([6e9adf7](https://github.com/taiga-family/maskito/commit/6e9adf758aa585944ee08f2e2aff81a5664adefd))
## [0.6.0](https://github.com/taiga-family/maskito/compare/v0.5.0...v0.6.0) (2023-03-15)
### 🚀 Features
- **angular:** add CVA and pipe ([#187](https://github.com/taiga-family/maskito/issues/187))
([a099257](https://github.com/taiga-family/maskito/commit/a099257a16b569444cdae9276ce66e9a806f531e))
- **core:** add `deleteWordBackward` & `deleteWordForward` support
([#193](https://github.com/taiga-family/maskito/issues/193))
([24b761c](https://github.com/taiga-family/maskito/commit/24b761c84d0947df5e4c78a2114f1de8f6ca20f4))
### 🐞 Bug Fixes
- **core:** show trailing fixed characters + duplicated fixed character on `Drop`
([#185](https://github.com/taiga-family/maskito/issues/185))
([c7f6a1b](https://github.com/taiga-family/maskito/commit/c7f6a1bb8098b5641ed8c6921c2ebc86c6135b58))
- **kit:** `maskitoParseNumber` incorrectly parses negative numbers
([#190](https://github.com/taiga-family/maskito/issues/190))
([d713bd1](https://github.com/taiga-family/maskito/commit/d713bd143e5090870a406ea14498cb99843bb9d0))
- **kit:** `Number` should drop decimal part on paste from clipboard if `precision=0`
([#195](https://github.com/taiga-family/maskito/issues/195))
([ba85c38](https://github.com/taiga-family/maskito/commit/ba85c38ec0c81a22ff758f4ba386d045ac49ffd5))
## [0.5.0](https://github.com/taiga-family/maskito/compare/v0.4.0...v0.5.0) (2023-03-09)
### 🚀 Features
- **core:** new utility `maskitoTransform(value, maskitoOptions)`
([#177](https://github.com/taiga-family/maskito/issues/177))
([20316f1](https://github.com/taiga-family/maskito/commit/20316f15e153bfeeb45eda6406b8792e00f3238f))
- **kit:** new utility `maskitoParseNumber` ([#178](https://github.com/taiga-family/maskito/issues/178))
([fc58141](https://github.com/taiga-family/maskito/commit/fc58141625ecbdc7d804aa382a69b38bf7146fc4))
### 🐞 Bug Fixes
- **kit:** `Number` mask throws an error on empty string in `thousandSeparator`
([#176](https://github.com/taiga-family/maskito/issues/176))
([cd52fad](https://github.com/taiga-family/maskito/commit/cd52fad80bc278f171dafa1709c54cba3f8fbc81))
## [0.4.0](https://github.com/taiga-family/maskito/compare/v0.3.0...v0.4.0) (2023-03-02)
### 🚀 Features
- **angular:** `maskitoElement` add new input ([#164](https://github.com/taiga-family/maskito/issues/164))
([407c131](https://github.com/taiga-family/maskito/commit/407c131d2d8f8514173ad7a5e248759e2d4f8abc))
### 🐞 Bug Fixes
- **kit:** `Number` pads empty integer part when paste from clipboard
([#168](https://github.com/taiga-family/maskito/issues/168))
([d043a82](https://github.com/taiga-family/maskito/commit/d043a82561cbed94b19d59d174fa6da7f08d49d4))
## [0.3.0](https://github.com/taiga-family/maskito/compare/v0.2.0...v0.3.0) (2023-03-01)
### 🚀 Features
- **angular:** add other maskito packages to `ng-update.packageGroup` of `package.json`
([#161](https://github.com/taiga-family/maskito/issues/161))
([bdecdaa](https://github.com/taiga-family/maskito/commit/bdecdaa9cac2681e35191cabd2d5d853eb97a09d))
### 🐞 Bug Fixes
- **kit:** `Date`-mask fix wrong year that appears using the min property
([#157](https://github.com/taiga-family/maskito/issues/157))
([544e891](https://github.com/taiga-family/maskito/commit/544e8912d2752e0fc8f77757e935070b94823f65))
## [0.2.0](https://github.com/taiga-family/maskito/compare/v0.1.1...v0.2.0) (2023-02-28)
### 🚀 Features
- **kit:** new `DateTime` mask ([#146](https://github.com/taiga-family/maskito/issues/146))
([6d6b2c1](https://github.com/taiga-family/maskito/commit/6d6b2c17b5c0f62bc804451524cd4b2ce3e50660))
### 🐞 Bug Fixes
- **kit:** `Number` is now replacing hyphen, en-dash and em-dash with minus sign
([#153](https://github.com/taiga-family/maskito/issues/153))
([1f21f11](https://github.com/taiga-family/maskito/commit/1f21f1159baadcef65e49bacaec77eba3b6f36d8))
### [0.1.1](https://github.com/taiga-family/maskito/compare/v0.1.0...v0.1.1) (2023-02-15)
### 🐞 Bug Fixes
- **core:** `Module parse failed: 'import' and 'export' may appear only with 'sourceType: module'`
([#131](https://github.com/taiga-family/maskito/issues/131))
([41e05c0](https://github.com/taiga-family/maskito/commit/41e05c09e41ed611e0c2b9aa07a953dfbe049da7))
## 0.1.0 (2023-02-14)
This release introduces the first publishing of the following packages:
- `@maskito/core` <br /> It is the main zero-dependency and framework-agnostic package. It can be used alone in Vanilla
JavaScript project. It listens `beforeinput` and `input` events to validate and calibrate textfield's value. <br />
Read more: https://maskito.dev/core-concepts/overview
- `@maskito/kit` <br /> The optional framework-agnostic package. It contains ready-to-use masks with configurable
parameters. This release introduces the following masks:
- [Number](https://maskito.dev/kit/number)
- [Time](https://maskito.dev/kit/time)
- [Date](https://maskito.dev/kit/date)
- [DateRange](https://maskito.dev/kit/date-range)
- `@maskito/angular`<br /> The Angular-specific library. It provides two convenient ways of using Maskito:
- Basic directive approach (when developer has direct access to native input element).
- Dependency Injection approach (when native input element is hidden somewhere deep inside another component).
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2024 Acpekt
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Maskito
[](https://npmjs.com/package/@maskito/core)
[](https://github.com/taiga-family/maskito/actions/workflows/build.yml)
<p align="center">
<img src="projects/demo/src/assets/icons/maskito.svg" alt="Maskito logo" width="120px">
</p>
<p align="center">
<a href="https://maskito.dev">Documentation</a> •
<a href="https://github.com/taiga-family/maskito/issues/new/choose">Submit an Issue</a> •
<a href="https://t.me/taiga_ui/10600">Contact Us</a>
</p>
**Maskito** is a collection of libraries, built with TypeScript. It helps you to create an input mask which ensures that
users type values according to predefined format.
## Why Maskito
- **Maskito** supports all user’s interactions with text fields: basic typing and deleting via keyboard, pasting,
dropping text inside with a pointer, browser autofill, predictive text from mobile native keyboard.
- **Maskito** is robust. The whole project is developed with strict TypeScript mode. Our code is covered by hundreds of
[Cypress](https://www.cypress.io) tests.
- Server Side Rendering and Shadow DOM support.
- You can use it with `HTMLInputElement` or `HTMLTextAreaElement` or even with `[contenteditable]` element.
- **Maskito** core is zero-dependency package. You can mask input in your vanilla JavaScript project. However, we have
separate packages for Angular, React and Vue as well.
- **Maskito** includes optional framework-agnostic package with configurable ready-to-use masks.
No text field with invalid value! Use Maskito. **Mask it!** Learn more about the library in our
[documentation](https://maskito.dev).
## Contributing
If you have suggestions for how **Maskito** could be improved, or want to report a bug, open an issue! We'd love all and
any contributions.
For more, check out the [Contributing Guide](CONTRIBUTING.md).
## Maintained
Maskito is a part of [Taiga UI](https://github.com/taiga-family/taiga-ui) libraries family which is backed and used by a
large enterprise. This means you can rely on timely support and continuous development.
| **Package** | **Downloads** |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [@maskito/core](https://npmjs.com/package/@maskito/core) | [](https://npmjs.com/package/@maskito/core) |
| [@maskito/kit](https://npmjs.com/package/@maskito/kit) | [](https://npmjs.com/package/@maskito/kit) |
| [@maskito/react](https://npmjs.com/package/@maskito/react) | [](https://npmjs.com/package/@maskito/react) |
| [@maskito/angular](https://npmjs.com/package/@maskito/angular) | [](https://npmjs.com/package/@maskito/angular) |
| [@maskito/vue](https://npmjs.com/package/@maskito/vue) | [](https://npmjs.com/package/@maskito/vue) |
| [@maskito/phone](https://npmjs.com/package/@maskito/phone) | [](https://npmjs.com/package/@maskito/phone) |
## License
🆓 Feel free to use our library in your commercial and private applications
All **Maskito** packages are covered by [Apache 2.0](/LICENSE)
Read more about this license [here](https://choosealicense.com/licenses/apache-2.0/)
================================================
FILE: codecov.yml
================================================
codecov:
branch: main
notify:
require_ci_to_pass: no
coverage:
# This value is used to customize the visible color range in Codecov.
# The first number represents the red, and the second represents green.
# You can change the range of colors by adjusting this configuration.
range: 50..100 # by default 70..100
round: down
precision: 2
# Disable codecov/patch check
status:
project:
default:
enabled: false
patch:
default:
enabled: false
================================================
FILE: eslint.config.ts
================================================
import taiga from '@taiga-ui/eslint-plugin-experience-next';
export default [
...taiga.configs.recommended,
{
files: ['*.tsx'],
rules: {
'react/display-name': 'off',
'react/react-in-jsx-scope': 'off',
'no-irregular-whitespace': 'off',
},
},
{
files: ['*.spec.tsx'],
rules: {
'jest/prefer-ending-with-an-expect': [
'error',
{assertFunctionNames: ['expect', 'check']},
],
},
},
// TODO: fix later
{
files: ['**/*'],
rules: {
'@typescript-eslint/no-unused-private-class-members': 'off',
'@typescript-eslint/prefer-function-type': 'off',
'@typescript-eslint/no-restricted-types': 'off',
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
'@angular-eslint/template/alt-text': 'off',
'@angular-eslint/prefer-signals': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'no-irregular-whitespace': 'off',
'de-morgan/no-negated-disjunction': 'off',
'@angular-eslint/template/no-interpolation-in-attributes': 'off',
'@typescript-eslint/no-invalid-this': 'off',
'@angular-eslint/consistent-component-styles': 'off',
'@typescript-eslint/no-useless-default-assignment': 'off',
'import/consistent-type-specifier-style': 'off',
'@typescript-eslint/no-unnecessary-type-conversion': 'off',
'@typescript-eslint/consistent-type-exports': 'off',
'@typescript-eslint/method-signature-style': 'off',
'@typescript-eslint/strict-void-return': 'off',
},
},
];
================================================
FILE: firebase.json
================================================
{
"hosting": {
"public": "dist/demo/browser",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
================================================
FILE: jest.config.ts
================================================
import {getJestProjectsAsync} from '@nx/jest';
import type {Config} from 'jest';
export default async (): Promise<Config> => ({projects: await getJestProjectsAsync()});
================================================
FILE: jest.preset.js
================================================
const nxPreset = require('@nx/jest/preset').default;
const {resolve} = require('node:path');
module.exports = {
...nxPreset,
transform: {
'^.+\\.(ts|tsx|js|jsx|mjs|html|svg)$': [
'jest-preset-angular',
{
diagnostics: true,
stringifyContentPathRegex: String.raw`\.html$`,
tsconfig: resolve(__dirname, 'tsconfig.spec.json'),
},
],
},
};
================================================
FILE: nx.json
================================================
{
"tui": {
"enabled": false
},
"workspaceLayout": {
"libsDir": "projects",
"appsDir": "projects"
},
"defaultProject": "demo",
"generators": {
"@nx/js:library": {
"buildable": true,
"publishable": true,
"strict": true,
"linter": "none",
"unitTestRunner": "jest",
"config": "project"
},
"@nx/angular:library": {
"linter": "none",
"unitTestRunner": "jest",
"buildable": true,
"publishable": true,
"compilationMode": "partial",
"strict": true,
"skipModule": true,
"standaloneConfig": true
},
"@nx/angular:application": {
"style": "less",
"linter": "none",
"unitTestRunner": "jest"
},
"@nx/angular:component": {
"style": "less"
},
"@nx/react": {
"application": {
"babel": true
},
"library": {
"linter": "eslint",
"publishable": true,
"bundler": "rollup",
"style": "none",
"strict": true,
"unitTestRunner": "jest"
}
}
},
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"sharedGlobals": [
"{workspaceRoot}/angular.json",
"{workspaceRoot}/nx.json",
"{workspaceRoot}/karma.*.js",
"{workspaceRoot}/tsconfig.*.json",
"{workspaceRoot}/tsconfig.json",
"{workspaceRoot}/babel.config.json"
],
"production": [
"default",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/src/test-setup.[jt]s",
"!{projectRoot}/**/*.cy.[jt]s?(x)",
"!{projectRoot}/cypress.config.[jt]s"
]
},
"targetDefaults": {
"build": {
"inputs": ["production", "^production"],
"cache": true
},
"lint": {
"cache": true
},
"@nx/jest:jest": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
"cache": true,
"options": {
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"component-test": {
"cache": true,
"inputs": ["default", "^production"]
},
"ct-react": {
"cache": true,
"inputs": ["default", "^production"]
}
},
"parallel": 3,
"useInferencePlugins": false,
"defaultBase": "origin/main"
}
================================================
FILE: package.json
================================================
{
"name": "maskito",
"version": "5.2.2",
"description": "Collection of libraries to create an input mask which ensures that user types value according to predefined format",
"homepage": "https://maskito.dev",
"bugs": "https://github.com/taiga-family/maskito/issues",
"repository": {
"type": "git",
"url": "https://github.com/taiga-family/maskito.git"
},
"license": "Apache-2.0",
"author": {
"email": "nikita.s.barsukov@gmail.com",
"name": "Nikita Barsukov",
"url": "https://github.com/nsbarsukov"
},
"contributors": [
{
"email": "alexander@inkin.ru",
"name": "Alex Inkin"
},
{
"email": "vladimir.potekh@gmail.com",
"name": "Vladimir Potekhin"
},
{
"email": "nikita.s.barsukov@gmail.com",
"name": "Nikita Barsukov"
},
{
"email": "nextzeddicus@gmail.com",
"name": "Georgiy Lunin"
}
],
"workspaces": [
"projects/*"
],
"scripts": {
"build": "nx run demo:build:production",
"cspell": "cspell --relative --dot --gitignore .",
"cy:open": "cypress open --project ./projects/demo-integrations/",
"cy:run": "nx e2e demo-integrations && nx component-test demo-integrations && nx ct-react demo-integrations",
"lint": "eslint .",
"prepare": "husky",
"prettier": "prettier !package-lock.json . --ignore-path .gitignore",
"release": "npx nx run-many --target publish --all",
"release:local": "npx release-it --no-git.push --'hooks.before:release=\"echo Skip publish\"'",
"serve:ssr": "node dist/demo/server/server.mjs",
"start": "nx run demo:serve",
"stylelint": "stylelint '**/*.{less,css}'",
"test": "nx run-many --target test --all",
"typecheck": "tsc --noEmit --skipLibCheck --incremental false --tsBuildInfoFile null --project tsconfig.spec.json && tsc -p projects/demo-integrations/tsconfig.json"
},
"commitlint": {
"extends": [
"@taiga-ui/commitlint-config"
]
},
"lint-staged": {
"*.less": [
"stylelint --fix"
],
"*.{js,ts,html,md,less,json,svg,yml}": [
"npm run lint -- --fix",
"prettier --write"
]
},
"browserslist": [
"extends @taiga-ui/browserslist-config"
],
"prettier": "@taiga-ui/prettier-config",
"stylelint": {
"extends": [
"@taiga-ui/stylelint-config"
],
"ignoreFiles": [
"**/dist/**",
"**/coverage/**",
"**/node_modules/**"
]
},
"overrides": {
"@taiga-ui/addon-commerce": {
"@maskito/angular": ">=4.0.0",
"@maskito/core": ">=4.0.0",
"@maskito/kit": ">=4.0.0",
"@maskito/phone": ">=4.0.0"
},
"@taiga-ui/kit": {
"@maskito/angular": ">=4.0.0",
"@maskito/core": ">=4.0.0",
"@maskito/kit": ">=4.0.0",
"@maskito/phone": ">=4.0.0"
}
},
"devDependencies": {
"@angular-devkit/build-angular": "19.2.22",
"@angular-devkit/core": "19.2.22",
"@angular-devkit/schematics": "19.2.22",
"@angular/build": "19.2.22",
"@angular/cli": "19.2.22",
"@angular/compiler-cli": "19.2.20",
"@angular/core": "19.2.20",
"@angular/platform-browser-dynamic": "19.2.20",
"@nx/angular": "21.6.3",
"@nx/eslint": "21.6.3",
"@nx/jest": "21.6.3",
"@nx/js": "21.6.3",
"@nx/module-federation": "21.6.3",
"@nx/react": "21.6.3",
"@nx/rollup": "21.6.3",
"@nx/workspace": "21.6.3",
"@taiga-ui/configs": "0.476.0",
"@tinkoff/eslint-config": "5.2.0",
"@tinkoff/eslint-config-react": "5.2.0",
"@types/highlight.js": "10.1.0",
"@types/node": "24.10.11",
"http-server": "14.1.1",
"husky": "9.1.7",
"ng-packagr": "19.2.2",
"nx": "21.6.3",
"postcss-preset-env": "10.6.1",
"ts-node": "10.9.2",
"tsutils": "3.21.0",
"typescript": "5.8.3"
},
"engines": {
"node": ">= 24",
"npm": ">= 11",
"yarn": "Please use npm instead of yarn to install dependencies"
},
"auto-changelog": {
"prepend": true,
"template": "templates/note.hbs"
},
"syncer": {
"includePaths": [
"./projects",
"./package-lock.json"
],
"matchPackageNames": [
"@maskito/*",
"maskito"
]
}
}
================================================
FILE: projects/angular/README.md
================================================
# @maskito/angular
[](https://npmjs.com/package/@maskito/angular)
[](https://bundlephobia.com/result?p=@maskito/angular)
<p align="center">
<img src="https://raw.githubusercontent.com/taiga-family/maskito/main/projects/demo/src/assets/icons/maskito.svg" alt="Maskito logo" width="120px">
</p>
<p align="center">
<a href="https://maskito.dev/frameworks/angular">Documentation</a> •
<a href="https://github.com/taiga-family/maskito/issues/new/choose">Submit an Issue</a> •
<a href="https://t.me/taiga_ui/10600">Contact Us</a>
</p>
> The Angular-specific library.<br /> It provides a convenient way to use Maskito as a directive.
## How to install
```bash
npm i @maskito/{core,angular}
```
================================================
FILE: projects/angular/jest.config.ts
================================================
export default {
displayName: 'angular',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: '../../coverage/angular',
transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};
================================================
FILE: projects/angular/ng-package.json
================================================
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/angular",
"lib": {
"entryFile": "src/index.ts"
}
}
================================================
FILE: projects/angular/package.json
================================================
{
"name": "@maskito/angular",
"version": "5.2.2",
"description": "The Angular-specific Maskito's library",
"keywords": [
"input",
"mask",
"inputmask",
"input-mask",
"text-mask",
"format",
"input-format",
"input-formatting",
"angular"
],
"homepage": "https://maskito.dev",
"bugs": "https://github.com/taiga-family/maskito/issues",
"repository": {
"type": "git",
"url": "https://github.com/taiga-family/maskito.git"
},
"license": "Apache-2.0",
"author": {
"email": "nikita.s.barsukov@gmail.com",
"name": "Nikita Barsukov",
"url": "https://github.com/nsbarsukov"
},
"contributors": [
{
"email": "alexander@inkin.ru",
"name": "Alex Inkin"
},
{
"email": "vladimir.potekh@gmail.com",
"name": "Vladimir Potekhin"
},
{
"email": "nikita.s.barsukov@gmail.com",
"name": "Nikita Barsukov"
},
{
"email": "nextzeddicus@gmail.com",
"name": "Georgiy Lunin"
}
],
"dependencies": {
"tslib": "2.8.1"
},
"devDependencies": {
"@angular/core": "19.2.20",
"@angular/forms": "19.2.20"
},
"peerDependencies": {
"@angular/core": ">=19.0.0",
"@angular/forms": ">=19.0.0",
"@maskito/core": "^5.2.2"
},
"ng-update": {
"packageGroup": [
"@maskito/core",
"@maskito/kit"
]
}
}
================================================
FILE: projects/angular/project.json
================================================
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "angular",
"prefix": "maskito",
"projectType": "library",
"sourceRoot": "projects/angular/src",
"tags": [],
"targets": {
"build": {
"configurations": {
"development": {},
"production": {
"tsConfig": "{projectRoot}/tsconfig.lib.prod.json"
}
},
"defaultConfiguration": "production",
"dependsOn": [
{
"dependencies": true,
"params": "forward",
"target": "build"
}
],
"executor": "@nx/angular:package",
"options": {
"project": "{projectRoot}/ng-package.json",
"tsConfig": "tsconfig.build.json"
},
"outputs": ["{workspaceRoot}/dist/{projectName}"]
},
"publish": {
"dependsOn": [
{
"params": "ignore",
"target": "build"
}
],
"executor": "nx:run-commands",
"options": {
"command": "npm publish ./dist/{projectName} --ignore-scripts"
}
},
"test": {
"executor": "@nx/jest:jest",
"options": {
"jestConfig": "{projectRoot}/jest.config.ts"
},
"outputs": ["{workspaceRoot}/coverage/{projectName}"]
}
}
}
================================================
FILE: projects/angular/src/index.ts
================================================
export * from './lib/maskito.directive';
export * from './lib/maskito.pipe';
export * from './lib/pattern.directive';
================================================
FILE: projects/angular/src/lib/maskito.directive.ts
================================================
import {
Directive,
effect,
ElementRef,
inject,
model,
NgZone,
type OnDestroy,
untracked,
} from '@angular/core';
import {DefaultValueAccessor} from '@angular/forms';
import {
Maskito,
MASKITO_DEFAULT_ELEMENT_PREDICATE,
type MaskitoOptions,
maskitoTransform,
} from '@maskito/core';
@Directive({selector: '[maskito]'})
export class MaskitoDirective implements OnDestroy {
private readonly elementRef: HTMLElement = inject(ElementRef).nativeElement;
private readonly ngZone = inject(NgZone);
private maskedElement: Maskito | null = null;
protected readonly initEffect = effect(async () => {
const options = this.options();
const elementPredicate = this.elementPredicate();
const {elementRef, ngZone} = this;
this.destroy();
if (!options) {
return;
}
const predicateResult = await elementPredicate(elementRef);
if (
untracked(this.elementPredicate) !== elementPredicate ||
untracked(this.options) !== options
) {
// Ignore the result of the predicate if the
// maskito element (or its options) has changed before the predicate was resolved.
return;
}
ngZone.runOutsideAngular(() => {
this.maskedElement = new Maskito(predicateResult, options);
});
});
public readonly options = model<MaskitoOptions | null>(null, {alias: 'maskito'});
public readonly elementPredicate = model(MASKITO_DEFAULT_ELEMENT_PREDICATE, {
alias: 'maskitoElement',
});
constructor() {
const accessor = inject(DefaultValueAccessor, {self: true, optional: true});
if (accessor) {
const original = accessor.writeValue.bind(accessor);
accessor.writeValue = (value: unknown) => {
const options = untracked(this.options);
original(
options ? maskitoTransform(String(value ?? ''), options) : value,
);
};
}
}
public ngOnDestroy(): void {
this.destroy();
}
private destroy(): void {
this.maskedElement?.destroy();
this.maskedElement = null;
}
}
================================================
FILE: projects/angular/src/lib/maskito.pipe.ts
================================================
import {Pipe, type PipeTransform} from '@angular/core';
import {
MASKITO_DEFAULT_OPTIONS,
type MaskitoOptions,
maskitoTransform,
} from '@maskito/core';
@Pipe({name: 'maskito'})
export class MaskitoPipe implements PipeTransform {
public transform(value: unknown, maskitoOptions: MaskitoOptions | null): string {
return maskitoTransform(
String(value ?? ''),
maskitoOptions ?? MASKITO_DEFAULT_OPTIONS,
);
}
}
================================================
FILE: projects/angular/src/lib/pattern.directive.ts
================================================
import {Directive, inject} from '@angular/core';
import {MaskitoDirective} from './maskito.directive';
@Directive({
selector: '[maskitoPattern]',
inputs: ['maskitoPattern'],
hostDirectives: [MaskitoDirective],
})
export class MaskitoPattern {
private readonly maskitoDirective = inject(MaskitoDirective, {self: true});
public set maskitoPattern(pattern: RegExp | string) {
this.maskitoDirective.options.set({
mask: typeof pattern === 'string' ? new RegExp(`^${pattern}$`) : pattern,
});
}
}
================================================
FILE: projects/angular/src/lib/tests/maskito.directive.spec.ts
================================================
import {ChangeDetectionStrategy, Component, signal} from '@angular/core';
import {type ComponentFixture, TestBed} from '@angular/core/testing';
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals';
import {MaskitoDirective} from '@maskito/angular';
import {
Maskito,
MASKITO_DEFAULT_ELEMENT_PREDICATE,
type MaskitoElementPredicate,
type MaskitoOptions,
} from '@maskito/core';
const DIGIT_ONLY: MaskitoOptions = {mask: /^\d*$/};
describe('MaskitoDirective — initEffect', () => {
@Component({
imports: [MaskitoDirective],
template: `
<input
[maskito]="options()"
[maskitoElement]="predicate()"
/>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestHostComponent {
public readonly options = signal<MaskitoOptions | null>(null);
public readonly predicate = signal(MASKITO_DEFAULT_ELEMENT_PREDICATE);
}
let fixture: ComponentFixture<TestHostComponent>;
let destroySpy: ReturnType<typeof jest.spyOn>;
function getDirective(): MaskitoDirective {
return fixture.debugElement.children[0]!.injector.get(MaskitoDirective);
}
function getMaskedElement(): Maskito | null {
return (getDirective() as unknown as {maskedElement: Maskito | null})
.maskedElement;
}
beforeEach(() => {
TestBed.configureTestingModule({imports: [TestHostComponent]});
destroySpy = jest.spyOn(Maskito.prototype, 'destroy');
fixture = TestBed.createComponent(TestHostComponent);
fixture.detectChanges();
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('when options is null', () => {
it('does not create a Maskito instance', async () => {
await fixture.whenStable();
expect(getMaskedElement()).toBeNull();
});
});
describe('when options are provided', () => {
beforeEach(async () => {
fixture.componentInstance.options.set(DIGIT_ONLY);
fixture.detectChanges();
await fixture.whenStable();
});
it('creates a Maskito instance', () => {
expect(getMaskedElement()).toBeInstanceOf(Maskito);
});
it('destroys the old instance and creates a new one when options change', async () => {
fixture.componentInstance.options.set({mask: /^[a-z]*$/});
fixture.detectChanges();
await fixture.whenStable();
expect(destroySpy).toHaveBeenCalledTimes(1);
expect(getMaskedElement()).toBeInstanceOf(Maskito);
});
it('destroys the instance when options become null', async () => {
fixture.componentInstance.options.set(null);
fixture.detectChanges();
await fixture.whenStable();
expect(destroySpy).toHaveBeenCalledTimes(1);
expect(getMaskedElement()).toBeNull();
});
it('destroys the instance when the directive is destroyed', () => {
const directive = getDirective() as unknown as {
maskedElement: Maskito | null;
};
fixture.destroy();
expect(destroySpy).toHaveBeenCalledTimes(1);
expect(directive.maskedElement).toBeNull();
});
});
describe('stale async predicate', () => {
function makeControlledPredicate(): {
predicate: MaskitoElementPredicate;
resolveCall: (index: number) => void;
} {
const resolvers: Array<() => void> = [];
const predicate: MaskitoElementPredicate = async (el) =>
new Promise<HTMLInputElement>((resolve) => {
resolvers.push(() => resolve(el as HTMLInputElement));
});
return {predicate, resolveCall: (i) => resolvers[i]!()};
}
it('ignores the result when elementPredicate changes before it resolves', async () => {
const {predicate: slowPredicate, resolveCall} = makeControlledPredicate();
fixture.componentInstance.options.set(DIGIT_ONLY);
fixture.componentInstance.predicate.set(slowPredicate);
fixture.detectChanges();
await fixture.whenStable();
expect(getMaskedElement()).toBeNull();
fixture.componentInstance.predicate.set(MASKITO_DEFAULT_ELEMENT_PREDICATE);
fixture.detectChanges();
await fixture.whenStable();
expect(getMaskedElement()).toBeInstanceOf(Maskito);
expect(destroySpy).not.toHaveBeenCalled();
resolveCall(0);
await fixture.whenStable();
expect(destroySpy).not.toHaveBeenCalled();
expect(getMaskedElement()).toBeInstanceOf(Maskito);
});
it('ignores the result when options change before the predicate resolves', async () => {
const {predicate: slowPredicate, resolveCall} = makeControlledPredicate();
fixture.componentInstance.options.set(DIGIT_ONLY);
fixture.componentInstance.predicate.set(slowPredicate);
fixture.detectChanges();
await fixture.whenStable();
expect(getMaskedElement()).toBeNull();
fixture.componentInstance.options.set({mask: /^[a-z]*$/});
fixture.detectChanges();
await fixture.whenStable();
resolveCall(0);
await fixture.whenStable();
expect(destroySpy).not.toHaveBeenCalled();
expect(getMaskedElement()).toBeNull();
});
});
});
================================================
FILE: projects/angular/src/lib/tests/maskito.spec.ts
================================================
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {type ComponentFixture, TestBed} from '@angular/core/testing';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {beforeEach, describe, expect, it} from '@jest/globals';
import {MaskitoDirective, MaskitoPipe} from '@maskito/angular';
import type {MaskitoOptions} from '@maskito/core';
describe('Maskito Angular package', () => {
@Component({
imports: [MaskitoDirective, MaskitoPipe, ReactiveFormsModule],
template: `
<div id="pipe">{{ control.value | maskito: options }}</div>
<input
id="input"
[formControl]="control"
[maskito]="options"
/>
`,
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
changeDetection: ChangeDetectionStrategy.Default,
})
class TestComponent {
public readonly control = new FormControl();
public options: MaskitoOptions | null = {
mask: /^\d+(,\d{0,2})?$/,
preprocessors: [
({elementState, data}) => {
const {value, selection} = elementState;
return {
elementState: {
selection,
value: value.replace('.', ','),
},
data: data.replace('.', ','),
};
},
],
};
}
let fixture: ComponentFixture<TestComponent>;
beforeEach(() => {
TestBed.configureTestingModule({imports: [TestComponent]});
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
});
it('null is treated as empty string', () => {
expect(getText()).toBe('');
expect(getValue()).toBe('');
});
it('formats new control value', () => {
fixture.componentInstance.control.setValue(12345.6789);
fixture.detectChanges();
expect(getText()).toBe('12345,67');
expect(getValue()).toBe('12345,67');
});
it('disable mask formatting if options is null', () => {
fixture.componentInstance.options = null;
fixture.detectChanges();
fixture.componentInstance.control.setValue(123456.9999);
fixture.detectChanges();
expect(getText()).toBe('123456.9999');
expect(getValue()).toBe('123456.9999');
});
function getText(): string {
return fixture.debugElement.nativeElement
.querySelector('#pipe')
.textContent.trim();
}
function getValue(): string {
return fixture.debugElement.nativeElement.querySelector('#input').value;
}
});
================================================
FILE: projects/angular/src/test-setup.ts
================================================
import {setupZoneTestEnv} from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
================================================
FILE: projects/angular/tsconfig.lib.prod.json
================================================
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"declarationMap": false
}
}
================================================
FILE: projects/core/README.md
================================================
# @maskito/core
[](https://npmjs.com/package/@maskito/core)
[](https://bundlephobia.com/result?p=@maskito/core)
<p align="center">
<img src="https://raw.githubusercontent.com/taiga-family/maskito/main/projects/demo/src/assets/icons/maskito.svg" alt="Maskito logo" width="120px">
</p>
<p align="center">
<a href="https://maskito.dev">Documentation</a> •
<a href="https://github.com/taiga-family/maskito/issues/new/choose">Submit an Issue</a> •
<a href="https://t.me/taiga_ui/10600">Contact Us</a>
</p>
> It is the main zero-dependency and framework-agnostic Maskito's package.<br />It can be used alone in
> vanilla JavaScript project.
## How to install
```bash
npm i @maskito/core
```
================================================
FILE: projects/core/jest.config.ts
================================================
export default {
displayName: 'core',
preset: '../../jest.preset.js',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/core',
};
================================================
FILE: projects/core/package.json
================================================
{
"name": "@maskito/core",
"version": "5.2.2",
"description": "The main zero-dependency and framework-agnostic Maskito's package to create an input mask",
"keywords": [
"input",
"mask",
"inputmask",
"input-mask",
"text-mask",
"format",
"input-format",
"input-formatting",
"javascript",
"typescript"
],
"homepage": "https://maskito.dev",
"bugs": "https://github.com/taiga-family/maskito/issues",
"repository": {
"type": "git",
"url": "https://github.com/taiga-family/maskito.git"
},
"license": "Apache-2.0",
"author": {
"email": "nikita.s.barsukov@gmail.com",
"name": "Nikita Barsukov",
"url": "https://github.com/nsbarsukov"
},
"contributors": [
{
"email": "alexander@inkin.ru",
"name": "Alex Inkin"
},
{
"email": "vladimir.potekh@gmail.com",
"name": "Vladimir Potekhin"
},
{
"email": "nikita.s.barsukov@gmail.com",
"name": "Nikita Barsukov"
},
{
"email": "nextzeddicus@gmail.com",
"name": "Georgiy Lunin"
}
]
}
================================================
FILE: projects/core/project.json
================================================
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "core",
"projectType": "library",
"sourceRoot": "projects/core/src",
"tags": [],
"targets": {
"build": {
"executor": "@nx/rollup:rollup",
"options": {
"assets": [
{
"glob": "README.md",
"input": "{projectRoot}",
"output": "."
}
],
"compiler": "tsc",
"external": "all",
"format": ["esm", "cjs"],
"main": "{projectRoot}/src/index.ts",
"outputPath": "dist/{projectName}",
"project": "{projectRoot}/package.json",
"tsConfig": "tsconfig.build.json",
"useLegacyTypescriptPlugin": false
},
"outputs": ["{options.outputPath}"]
},
"publish": {
"dependsOn": [
{
"params": "ignore",
"target": "build"
}
],
"executor": "nx:run-commands",
"options": {
"command": "npm publish ./dist/{projectName} --ignore-scripts"
}
},
"test": {
"executor": "@nx/jest:jest",
"options": {
"jestConfig": "{projectRoot}/jest.config.ts"
},
"outputs": ["{workspaceRoot}/coverage/{projectName}"]
}
}
}
================================================
FILE: projects/core/src/index.ts
================================================
export {
MASKITO_DEFAULT_ELEMENT_PREDICATE,
MASKITO_DEFAULT_OPTIONS,
} from './lib/constants';
export {Maskito} from './lib/mask';
export {
maskitoChangeEventPlugin,
maskitoInitialCalibrationPlugin,
maskitoStrictCompositionPlugin,
} from './lib/plugins';
export type {
MaskitoElement,
MaskitoElementPredicate,
MaskitoMask,
MaskitoMaskExpression,
MaskitoOptions,
MaskitoPlugin,
MaskitoPostprocessor,
MaskitoPreprocessor,
} from './lib/types';
export {
maskitoAdaptContentEditable,
maskitoPipe,
maskitoTransform,
maskitoUpdateElement,
} from './lib/utils';
================================================
FILE: projects/core/src/lib/classes/index.ts
================================================
export {MaskHistory} from './mask-history';
export {MaskModel} from './mask-model/mask-model';
================================================
FILE: projects/core/src/lib/classes/mask-history.ts
================================================
import type {ElementState, TypedInputEvent} from '../types';
export abstract class MaskHistory {
private now: ElementState | null = null;
private readonly past: ElementState[] = [];
private future: ElementState[] = [];
protected abstract updateElementState(
state: ElementState,
eventInit: Pick<TypedInputEvent, 'data' | 'inputType'>,
): void;
protected undo(): void {
const state = this.past.pop();
if (state && this.now) {
this.future.push(this.now);
this.updateElement(state, 'historyUndo');
}
}
protected redo(): void {
const state = this.future.pop();
if (state && this.now) {
this.past.push(this.now);
this.updateElement(state, 'historyRedo');
}
}
protected updateHistory(state: ElementState): void {
if (!this.now) {
this.now = state;
return;
}
const isValueChanged = this.now.value !== state.value;
const isSelectionChanged = this.now.selection.some(
(item, index) => item !== state.selection[index],
);
if (!isValueChanged && !isSelectionChanged) {
return;
}
if (isValueChanged) {
this.past.push(this.now);
this.future = [];
}
this.now = state;
}
private updateElement(
state: ElementState,
inputType: TypedInputEvent['inputType'],
): void {
this.now = state;
this.updateElementState(state, {inputType, data: null});
}
}
================================================
FILE: projects/core/src/lib/classes/mask-model/mask-model.ts
================================================
import type {
ElementState,
MaskitoMaskExpression,
MaskitoOptions,
SelectionRange,
} from '../../types';
import {areElementStatesEqual} from '../../utils/element-states-equality';
import {applyOverwriteMode} from './utils/apply-overwrite-mode';
import {calibrateValueByMask} from './utils/calibrate-value-by-mask';
import {removeFixedMaskCharacters} from './utils/remove-fixed-mask-characters';
export class MaskModel implements ElementState {
private readonly unmaskInitialState: ElementState = {value: '', selection: [0, 0]};
public value = '';
public selection: SelectionRange = [0, 0];
constructor(
initialElementState: ElementState,
private readonly maskOptions: Required<MaskitoOptions>,
) {
const expression = this.getMaskExpression(initialElementState);
const {value, selection} = calibrateValueByMask(initialElementState, expression);
this.unmaskInitialState = removeFixedMaskCharacters(
{value, selection},
expression,
);
this.value = value;
this.selection = selection;
}
public addCharacters(newCharacters: string): void {
const {value, selection, maskOptions} = this;
const initialElementState = {value, selection} as const;
const {
selection: [from, to],
} = applyOverwriteMode(
initialElementState,
newCharacters,
maskOptions.overwriteMode,
);
const maskExpression = this.getMaskExpression({
value: `${value.slice(0, from)}${newCharacters}${value.slice(to)}`,
selection: [from + newCharacters.length, from + newCharacters.length],
});
const [unmaskedFrom, unmaskedTo] = applyOverwriteMode(
this.unmaskInitialState,
newCharacters,
maskOptions.overwriteMode,
).selection;
const newUnmaskedLeadingValuePart = `${this.unmaskInitialState.value.slice(0, unmaskedFrom)}${newCharacters}`;
const newCaretIndex = newUnmaskedLeadingValuePart.length;
const maskedElementState = calibrateValueByMask(
{
value: `${newUnmaskedLeadingValuePart}${this.unmaskInitialState.value.slice(unmaskedTo)}`,
selection: [newCaretIndex, newCaretIndex],
},
maskExpression,
initialElementState,
);
const prevLeadingPart = value.slice(0, from);
const newLeadingPartState = calibrateValueByMask(
{
value: newUnmaskedLeadingValuePart,
selection: [newCaretIndex, newCaretIndex],
},
maskExpression,
initialElementState,
);
const isInvalidCharsInsertion =
newLeadingPartState.value === prevLeadingPart ||
(newLeadingPartState.value.length < prevLeadingPart.length &&
removeFixedMaskCharacters(newLeadingPartState, maskExpression).value ===
this.unmaskInitialState.value.slice(0, unmaskedFrom));
if (
isInvalidCharsInsertion ||
areElementStatesEqual(this, maskedElementState) // If typing new characters does not change value
) {
throw new Error('Invalid mask value');
}
this.value = maskedElementState.value;
this.selection = maskedElementState.selection;
}
public deleteCharacters(): void {
const [from, to] = this.selection;
if (from === to || !to) {
return;
}
const {value} = this;
const maskExpression = this.getMaskExpression({
value: `${value.slice(0, from)}${value.slice(to)}`,
selection: [from, from],
});
const initialElementState = {value, selection: [from, to]} as const;
const [unmaskedFrom, unmaskedTo] = this.unmaskInitialState.selection;
const newUnmaskedValue = `${this.unmaskInitialState.value.slice(0, unmaskedFrom)}${this.unmaskInitialState.value.slice(unmaskedTo)}`;
const maskedElementState = calibrateValueByMask(
{value: newUnmaskedValue, selection: [unmaskedFrom, unmaskedFrom]},
maskExpression,
initialElementState,
);
this.value = maskedElementState.value;
this.selection = maskedElementState.selection;
}
private getMaskExpression(elementState: ElementState): MaskitoMaskExpression {
const {mask} = this.maskOptions;
return typeof mask === 'function' ? mask(elementState) : mask;
}
}
================================================
FILE: projects/core/src/lib/classes/mask-model/tests/dynamic-mask.spec.ts
================================================
import {describe, expect, it} from '@jest/globals';
import {MASKITO_DEFAULT_OPTIONS} from '@maskito/core';
import type {ElementState, MaskitoMask, MaskitoOptions} from '../../../types';
import {MaskModel} from '../mask-model';
const EMPTY_STATE: ElementState = {
selection: [0, 0],
value: '',
};
describe('MaskModel | Dynamic mask', () => {
describe('switching on the fly works', () => {
const SHORT: MaskitoMask = Array.from<RegExp>({length: 10}).fill(/\d/);
const MEDIUM: MaskitoMask = [
/\d/,
/\d/,
/\d/,
/\d/,
' ',
/\d/,
/\d/,
/\d/,
/\d/,
' ',
/\d/,
/\d/,
/\d/,
/\d/,
' ',
/\d/,
/\d/,
/\d/,
/\d/,
];
const LONG: MaskitoMask = Array.from<RegExp>({length: 20}).fill(/\d/);
const maskitoOptions: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
mask: ({value}) => {
const digitsCount = value.replaceAll(/\D/g, '').length;
if (digitsCount <= 10) {
return SHORT;
}
if (digitsCount <= 16) {
return MEDIUM;
}
return LONG;
},
};
it('enable short mask if number of digits is <=10', () => {
const maskModel = new MaskModel(EMPTY_STATE, maskitoOptions);
maskModel.addCharacters('01234abc56789');
expect(maskModel.value).toBe('0123456789');
expect(maskModel.selection).toEqual([
'0123456789'.length,
'0123456789'.length,
]);
});
it('enable medium mask if number of digits is 10 < x <= 16', () => {
const maskModel = new MaskModel(EMPTY_STATE, maskitoOptions);
maskModel.addCharacters('01234abc56789123456');
expect(maskModel.value).toBe('0123 4567 8912 3456');
expect(maskModel.selection).toEqual([
'0123 4567 8912 3456'.length,
'0123 4567 8912 3456'.length,
]);
});
it('enable long mask if number of digits is >16 (by paste)', () => {
const maskModel = new MaskModel(EMPTY_STATE, maskitoOptions);
maskModel.addCharacters('01234abc567891234567');
expect(maskModel.value).toBe('01234567891234567');
expect(maskModel.selection).toEqual([
'01234567891234567'.length,
'01234567891234567'.length,
]);
});
it('enable long mask if number of digits is >16 (by adding new character to the previous mask)', () => {
const initialValue = '0123 4567 8912 3456';
const maskModel = new MaskModel(
{
value: initialValue,
selection: [initialValue.length, initialValue.length],
},
maskitoOptions,
);
maskModel.addCharacters('7');
expect(maskModel.value).toBe('01234567891234567');
expect(maskModel.selection).toEqual([
'01234567891234567'.length,
'01234567891234567'.length,
]);
});
});
});
================================================
FILE: projects/core/src/lib/classes/mask-model/tests/mask-model-fixed-characters.spec.ts
================================================
import {describe, expect, it} from '@jest/globals';
import {MASKITO_DEFAULT_OPTIONS} from '../../../constants';
import type {MaskitoMask, MaskitoOptions} from '../../../types';
import {MaskModel} from '../mask-model';
describe('MaskModel | Fixed characters', () => {
describe('New typed character is equal to the previous (already existing) fixed character', () => {
const phoneMaskitoOptions: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
mask: [
'+',
'7',
' ',
'(',
/\d/,
/\d/,
/\d/,
')',
' ',
/\d/,
'0',
/\d/,
'-',
/\d/,
/\d/,
'-',
/\d/,
/\d/,
],
};
const check = ({
initialValue,
addedCharacters,
expectedNewValue,
}: {
initialValue: string;
addedCharacters: string;
expectedNewValue: string;
}): void => {
const selection: [number, number] = [
initialValue.length,
initialValue.length,
];
const maskModel = new MaskModel(
{
selection,
value: initialValue,
},
phoneMaskitoOptions,
);
try {
maskModel.addCharacters(addedCharacters);
} finally {
expect(maskModel.value).toBe(expectedNewValue);
expect(maskModel.selection).toEqual([
expectedNewValue.length,
expectedNewValue.length,
]);
}
};
it('+7| => Type 7 => +7 (7', () => {
check({
initialValue: '+7',
addedCharacters: '7',
expectedNewValue: '+7 (7',
});
});
it('+7| => Type 9 => +7 (9', () => {
check({
initialValue: '+7',
addedCharacters: '9',
expectedNewValue: '+7 (9',
});
});
it('+7 | (space after seven) => Type 7 => +7 (7', () => {
check({
initialValue: '+7 ',
addedCharacters: '7',
expectedNewValue: '+7 (7',
});
});
it('+7 (7| => Type 7 => +7 (77', () => {
check({
initialValue: '+7 (7',
addedCharacters: '7',
expectedNewValue: '+7 (77',
});
});
it('+7 (900) 2| (next character is fixed character "0") => Type 1 => +7 (900) 201|', () => {
check({
initialValue: '+7 (900) 2',
addedCharacters: '1',
expectedNewValue: '+7 (900) 201',
});
});
it('+7 (900) 20| => Type 0 => +7 (900) 200|', () => {
check({
initialValue: '+7 (900) 20',
addedCharacters: '0',
expectedNewValue: '+7 (900) 200',
});
});
});
describe('Attempt to insert invalid characters for `overwriteMode: replace`', () => {
const testCases: Record<string, MaskitoMask> = {
'["$", /d/, /d/]': ['$', /\d/, /\d/],
'dynamic mask': ({value}) => {
const digitsCount = value.replaceAll(/\D/g, '').length;
return [
'$',
...Array.from<RegExp>({length: digitsCount || 1}).fill(/\d/),
];
},
};
Object.entries(testCases).forEach(([title, mask]) => {
describe(`mask expression contains leading characters – ${title}`, () => {
const options: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
mask,
overwriteMode: 'replace',
};
it('$1|2 => Type A => $1|2', () => {
const value = '$12';
const selection = [2, 2] as const;
const maskModel = new MaskModel({value, selection}, options);
expect(() => maskModel.addCharacters('q')).toThrow();
expect(maskModel.value).toBe(value);
expect(maskModel.selection).toEqual(selection);
});
it('$|12 => Type $ => $|12', () => {
const value = '$12';
const selection = [1, 1] as const;
const maskModel = new MaskModel({value, selection}, options);
expect(() => maskModel.addCharacters('$')).toThrow();
expect(maskModel.value).toBe(value);
expect(maskModel.selection).toEqual(selection);
});
it('$|12 => Type X => $|12', () => {
const value = '$12';
const selection = [1, 1] as const;
const maskModel = new MaskModel({value, selection}, options);
expect(() => maskModel.addCharacters('X')).toThrow();
expect(maskModel.value).toBe(value);
expect(maskModel.selection).toEqual(selection);
});
});
});
});
describe('Dynamic mask expression + trailing fixed character', () => {
const postfix = 'left';
const timeMask: ReadonlyArray<RegExp | string> = [/\d/, /\d/, ':', /\d/, /\d/];
const timeWithPostfixMask: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
mask: ({value}) => {
let digitsCount = Math.min(value.replaceAll(/\D/g, '').length, 4);
const afterLastDigit =
timeMask.findIndex((x) => typeof x !== 'string' && !--digitsCount) +
1;
return afterLastDigit
? timeMask.slice(0, afterLastDigit).concat(...postfix)
: [];
},
overwriteMode: 'replace',
};
it('adds trailing postfix on enter of digit inside empty textfield', () => {
const maskModel = new MaskModel(
{
selection: [0, 0],
value: '',
},
timeWithPostfixMask,
);
maskModel.addCharacters('1');
expect(maskModel.value).toBe('1left');
expect(maskModel.selection).toEqual([1, 1]);
});
it('adds trailing postfix on paste of many digits inside empty textfield', () => {
const maskModel = new MaskModel(
{
selection: [0, 0],
value: '',
},
timeWithPostfixMask,
);
maskModel.addCharacters('123');
expect(maskModel.value).toBe('12:3left');
expect(maskModel.selection).toEqual(['12:3'.length, '12:3'.length]);
});
it('edits digit in the middle', () => {
const maskModel = new MaskModel(
{
selection: [1, 1],
value: '12:3left',
},
timeWithPostfixMask,
);
maskModel.addCharacters('4');
expect(maskModel.value).toBe('14:3left');
expect(maskModel.selection).toEqual([3, 3]);
});
it('erases the last digit without losing trailing fixed characters', () => {
const maskModel = new MaskModel(
{
selection: [3, 4],
value: '12:3left',
},
timeWithPostfixMask,
);
maskModel.deleteCharacters();
expect(maskModel.value).toBe('12left');
expect(maskModel.selection).toEqual([2, 2]);
});
it('erases the digit in the middle without losing trailing fixed character', () => {
const maskModel = new MaskModel(
{
selection: [3, 4],
value: '12:34 left',
},
timeWithPostfixMask,
);
maskModel.deleteCharacters();
expect(maskModel.value).toBe('12:4left');
expect(maskModel.selection).toEqual([3, 3]);
});
});
it('attempt to enter invalid character at the position of fixed character', () => {
const dateMask: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
mask: [/\d/, /\d/, '.', /\d/, /\d/],
};
const selection = [2, 2] as const;
const maskModel = new MaskModel(
{
selection,
value: '12',
},
dateMask,
);
expect(() => maskModel.addCharacters('#')).toThrow();
expect(maskModel.value).toBe('12');
expect(maskModel.selection).toEqual(selection);
});
it('accepts valid character at the position of fixed character', () => {
const dateMask: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
mask: [/\d/, /\d/, ':', /\d/, /\d/],
};
const selection = [2, 2] as const;
const maskModel = new MaskModel(
{
selection,
value: '12',
},
dateMask,
);
maskModel.addCharacters(':');
expect(maskModel.value).toBe('12:');
expect(maskModel.selection).toEqual(['12:'.length, '12:'.length]);
});
});
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/apply-overwrite-mode.ts
================================================
import type {ElementState, MaskitoOptions} from '../../../types';
export function applyOverwriteMode(
{value, selection}: ElementState,
newCharacters: string,
mode: MaskitoOptions['overwriteMode'],
): ElementState {
const [from, to] = selection;
const computedMode = typeof mode === 'function' ? mode({value, selection}) : mode;
return {
value,
selection:
computedMode === 'replace'
? [from, Math.max(from + newCharacters.length, to)]
: [from, to],
};
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/calibrate-value-by-mask.ts
================================================
import type {ElementState, MaskitoMaskExpression} from '../../../types';
import {guessValidValueByPattern} from './guess-valid-value-by-pattern';
import {guessValidValueByRegExp} from './guess-valid-value-by-reg-exp';
import {validateValueWithMask} from './validate-value-with-mask';
export function calibrateValueByMask(
elementState: ElementState,
mask: MaskitoMaskExpression,
initialElementState: ElementState | null = null,
): ElementState {
if (validateValueWithMask(elementState.value, mask)) {
return elementState;
}
const {value, selection} = Array.isArray(mask)
? guessValidValueByPattern(elementState, mask, initialElementState)
: guessValidValueByRegExp(elementState, mask);
return {
selection,
value: Array.isArray(mask) ? value.slice(0, mask.length) : value,
};
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/get-leading-fixed-characters.ts
================================================
import type {ElementState} from '../../../types';
import {isFixedCharacter} from './is-fixed-character';
export function getLeadingFixedCharacters(
mask: Array<RegExp | string>,
validatedValuePart: string,
newCharacter: string,
initialElementState: ElementState | null,
): string {
let leadingFixedCharacters = '';
for (let i = validatedValuePart.length; i < mask.length; i++) {
const charConstraint = mask[i] || '';
const isInitiallyExisted = initialElementState?.value[i] === charConstraint;
if (
!isFixedCharacter(charConstraint) ||
(charConstraint === newCharacter && !isInitiallyExisted)
) {
return leadingFixedCharacters;
}
leadingFixedCharacters += charConstraint;
}
return leadingFixedCharacters;
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-pattern.ts
================================================
import type {ElementState} from '../../../types';
import {getLeadingFixedCharacters} from './get-leading-fixed-characters';
import {isFixedCharacter} from './is-fixed-character';
import {validateValueWithMask} from './validate-value-with-mask';
export function guessValidValueByPattern(
elementState: ElementState,
mask: Array<RegExp | string>,
initialElementState: ElementState | null,
): ElementState {
let maskedFrom: number | null = null;
let maskedTo: number | null = null;
const maskedValue = Array.from(elementState.value).reduce(
(validatedCharacters, char, charIndex) => {
const leadingCharacters = getLeadingFixedCharacters(
mask,
validatedCharacters,
char,
initialElementState,
);
const newValidatedChars = `${validatedCharacters}${leadingCharacters}`;
const charConstraint = mask[newValidatedChars.length] || '';
if (maskedFrom === null && charIndex >= elementState.selection[0]) {
maskedFrom = newValidatedChars.length;
}
if (maskedTo === null && charIndex >= elementState.selection[1]) {
maskedTo = newValidatedChars.length;
}
if (isFixedCharacter(charConstraint)) {
return `${newValidatedChars}${charConstraint}`;
}
if (char.match(charConstraint)) {
return `${newValidatedChars}${char}`;
}
return leadingCharacters.startsWith(char)
? newValidatedChars
: validatedCharacters;
},
'',
);
const trailingFixedCharacters = getLeadingFixedCharacters(
mask,
maskedValue,
'',
initialElementState,
);
return {
value: validateValueWithMask(`${maskedValue}${trailingFixedCharacters}`, mask)
? `${maskedValue}${trailingFixedCharacters}`
: maskedValue,
// issues: https://github.com/typescript-eslint/typescript-eslint/issues/12069
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
selection: [maskedFrom ?? maskedValue.length, maskedTo ?? maskedValue.length],
};
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-reg-exp.ts
================================================
import type {ElementState} from '../../../types';
export function guessValidValueByRegExp(
{value, selection}: ElementState,
maskRegExp: RegExp,
): ElementState {
const [from, to] = selection;
let newFrom = from;
let newTo = to;
const validatedValue = Array.from(value).reduce((validatedValuePart, char, i) => {
const newPossibleValue = `${validatedValuePart}${char}`;
if (from === i) {
newFrom = validatedValuePart.length;
}
if (to === i) {
newTo = validatedValuePart.length;
}
return newPossibleValue.match(maskRegExp) ? newPossibleValue : validatedValuePart;
}, '');
return {
value: validatedValue,
selection: [
Math.min(newFrom, validatedValue.length),
Math.min(newTo, validatedValue.length),
],
};
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/is-fixed-character.ts
================================================
export function isFixedCharacter(char: RegExp | string): char is string {
return typeof char === 'string';
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/remove-fixed-mask-characters.ts
================================================
import type {ElementState, MaskitoMaskExpression} from '../../../types';
import {isFixedCharacter} from './is-fixed-character';
export function removeFixedMaskCharacters(
initialElementState: ElementState,
mask: MaskitoMaskExpression,
): ElementState {
if (!Array.isArray(mask)) {
return initialElementState;
}
const [from, to] = initialElementState.selection;
const selection: number[] = [];
const unmaskedValue = Array.from(initialElementState.value).reduce(
(rawValue, char, i) => {
const charConstraint = mask[i] || '';
if (i === from) {
selection.push(rawValue.length);
}
if (i === to) {
selection.push(rawValue.length);
}
return isFixedCharacter(charConstraint) && charConstraint === char
? rawValue
: `${rawValue}${char}`;
},
'',
);
if (selection.length < 2) {
selection.push(
...Array.from<number>({length: 2 - selection.length}).fill(
unmaskedValue.length,
),
);
}
return {
value: unmaskedValue,
selection: [selection[0]!, selection[1]!],
};
}
================================================
FILE: projects/core/src/lib/classes/mask-model/utils/validate-value-with-mask.ts
================================================
import type {MaskitoMaskExpression} from '../../../types';
import {isFixedCharacter} from './is-fixed-character';
export function validateValueWithMask(
value: string,
maskExpression: MaskitoMaskExpression,
): boolean {
if (Array.isArray(maskExpression)) {
return (
value.length === maskExpression.length &&
Array.from(value).every((char, i) => {
const charConstraint = maskExpression[i] || '';
return isFixedCharacter(charConstraint)
? char === charConstraint
: char.match(charConstraint);
})
);
}
return maskExpression.test(value);
}
================================================
FILE: projects/core/src/lib/constants/default-element-predicate.ts
================================================
import type {MaskitoElementPredicate} from '../types';
import {maskitoAdaptContentEditable} from '../utils/content-editable';
export const MASKITO_DEFAULT_ELEMENT_PREDICATE: MaskitoElementPredicate = (e) =>
e.isContentEditable
? maskitoAdaptContentEditable(e)
: e.querySelector<HTMLInputElement | HTMLTextAreaElement>('input,textarea') ||
(e as HTMLInputElement | HTMLTextAreaElement);
================================================
FILE: projects/core/src/lib/constants/default-options.ts
================================================
import type {MaskitoOptions} from '../types';
export const MASKITO_DEFAULT_OPTIONS: Required<MaskitoOptions> = {
mask: /^.*$/,
preprocessors: [],
postprocessors: [],
plugins: [],
overwriteMode: 'shift',
};
================================================
FILE: projects/core/src/lib/constants/index.ts
================================================
export * from './default-element-predicate';
export * from './default-options';
================================================
FILE: projects/core/src/lib/mask.ts
================================================
import {MaskHistory, MaskModel} from './classes';
import {MASKITO_DEFAULT_OPTIONS} from './constants';
import {createBrokenDefaultPlugin, createDoubleSpacePlugin} from './plugins';
import type {
ElementState,
MaskitoElement,
MaskitoOptions,
SelectionRange,
TypedInputEvent,
} from './types';
import {
areElementStatesEqual,
areElementValuesEqual,
EventListener,
getLineSelection,
getNotEmptySelection,
getWordSelection,
isRedo,
isUndo,
maskitoPipe,
maskitoTransform,
} from './utils';
const BUILT_IN_PLUGINS = [createDoubleSpacePlugin(), createBrokenDefaultPlugin()];
export class Maskito extends MaskHistory {
private readonly isTextArea = this.element.nodeName === 'TEXTAREA';
private readonly eventListener = new EventListener(this.element);
private readonly options: Required<MaskitoOptions> = {
...MASKITO_DEFAULT_OPTIONS,
...this.maskitoOptions,
};
private upcomingElementState: ElementState | null = null;
private readonly preprocessor = maskitoPipe(this.options.preprocessors);
private readonly postprocessor = maskitoPipe(this.options.postprocessors);
private readonly teardowns = this.options.plugins
.concat(BUILT_IN_PLUGINS)
.map((plugin) => plugin(this.element, this.options));
constructor(
private readonly element: MaskitoElement,
private readonly maskitoOptions: MaskitoOptions,
) {
super();
this.updateHistory(this.elementState);
this.eventListener.listen('keydown', (event) => {
if (isRedo(event)) {
event.preventDefault();
return this.redo();
}
if (isUndo(event)) {
event.preventDefault();
return this.undo();
}
});
this.eventListener.listen('beforeinput', (event) => {
const isForward = event.inputType.includes('Forward');
this.updateHistory(this.elementState);
switch (event.inputType) {
case 'deleteByCut':
case 'deleteContentBackward':
case 'deleteContentForward':
return this.handleDelete({
event,
isForward,
selection: getNotEmptySelection(this.elementState, isForward),
});
case 'deleteHardLineBackward':
case 'deleteHardLineForward':
case 'deleteSoftLineBackward':
case 'deleteSoftLineForward':
return this.handleDelete({
event,
isForward,
selection: getLineSelection(this.elementState, isForward),
force: true,
});
case 'deleteWordBackward':
case 'deleteWordForward':
return this.handleDelete({
event,
isForward,
selection: getWordSelection(this.elementState, isForward),
});
case 'historyRedo':
event.preventDefault();
return this.redo();
// historyUndo/historyRedo will not be triggered if value was modified programmatically
case 'historyUndo':
event.preventDefault();
return this.undo();
case 'insertCompositionText':
return; // will be handled inside `compositionend` event
case 'insertLineBreak':
case 'insertParagraph':
return this.handleEnter(event);
case 'insertReplacementText':
/**
* According {@link https://www.w3.org/TR/input-events-2 W3C specification}:
* > `insertReplacementText` – insert or replace existing text by means of a spell checker,
* > auto-correct, writing suggestions or similar.
* ___
* Firefox emits `insertReplacementText` event for its suggestion/autofill and for spell checker.
* However, it is impossible to detect which part of the textfield value is going to be replaced
* (`selectionStart` and `selectionEnd` just equal to the last caret position).
* ___
* Chrome does not fire `beforeinput` event for its suggestion/autofill.
* It emits only `input` event with `inputType` and `data` set to `undefined`.
* ___
* All these browser limitations make us to validate the result value later in `input` event.
*/
return;
case 'insertFromDrop':
case 'insertFromPaste':
case 'insertText':
default:
return this.handleInsert(
event,
event.data ??
// `event.data` for `contentEditable` is always `null` for paste/drop events
event.dataTransfer?.getData('text/plain') ??
'',
);
}
});
this.eventListener.listen(
'input',
() => {
if (
this.upcomingElementState &&
!areElementStatesEqual(this.upcomingElementState, this.elementState)
) {
this.updateElementState(this.upcomingElementState);
}
this.upcomingElementState = null;
},
{capture: true},
);
this.eventListener.listen('input', ({inputType}) => {
if (inputType === 'insertCompositionText') {
return; // will be handled inside `compositionend` event
}
this.ensureValueFitsMask();
this.updateHistory(this.elementState);
});
this.eventListener.listen('compositionend', () => {
this.ensureValueFitsMask();
this.updateHistory(this.elementState);
});
}
public destroy(): void {
this.eventListener.destroy();
this.teardowns.forEach((teardown) => teardown?.());
}
protected updateElementState(
{value, selection}: ElementState,
eventInit?: Pick<TypedInputEvent, 'data' | 'inputType'>,
): void {
const initialValue = this.elementState.value;
this.updateValue(value);
this.updateSelectionRange(selection);
if (eventInit && initialValue !== value) {
this.dispatchInputEvent(eventInit);
}
}
private get elementState(): ElementState {
const {value, selectionStart, selectionEnd} = this.element;
return {
value,
selection: [selectionStart ?? 0, selectionEnd ?? 0],
};
}
private get maxLength(): number {
const {maxLength} = this.element;
return maxLength === -1 ? Infinity : maxLength;
}
private updateSelectionRange([from, to]: SelectionRange): void {
const {element} = this;
if (
element.matches(':focus') &&
(element.selectionStart !== from || element.selectionEnd !== to)
) {
element.setSelectionRange(from, to);
}
}
private updateValue(value: string): void {
/**
* Don't "disturb" unnecessarily `value`-setter
* (i.e. it breaks React controlled input behavior)
*/
if (this.element.value !== value || this.element.isContentEditable) {
this.element.value = value;
}
}
private ensureValueFitsMask(): void {
this.updateElementState(maskitoTransform(this.elementState, this.options), {
inputType: 'insertText',
data: null,
});
}
private dispatchInputEvent(
eventInit: Pick<TypedInputEvent, 'data' | 'inputType'> = {
inputType: 'insertText',
data: null,
},
): void {
this.element.dispatchEvent(
new InputEvent('input', {
...eventInit,
bubbles: true,
cancelable: false,
}),
);
}
private handleDelete({
event,
selection,
isForward,
}: {
event: TypedInputEvent;
selection: SelectionRange;
isForward: boolean;
force?: boolean;
}): void {
const initialState: ElementState = {
value: this.elementState.value,
selection,
};
const {elementState} = this.preprocessor(
{
elementState: initialState,
data: '',
},
isForward ? 'deleteForward' : 'deleteBackward',
);
const maskModel = new MaskModel(elementState, this.options);
maskModel.deleteCharacters();
const newElementState = this.postprocessor(maskModel, initialState);
if (
areElementValuesEqual(initialState, elementState, maskModel, newElementState)
) {
const [from, to] = elementState.selection;
event.preventDefault();
// User presses Backspace/Delete for the fixed value
return this.updateSelectionRange(isForward ? [to, to] : [from, from]);
}
this.upcomingElementState = newElementState;
}
private handleInsert(event: TypedInputEvent, data: string): void {
const {options, maxLength, elementState: initialElementState} = this;
const [from, to] = initialElementState.selection;
const {elementState, data: insertedText = data} = this.preprocessor(
{
data,
elementState: initialElementState,
},
'insert',
);
const maskModel = new MaskModel(elementState, options);
try {
maskModel.addCharacters(insertedText);
} catch {
return event.preventDefault();
}
this.upcomingElementState = this.clampState(
this.postprocessor(maskModel, initialElementState),
);
/**
* When textfield value length is already equal to attribute `maxlength`,
* pressing any key (even with valid value) does not emit `input` event
* (except to the case when user replaces some characters by selection).
*/
const noInputEventDispatch =
initialElementState.value.length >= maxLength && from === to;
if (noInputEventDispatch) {
if (
options.overwriteMode === 'replace' &&
!areElementStatesEqual(this.upcomingElementState, initialElementState)
) {
this.dispatchInputEvent({inputType: 'insertText', data});
} else {
/**
* This `beforeinput` event will not be followed by `input` event –
* clear computed state to avoid any possible side effect
* for new possible `input` event without preceding `beforeinput` event
* (e.g. browser autofill, `document.execCommand('delete')` etc.)
*/
this.upcomingElementState = null;
}
}
}
private handleEnter(event: TypedInputEvent): void {
if (this.isTextArea || this.element.isContentEditable) {
this.handleInsert(event, '\n');
}
}
private clampState({value, selection}: ElementState): ElementState {
const [from, to] = selection;
const max = this.maxLength;
return {
value: value.slice(0, max),
selection: [Math.min(from, max), Math.min(to, max)],
};
}
}
================================================
FILE: projects/core/src/lib/plugins/broken-prevent-default.plugin.ts
================================================
import type {MaskitoPlugin} from '@maskito/core';
import type {TypedInputEvent} from '../types';
import {EventListener} from '../utils';
/**
* All `input` events with `inputType=deleteContentBackward` always follows `beforeinput` event with the same `inputType`.
* If `beforeinput[inputType=deleteContentBackward]` is prevented, subsequent `input[inputType=deleteContentBackward]` is prevented too.
* There is an exception – Android devices with Microsoft SwiftKey Keyboard in Mobile Chrome.
* These devices ignores `preventDefault` for `beforeinput` event if Backspace is pressed.
* @see https://github.com/taiga-family/maskito/issues/2135#issuecomment-2980729647
* ___
* TODO: track Chromium bug report and delete this plugin after bug fix
* https://issues.chromium.org/issues/40885402
*/
export function createBrokenDefaultPlugin(): MaskitoPlugin {
return (element) => {
const eventListener = new EventListener(element);
let isVirtualAndroidKeyboard = false;
let beforeinputEvent: TypedInputEvent;
let value = element.value;
eventListener.listen('keydown', ({key}) => {
isVirtualAndroidKeyboard = key === 'Unidentified';
});
eventListener.listen('beforeinput', (event) => {
beforeinputEvent = event;
value = element.value;
});
eventListener.listen(
'input',
(event) => {
if (
isVirtualAndroidKeyboard &&
beforeinputEvent.defaultPrevented &&
beforeinputEvent.inputType === 'deleteContentBackward' &&
event.inputType === 'deleteContentBackward'
) {
element.value = value;
}
},
{capture: true},
);
return () => eventListener.destroy();
};
}
================================================
FILE: projects/core/src/lib/plugins/change-event-plugin.ts
================================================
import type {MaskitoPlugin} from '../types';
export function maskitoChangeEventPlugin(): MaskitoPlugin {
return (element) => {
if (element.isContentEditable) {
return;
}
let value = element.value;
const valueListener = (): void => {
value = element.value;
};
const blurListener = (): void => {
if (element.value !== value) {
element.dispatchEvent(new Event('change', {bubbles: true}));
}
};
element.addEventListener('focus', valueListener);
element.addEventListener('change', valueListener);
element.addEventListener('blur', blurListener);
return () => {
element.removeEventListener('focus', valueListener);
element.removeEventListener('change', valueListener);
element.removeEventListener('blur', blurListener);
};
};
}
================================================
FILE: projects/core/src/lib/plugins/double-space.plugin.ts
================================================
import type {MaskitoPlugin} from '@maskito/core';
import type {TypedInputEvent} from '../types';
import {EventListener} from '../utils';
const SPACE = ' ';
/**
* 1. Android user (with G-board keyboard or similar) presses 1st space
* ```
* {type: "beforeinput", data: " ", inputType: "insertText"}
* ```
* 2. User presses 2nd space
* ```
* // Android tries to delete previously inserted space
* {type: "beforeinput", inputType: "deleteContentBackward"}
* {type: "beforeinput", data: ". ", inputType: "insertText"}
* ```
* ---------
* 1. MacOS user presses 1st space
* ```
* {type: "beforeinput", data: " ", inputType: "insertText"}
* ```
* 2. User presses 2nd space
* ```
* // MacOS automatically run `element.setSelectionRange(indexBeforeSpace, indexAfterSpace)` and then
* {type: "beforeinput", data: ". ", inputType: "insertText"}
* ```
* ---------
* @see https://github.com/taiga-family/maskito/issues/2023
*/
export function createDoubleSpacePlugin(): MaskitoPlugin {
let prevValue = '';
let prevCaretIndex = 0;
let prevEvent: TypedInputEvent | null = null;
let prevRejectedSpace = false;
return (element) => {
const eventListener = new EventListener(element);
eventListener.listen('beforeinput', (event) => {
const {value, selectionStart, selectionEnd} = element;
const rejectedSpace =
prevEvent?.inputType === 'insertText' &&
prevEvent.data === SPACE &&
!value.slice(0, Number(selectionEnd)).endsWith(SPACE);
if (event.inputType === 'insertText' && event.data === `.${SPACE}`) {
if (
prevEvent?.inputType === 'deleteContentBackward' &&
prevRejectedSpace
) {
// Android
element.value = prevValue;
element.setSelectionRange(prevCaretIndex, prevCaretIndex);
} else if (rejectedSpace) {
// Mac OS
element.setSelectionRange(selectionStart, selectionStart);
}
}
prevRejectedSpace = rejectedSpace;
prevEvent = event;
prevValue = value;
prevCaretIndex = Number(
(rejectedSpace ? prevCaretIndex : selectionEnd) === value.length
? selectionEnd
: selectionStart,
);
});
return () => eventListener.destroy();
};
}
================================================
FILE: projects/core/src/lib/plugins/index.ts
================================================
export * from './broken-prevent-default.plugin';
export * from './change-event-plugin';
export * from './double-space.plugin';
export * from './initial-calibration-plugin';
export * from './strict-composition-plugin';
================================================
FILE: projects/core/src/lib/plugins/initial-calibration-plugin.ts
================================================
import type {MaskitoOptions, MaskitoPlugin} from '../types';
import {maskitoTransform, maskitoUpdateElement} from '../utils';
export function maskitoInitialCalibrationPlugin(
customOptions?: MaskitoOptions,
): MaskitoPlugin {
return (element, options) => {
const from = element.selectionStart ?? 0;
const to = element.selectionEnd ?? 0;
maskitoUpdateElement(element, {
value: maskitoTransform(element.value, customOptions || options),
selection: [from, to],
});
};
}
================================================
FILE: projects/core/src/lib/plugins/strict-composition-plugin.ts
================================================
import type {ElementState, MaskitoPlugin, TypedInputEvent} from '../types';
import {areElementStatesEqual, maskitoTransform, maskitoUpdateElement} from '../utils';
export function maskitoStrictCompositionPlugin(): MaskitoPlugin {
return (element, maskitoOptions) => {
const listener = (event: TypedInputEvent): void => {
if (event.inputType !== 'insertCompositionText') {
return;
}
const selection = [
element.selectionStart ?? 0,
element.selectionEnd ?? 0,
] as const;
const elementState: ElementState = {
selection,
value: element.value,
};
const validatedState = maskitoTransform(elementState, maskitoOptions);
if (!areElementStatesEqual(elementState, validatedState)) {
event.preventDefault();
maskitoUpdateElement(element, validatedState);
}
};
element.addEventListener('input', listener as EventListener);
return () => element.removeEventListener('input', listener as EventListener);
};
}
================================================
FILE: projects/core/src/lib/types/element-predicate.ts
================================================
import type {MaskitoElement} from './maskito-element';
export type MaskitoElementPredicate = (
element: HTMLElement,
) => MaskitoElement | Promise<MaskitoElement>;
================================================
FILE: projects/core/src/lib/types/element-state.ts
================================================
import type {SelectionRange} from './selection-range';
export interface ElementState {
readonly value: string;
readonly selection: SelectionRange;
}
================================================
FILE: projects/core/src/lib/types/index.ts
================================================
export * from './element-predicate';
export * from './element-state';
export * from './mask';
export * from './mask-options';
export * from './mask-processors';
export * from './maskito-element';
export * from './plugin';
export * from './selection-range';
export * from './typed-input-event';
================================================
FILE: projects/core/src/lib/types/mask-options.ts
================================================
import type {ElementState} from './element-state';
import type {MaskitoMask} from './mask';
import type {MaskitoPostprocessor, MaskitoPreprocessor} from './mask-processors';
import type {MaskitoPlugin} from './plugin';
export interface MaskitoOptions {
readonly mask: MaskitoMask;
readonly preprocessors?: readonly MaskitoPreprocessor[];
readonly postprocessors?: readonly MaskitoPostprocessor[];
readonly plugins?: readonly MaskitoPlugin[];
readonly overwriteMode?:
| 'replace'
| 'shift'
| ((elementState: ElementState) => 'replace' | 'shift');
}
================================================
FILE: projects/core/src/lib/types/mask-processors.ts
================================================
import type {ElementState} from './element-state';
export type MaskitoPreprocessor = (
_: {
elementState: ElementState;
data: string;
},
actionType: 'deleteBackward' | 'deleteForward' | 'insert' | 'validation',
) => {
elementState: ElementState;
data?: string;
};
export type MaskitoPostprocessor = (
elementState: ElementState,
initialElementState: ElementState,
) => ElementState;
================================================
FILE: projects/core/src/lib/types/mask.ts
================================================
import type {ElementState} from './element-state';
export type MaskitoMaskExpression = Array<RegExp | string> | RegExp;
export type MaskitoMask =
| MaskitoMaskExpression
| ((elementState: ElementState) => MaskitoMaskExpression);
================================================
FILE: projects/core/src/lib/types/maskito-element.ts
================================================
export type TextfieldLike = Pick<
HTMLInputElement,
| 'maxLength'
| 'select'
| 'selectionEnd'
| 'selectionStart'
| 'setSelectionRange'
| 'value'
>;
export type MaskitoElement = HTMLElement & TextfieldLike;
================================================
FILE: projects/core/src/lib/types/plugin.ts
================================================
import type {MaskitoOptions} from './mask-options';
import type {MaskitoElement} from './maskito-element';
export type MaskitoPlugin = (
element: MaskitoElement,
options: Required<MaskitoOptions>,
) => (() => void) | void;
================================================
FILE: projects/core/src/lib/types/selection-range.ts
================================================
export type SelectionRange = readonly [from: number, to: number];
================================================
FILE: projects/core/src/lib/types/typed-input-event.ts
================================================
export interface TypedInputEvent extends InputEvent {
inputType:
| 'deleteByCut' // Ctrl (Command) + X
| 'deleteContentBackward' // Backspace
| 'deleteContentForward' // Delete (Fn + Backspace)
| 'deleteHardLineBackward' // Ctrl (Command) + Backspace
| 'deleteHardLineForward'
| 'deleteSoftLineBackward' // Ctrl (Command) + Backspace
| 'deleteSoftLineForward'
| 'deleteWordBackward' // Alt (Option) + Backspace
| 'deleteWordForward' // Alt (Option) + Delete (Fn + Backspace)
| 'historyRedo' // Ctrl (Command) + Shift + Z
| 'historyUndo' // Ctrl (Command) + Z
| 'insertCompositionText'
| 'insertFromDrop'
| 'insertFromPaste' // Ctrl (Command) + V
| 'insertLineBreak'
| 'insertParagraph'
| 'insertReplacementText'
| 'insertText';
}
================================================
FILE: projects/core/src/lib/utils/content-editable.ts
================================================
import type {MaskitoElement, TextfieldLike} from '../types';
import {getContentEditableSelection} from './dom/get-content-editable-selection';
import {setContentEditableSelection} from './dom/set-content-editable-selection';
class ContentEditableAdapter implements TextfieldLike {
public maxLength = Infinity;
constructor(private readonly element: HTMLElement) {}
public get value(): string {
return this.element.innerText.replace(/\n\n$/, '\n');
}
public set value(value) {
// Setting into innerHTML of element with `white-space: pre;` style
this.element.innerHTML = value.replace(/\n$/, '\n\n');
}
public get selectionStart(): number | null {
return getContentEditableSelection(this.element)[0];
}
public get selectionEnd(): number | null {
return getContentEditableSelection(this.element)[1];
}
public setSelectionRange(from: number | null, to: number | null): void {
setContentEditableSelection(this.element, [from ?? 0, to ?? 0]);
}
public select(): void {
this.setSelectionRange(0, this.value.length);
}
}
export function maskitoAdaptContentEditable(element: HTMLElement): MaskitoElement {
const adapter = new ContentEditableAdapter(element);
return new Proxy(element, {
get(target, prop: keyof HTMLElement) {
if (prop in adapter) {
return adapter[prop as keyof ContentEditableAdapter];
}
const nativeProperty = target[prop];
return typeof nativeProperty === 'function'
? nativeProperty.bind(target)
: nativeProperty;
},
set(target, prop: keyof HTMLElement, val, receiver) {
return Reflect.set(prop in adapter ? adapter : target, prop, val, receiver);
},
}) as MaskitoElement;
}
================================================
FILE: projects/core/src/lib/utils/dom/event-listener.ts
================================================
import type {TypedInputEvent} from '../../types';
export class EventListener {
private readonly listeners: Array<() => void> = [];
constructor(private readonly element: HTMLElement) {}
public listen<E extends keyof HTMLElementEventMap>(
eventType: E,
fn: (
event: E extends 'beforeinput' | 'input'
? TypedInputEvent
: HTMLElementEventMap[E],
) => unknown,
options?: AddEventListenerOptions,
): void {
const untypedFn = fn as (event: HTMLElementEventMap[E]) => unknown;
this.element.addEventListener(eventType, untypedFn, options);
this.listeners.push(() =>
this.element.removeEventListener(eventType, untypedFn, options),
);
}
public destroy(): void {
this.listeners.forEach((stopListen) => stopListen());
}
}
================================================
FILE: projects/core/src/lib/utils/dom/get-content-editable-selection.ts
================================================
import type {SelectionRange} from '../../types';
export function getContentEditableSelection(element: HTMLElement): SelectionRange {
const {anchorOffset = 0, focusOffset = 0} =
element.ownerDocument.getSelection() || {};
const from = Math.min(anchorOffset, focusOffset);
const to = Math.max(anchorOffset, focusOffset);
return [from, to];
}
================================================
FILE: projects/core/src/lib/utils/dom/history-events.ts
================================================
import {HotkeyCode, HotkeyModifier, isHotkey} from './hotkey';
export function isRedo(event: KeyboardEvent): boolean {
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
);
}
export function isUndo(event: KeyboardEvent): boolean {
return (
isHotkey(event, HotkeyModifier.CTRL, HotkeyCode.Z) || // Windows & Android
isHotkey(event, HotkeyModifier.META, HotkeyCode.Z) // macOS & iOS
);
}
================================================
FILE: projects/core/src/lib/utils/dom/hotkey.ts
================================================
export const HotkeyModifier = {
CTRL: 1 << 0,
ALT: 1 << 1,
SHIFT: 1 << 2,
META: 1 << 3,
} as const;
// TODO add variants that can be processed correctly
export const HotkeyCode = {
Y: 89,
Z: 90,
} as const;
/**
* 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
*/
export function isHotkey(
event: KeyboardEvent,
modifiers: (typeof HotkeyModifier)[keyof typeof HotkeyModifier],
hotkeyCode: (typeof HotkeyCode)[keyof typeof HotkeyCode],
): boolean {
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}
*/
event.keyCode === hotkeyCode
);
}
================================================
FILE: projects/core/src/lib/utils/dom/set-content-editable-selection.ts
================================================
import type {SelectionRange} from '../../types';
export function setContentEditableSelection(
element: HTMLElement,
[from, to]: SelectionRange,
): void {
const document = element.ownerDocument;
const range = document.createRange();
range.setStart(
element.firstChild || element,
Math.min(from, element.textContent?.length ?? 0),
);
range.setEnd(
element.lastChild || element,
Math.min(to, element.textContent?.length ?? 0),
);
const selection = document.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
}
}
================================================
FILE: projects/core/src/lib/utils/dom/update-element.ts
================================================
import type {ElementState, MaskitoElement} from '../../types';
/**
* 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
*/
export function maskitoUpdateElement(
element: MaskitoElement,
valueOrElementState: ElementState | string,
): void {
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')) {
element.setSelectionRange(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
gitextract_lbehwmqa/ ├── .cspell.json ├── .editorconfig ├── .firebaserc ├── .github/ │ ├── CODEOWNERS │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ ├── 1-bug-report.yml │ │ ├── 2-feature-request.yml │ │ └── 3-documentation.yml │ ├── renovate.json │ └── workflows/ │ ├── assign-author.yml │ ├── auto-merge.yml │ ├── build.yml │ ├── deploy-preview.yml │ ├── deploy.yml │ ├── e2e.yml │ ├── lint.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .husky/ │ ├── commit-msg │ └── pre-commit ├── .npmrc ├── .release-it.js ├── .ws-context ├── CHANGELOG.md ├── LICENSE ├── README.md ├── codecov.yml ├── eslint.config.ts ├── firebase.json ├── jest.config.ts ├── jest.preset.js ├── nx.json ├── package.json ├── projects/ │ ├── angular/ │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── ng-package.json │ │ ├── package.json │ │ ├── project.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ ├── lib/ │ │ │ │ ├── maskito.directive.ts │ │ │ │ ├── maskito.pipe.ts │ │ │ │ ├── pattern.directive.ts │ │ │ │ └── tests/ │ │ │ │ ├── maskito.directive.spec.ts │ │ │ │ └── maskito.spec.ts │ │ │ └── test-setup.ts │ │ └── tsconfig.lib.prod.json │ ├── core/ │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ └── src/ │ │ ├── index.ts │ │ └── lib/ │ │ ├── classes/ │ │ │ ├── index.ts │ │ │ ├── mask-history.ts │ │ │ └── mask-model/ │ │ │ ├── mask-model.ts │ │ │ ├── tests/ │ │ │ │ ├── dynamic-mask.spec.ts │ │ │ │ └── mask-model-fixed-characters.spec.ts │ │ │ └── utils/ │ │ │ ├── apply-overwrite-mode.ts │ │ │ ├── calibrate-value-by-mask.ts │ │ │ ├── get-leading-fixed-characters.ts │ │ │ ├── guess-valid-value-by-pattern.ts │ │ │ ├── guess-valid-value-by-reg-exp.ts │ │ │ ├── is-fixed-character.ts │ │ │ ├── remove-fixed-mask-characters.ts │ │ │ └── validate-value-with-mask.ts │ │ ├── constants/ │ │ │ ├── default-element-predicate.ts │ │ │ ├── default-options.ts │ │ │ └── index.ts │ │ ├── mask.ts │ │ ├── plugins/ │ │ │ ├── broken-prevent-default.plugin.ts │ │ │ ├── change-event-plugin.ts │ │ │ ├── double-space.plugin.ts │ │ │ ├── index.ts │ │ │ ├── initial-calibration-plugin.ts │ │ │ └── strict-composition-plugin.ts │ │ ├── types/ │ │ │ ├── element-predicate.ts │ │ │ ├── element-state.ts │ │ │ ├── index.ts │ │ │ ├── mask-options.ts │ │ │ ├── mask-processors.ts │ │ │ ├── mask.ts │ │ │ ├── maskito-element.ts │ │ │ ├── plugin.ts │ │ │ ├── selection-range.ts │ │ │ └── typed-input-event.ts │ │ └── utils/ │ │ ├── content-editable.ts │ │ ├── dom/ │ │ │ ├── event-listener.ts │ │ │ ├── get-content-editable-selection.ts │ │ │ ├── history-events.ts │ │ │ ├── hotkey.ts │ │ │ ├── set-content-editable-selection.ts │ │ │ └── update-element.ts │ │ ├── element-states-equality.ts │ │ ├── get-line-selection.ts │ │ ├── get-not-empty-selection.ts │ │ ├── get-word-selection.ts │ │ ├── index.ts │ │ ├── pipe.ts │ │ ├── test/ │ │ │ ├── get-not-empty-selection.spec.ts │ │ │ ├── get-word-selection.spec.ts │ │ │ ├── pipe.spec.ts │ │ │ └── transform.spec.ts │ │ └── transform.ts │ ├── demo/ │ │ ├── .gitignore │ │ ├── esbuild-plugins/ │ │ │ ├── maskito-as-taiga-ui-dep.plugin.js │ │ │ └── vue-esm.plugin.js │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ ├── src/ │ │ │ ├── app/ │ │ │ │ ├── app.component.html │ │ │ │ ├── app.component.spec.ts │ │ │ │ ├── app.component.ts │ │ │ │ ├── app.config.ts │ │ │ │ ├── app.routes.ts │ │ │ │ ├── app.style.less │ │ │ │ ├── constants/ │ │ │ │ │ ├── demo-path.ts │ │ │ │ │ ├── doc-example-primary-tab.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── modules/ │ │ │ │ │ ├── example-primary-tabs-icons/ │ │ │ │ │ │ ├── angular-logo.component.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── javascript-logo.component.ts │ │ │ │ │ │ ├── react-logo.component.ts │ │ │ │ │ │ └── vue-logo.component.ts │ │ │ │ │ └── logo/ │ │ │ │ │ ├── logo.component.ts │ │ │ │ │ ├── logo.style.less │ │ │ │ │ └── logo.template.html │ │ │ │ ├── server-error-handler.ts │ │ │ │ └── utils/ │ │ │ │ ├── add-default-tabs-processor/ │ │ │ │ │ ├── add-default-tabs-processor.ts │ │ │ │ │ └── default-tabs/ │ │ │ │ │ ├── angular-default-tab.ts │ │ │ │ │ ├── js-default-tab.ts │ │ │ │ │ ├── react-default-tab.ts │ │ │ │ │ └── vue-default-tab.ts │ │ │ │ └── index.ts │ │ │ ├── assets/ │ │ │ │ └── manifest.webmanifest │ │ │ ├── environments/ │ │ │ │ ├── environment.prod.ts │ │ │ │ └── environment.ts │ │ │ ├── index.html │ │ │ ├── main.server.ts │ │ │ ├── main.ts │ │ │ ├── pages/ │ │ │ │ ├── documentation/ │ │ │ │ │ ├── browser-support/ │ │ │ │ │ │ ├── browser-support.component.ts │ │ │ │ │ │ └── browser-support.template.html │ │ │ │ │ ├── core-concepts-overview/ │ │ │ │ │ │ ├── core-concepts-overview.component.ts │ │ │ │ │ │ ├── core-concepts-overview.styles.less │ │ │ │ │ │ ├── core-concepts-overview.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ └── maskito-public-api-demo.md │ │ │ │ │ ├── element-state/ │ │ │ │ │ │ ├── element-state.component.ts │ │ │ │ │ │ ├── element-state.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ └── element-state-demo.md │ │ │ │ │ ├── mask-expression/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── basic-time-example.md │ │ │ │ │ │ │ ├── dynamic-mask-expression-demo.md │ │ │ │ │ │ │ └── reg-exp-mask-expression-demo.md │ │ │ │ │ │ ├── mask-expression.component.ts │ │ │ │ │ │ └── mask-expression.template.html │ │ │ │ │ ├── maskito-libraries/ │ │ │ │ │ │ ├── maskito-libraries.component.ts │ │ │ │ │ │ └── maskito-libraries.template.html │ │ │ │ │ ├── next-steps/ │ │ │ │ │ │ ├── next-steps.component.ts │ │ │ │ │ │ └── next-steps.template.html │ │ │ │ │ ├── overwrite-mode/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── dynamic/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── replace/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── shift/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── overwrite-mode.component.ts │ │ │ │ │ │ └── overwrite-mode.template.html │ │ │ │ │ ├── plugins/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-initial-calibration/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 2-strict-composition/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 3-change-event/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── oversimplified-number-mask.md │ │ │ │ │ │ │ └── pads-zero-plugin.ts │ │ │ │ │ │ ├── plugins.component.ts │ │ │ │ │ │ ├── plugins.style.less │ │ │ │ │ │ └── plugins.template.html │ │ │ │ │ ├── processors/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── postprocessor-in-action.md │ │ │ │ │ │ │ ├── preprocessor-first-arg-demo.md │ │ │ │ │ │ │ ├── preprocessor-in-action-demo.md │ │ │ │ │ │ │ └── processor-second-arg-demo.md │ │ │ │ │ │ ├── processors.component.ts │ │ │ │ │ │ └── processors.template.html │ │ │ │ │ ├── real-world-form/ │ │ │ │ │ │ ├── index.html │ │ │ │ │ │ ├── index.less │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── supported-input-types/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── password/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── search/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── tel/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── text/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── url/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── supported-input-types.component.ts │ │ │ │ │ │ └── supported-input-types.template.html │ │ │ │ │ ├── transformer/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ └── utility-in-action-demo.md │ │ │ │ │ │ ├── transformer.component.ts │ │ │ │ │ │ └── transformer.template.html │ │ │ │ │ └── what-is-maskito/ │ │ │ │ │ ├── what-is-maskito.component.ts │ │ │ │ │ ├── what-is-maskito.style.less │ │ │ │ │ └── what-is-maskito.template.html │ │ │ │ ├── frameworks/ │ │ │ │ │ ├── angular/ │ │ │ │ │ │ ├── angular-doc.component.ts │ │ │ │ │ │ ├── angular-doc.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ ├── 1-nested/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── template.html │ │ │ │ │ │ ├── 2-nested/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── template.html │ │ │ │ │ │ ├── 3-programmatically/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── template.html │ │ │ │ │ │ ├── 4-pipe/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── template.html │ │ │ │ │ │ ├── 5-custom-unmask-handler/ │ │ │ │ │ │ │ ├── index.html │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── unmask.directive.ts │ │ │ │ │ │ ├── 6-pattern/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── template.html │ │ │ │ │ │ ├── basic-directive-approach.md │ │ │ │ │ │ ├── custom-input-example.md │ │ │ │ │ │ └── import-maskito.md │ │ │ │ │ ├── react/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-use-maskito-basic-usage/ │ │ │ │ │ │ │ │ ├── example.component.tsx │ │ │ │ │ │ │ │ └── useMaskitoBasicUsage.tsx │ │ │ │ │ │ │ ├── 2-element-predicate/ │ │ │ │ │ │ │ │ ├── awesomeInput.tsx │ │ │ │ │ │ │ │ ├── example.component.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── 3-merge-ref/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── 3-react-hook-form/ │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── with-maskito-register.ts │ │ │ │ │ │ │ ├── best-bad-practice.md │ │ │ │ │ │ │ ├── controlled-input.md │ │ │ │ │ │ │ └── merge-ref.md │ │ │ │ │ │ ├── react-doc.component.ts │ │ │ │ │ │ ├── react-doc.style.less │ │ │ │ │ │ └── react-doc.template.html │ │ │ │ │ └── vue/ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ ├── best-bad-practice.md │ │ │ │ │ │ ├── query-nested-input.md │ │ │ │ │ │ ├── use-maskito-basic-usage.md │ │ │ │ │ │ └── vue-1/ │ │ │ │ │ │ └── component.ts │ │ │ │ │ ├── vue-doc.component.ts │ │ │ │ │ └── vue-doc.template.html │ │ │ │ ├── kit/ │ │ │ │ │ ├── date/ │ │ │ │ │ │ ├── date-mask-doc.component.ts │ │ │ │ │ │ ├── date-mask-doc.style.less │ │ │ │ │ │ ├── date-mask-doc.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ ├── 1-localization/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-min-max/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── maskito-parse-stringify-date-demo.md │ │ │ │ │ ├── date-range/ │ │ │ │ │ │ ├── date-range-mask-doc.component.ts │ │ │ │ │ │ ├── date-range-mask-doc.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ ├── 1-date-localization/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-min-max/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-min-max-length/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── 4-range-separator/ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ └── mask.ts │ │ │ │ │ ├── date-time/ │ │ │ │ │ │ ├── date-time-mask-doc.component.ts │ │ │ │ │ │ ├── date-time-mask-doc.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ ├── 1-date-time-localization/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-date-time-separator/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-min-max/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 4-time-step/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 5-am-pm/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── maskito-parse-stringify-date-time-demo.md │ │ │ │ │ ├── number/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-high-precision/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 2-separators/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 3-postfix/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 4-decimal-zero-padding/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 5-custom-minus-sign/ │ │ │ │ │ │ │ │ ├── components.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 6-minus-before-prefix/ │ │ │ │ │ │ │ │ ├── components.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 7-dynamic-decimal-zero-padding/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 8-thousand-separator-pattern/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 9-thousand-separator-pattern-intl/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── helpers/ │ │ │ │ │ │ │ ├── parse-number-as-bigint-type.md │ │ │ │ │ │ │ ├── parse-number-as-number-type.md │ │ │ │ │ │ │ ├── parse-number-invalid-usage.md │ │ │ │ │ │ │ └── stringify-number.md │ │ │ │ │ │ ├── number-mask-doc.component.ts │ │ │ │ │ │ └── number-mask-doc.template.html │ │ │ │ │ ├── plugins/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-selection-handler/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 2-caret-guard/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 3-event-handlers/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 4-reject/ │ │ │ │ │ │ │ ├── animation.css │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── kit-plugins-doc.component.ts │ │ │ │ │ │ └── kit-plugins-doc.template.html │ │ │ │ │ └── time/ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ ├── 1-modes/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-am-pm/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-step/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 4-affixes/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 5-time-segments-min-max/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── maskito-parse-stringify-time-demo.md │ │ │ │ │ ├── time-mask-doc.component.ts │ │ │ │ │ ├── time-mask-doc.style.less │ │ │ │ │ └── time-mask-doc.template.html │ │ │ │ ├── pages.ts │ │ │ │ ├── phone/ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ ├── 1-basic/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-validation/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-non-strict/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 4-lazy-metadata/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── simple.md │ │ │ │ │ │ ├── 5-focus-blur-events/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── 6-national-format/ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ └── mask.ts │ │ │ │ │ ├── phone-doc.component.ts │ │ │ │ │ ├── phone-doc.style.less │ │ │ │ │ └── phone-doc.template.html │ │ │ │ ├── recipes/ │ │ │ │ │ ├── card/ │ │ │ │ │ │ ├── card-doc.component.ts │ │ │ │ │ │ ├── card-doc.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ └── 1-basic/ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ ├── style.less │ │ │ │ │ │ └── template.html │ │ │ │ │ ├── content-editable/ │ │ │ │ │ │ ├── content-editable-doc.component.ts │ │ │ │ │ │ ├── content-editable-doc.template.html │ │ │ │ │ │ └── examples/ │ │ │ │ │ │ ├── 1-time/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-multi-line/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── maskito-with-content-editable.md │ │ │ │ │ │ └── vanilla-js-tab.md │ │ │ │ │ ├── network-address/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-ipv6/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 2-ipv4/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 3-mac/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── network-address-doc.component.ts │ │ │ │ │ │ └── network-address-doc.template.html │ │ │ │ │ ├── phone/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-us-phone/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 2-kz-phone/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ │ └── template.html │ │ │ │ │ │ ├── phone-doc.component.ts │ │ │ │ │ │ └── phone-doc.template.html │ │ │ │ │ ├── placeholder/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-cvc-code/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ ├── 2-phone/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 3-date/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── placeholder-doc.component.ts │ │ │ │ │ │ └── placeholder-doc.template.html │ │ │ │ │ ├── postfix/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-pattern-mask/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 2-postprocessor/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── postfix-doc.component.ts │ │ │ │ │ │ └── postfix-doc.template.html │ │ │ │ │ ├── prefix/ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ ├── 1-pattern-mask/ │ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ │ └── 2-postprocessor/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── prefix-doc.component.ts │ │ │ │ │ │ └── prefix-doc.template.html │ │ │ │ │ └── textarea/ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ ├── 1-latin/ │ │ │ │ │ │ │ ├── component.ts │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── maskito-with-textarea.md │ │ │ │ │ ├── textarea-doc.component.ts │ │ │ │ │ └── textarea-doc.template.html │ │ │ │ └── stackblitz/ │ │ │ │ ├── components/ │ │ │ │ │ ├── stackblitz-edit-button/ │ │ │ │ │ │ ├── stackblitz-edit-button.component.ts │ │ │ │ │ │ └── stackblitz-edit-button.style.less │ │ │ │ │ └── stackblitz-starter/ │ │ │ │ │ ├── stackblitz-starter.component.ts │ │ │ │ │ └── stackblitz-starter.style.less │ │ │ │ ├── files/ │ │ │ │ │ ├── example.ts.md │ │ │ │ │ ├── starter.ts.md │ │ │ │ │ └── styles.css │ │ │ │ ├── index.ts │ │ │ │ └── stackblitz.service.ts │ │ │ ├── server.ts │ │ │ ├── styles.less │ │ │ ├── test-setup.ts │ │ │ └── typings.d.ts │ │ ├── tsconfig.app.json │ │ └── tsconfig.typecheck.json │ ├── demo-integrations/ │ │ ├── cypress-react.config.ts │ │ ├── cypress.config.ts │ │ ├── package.json │ │ ├── project.json │ │ ├── src/ │ │ │ ├── fixtures/ │ │ │ │ └── example.json │ │ │ ├── plugins/ │ │ │ │ └── index.js │ │ │ ├── support/ │ │ │ │ ├── assertions/ │ │ │ │ │ ├── have-ng-control-value.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── commands/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── paste.ts │ │ │ │ │ └── smart-tick.ts │ │ │ │ ├── component-index.html │ │ │ │ ├── component-react.ts │ │ │ │ ├── component.ts │ │ │ │ ├── constants/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── real-events-support.ts │ │ │ │ └── e2e.ts │ │ │ └── tests/ │ │ │ ├── addons/ │ │ │ │ └── phone/ │ │ │ │ ├── phone-basic.cy.ts │ │ │ │ ├── phone-national-trunk-prefix.cy.ts │ │ │ │ ├── phone-non-strict.cy.ts │ │ │ │ ├── phone-separator.cy.ts │ │ │ │ └── phone-strict.cy.ts │ │ │ ├── angular/ │ │ │ │ ├── form-control-changes.cy.ts │ │ │ │ └── unmask-handler.cy.ts │ │ │ ├── component-testing/ │ │ │ │ ├── angular/ │ │ │ │ │ ├── disable-mask-on-null.cy.ts │ │ │ │ │ └── pattern.cy.ts │ │ │ │ ├── angular-predicate/ │ │ │ │ │ ├── angular-predicate.cy.ts │ │ │ │ │ └── multi-test.component.ts │ │ │ │ ├── change-event-plugin/ │ │ │ │ │ └── change-event-plugin.cy.ts │ │ │ │ ├── initial-calibration-plugin/ │ │ │ │ │ └── dispatch-event.cy.ts │ │ │ │ ├── multi-character-date-segment-separator/ │ │ │ │ │ └── multi-character-date-segment-separator.cy.ts │ │ │ │ ├── native-max-length/ │ │ │ │ │ └── native-maxlength-attribute.cy.ts │ │ │ │ ├── native-select-method/ │ │ │ │ │ └── native-select-method.cy.ts │ │ │ │ ├── number/ │ │ │ │ │ ├── alone-decimal-separator.cy.ts │ │ │ │ │ ├── min-max-bigint.cy.ts │ │ │ │ │ ├── mirrored-prefix-postfix.cy.ts │ │ │ │ │ ├── mirrored-value-postfix.cy.ts │ │ │ │ │ ├── multi-character-prefix.cy.ts │ │ │ │ │ ├── overwrite-selection-range.cy.ts │ │ │ │ │ ├── postfix-multi-character.cy.ts │ │ │ │ │ ├── postfix-with-point.cy.ts │ │ │ │ │ ├── runtime-postfix-changes/ │ │ │ │ │ │ ├── runtime-postfix-changes.cy.ts │ │ │ │ │ │ └── sandbox.component.ts │ │ │ │ │ └── with-initial-value.cy.ts │ │ │ │ ├── overwrite-mode/ │ │ │ │ │ └── overwrite-mode-replace.cy.ts │ │ │ │ ├── paste/ │ │ │ │ │ └── cy-paste-utility.cy.ts │ │ │ │ ├── phone/ │ │ │ │ │ ├── phone-national-format.cy.ts │ │ │ │ │ └── phone-with-initial-value.cy.ts │ │ │ │ ├── placeholder/ │ │ │ │ │ ├── placeholder-dispatch-input-events.cy.ts │ │ │ │ │ ├── placeholder-has-same-characters-as-textfield.cy.ts │ │ │ │ │ └── placeholder-partial-removal-on-blur.cy.ts │ │ │ │ ├── react/ │ │ │ │ │ ├── async-predicate-options-race/ │ │ │ │ │ │ ├── reactApp.tsx │ │ │ │ │ │ └── reactAsyncPredicateOptionsRace.cy.tsx │ │ │ │ │ ├── async-predicates-race/ │ │ │ │ │ │ ├── reactApp.tsx │ │ │ │ │ │ └── reactAsyncPredicatesRace.cy.tsx │ │ │ │ │ ├── awesomeInput.tsx │ │ │ │ │ └── change-event/ │ │ │ │ │ └── changeEvent.cy.tsx │ │ │ │ └── utils.ts │ │ │ ├── kit/ │ │ │ │ ├── date/ │ │ │ │ │ ├── date-basic.cy.ts │ │ │ │ │ ├── date-fullwidth-to-halfwidth.cy.ts │ │ │ │ │ ├── date-min-max.cy.ts │ │ │ │ │ ├── date-mode.cy.ts │ │ │ │ │ ├── date-segments-zero-padding.cy.ts │ │ │ │ │ └── date-separator.cy.ts │ │ │ │ ├── date-range/ │ │ │ │ │ ├── date-range-basic.cy.ts │ │ │ │ │ ├── date-range-custom-range-separator.cy.ts │ │ │ │ │ ├── date-range-fullwidth-to-halfwidth.cy.ts │ │ │ │ │ ├── date-range-min-max-length.cy.ts │ │ │ │ │ ├── date-range-min-max.cy.ts │ │ │ │ │ ├── date-range-mode.cy.ts │ │ │ │ │ ├── date-range-segments-zero-padding.cy.ts │ │ │ │ │ └── date-range-separator.cy.ts │ │ │ │ ├── date-time/ │ │ │ │ │ ├── date-time-basic.cy.ts │ │ │ │ │ ├── date-time-date-time-separator.cy.ts │ │ │ │ │ ├── date-time-fullwidth-to-halfwidth.cy.ts │ │ │ │ │ ├── date-time-meridiem.cy.ts │ │ │ │ │ ├── date-time-min-max.cy.ts │ │ │ │ │ ├── date-time-mode.cy.ts │ │ │ │ │ ├── date-time-separator.cy.ts │ │ │ │ │ └── date-time-time-step.cy.ts │ │ │ │ ├── number/ │ │ │ │ │ ├── number-basic.cy.ts │ │ │ │ │ ├── number-bigint.cy.ts │ │ │ │ │ ├── number-decimal-separator.cy.ts │ │ │ │ │ ├── number-decimal-zero-padding.cy.ts │ │ │ │ │ ├── number-examples.cy.ts │ │ │ │ │ ├── number-fullwidth-to-halfwidth.cy.ts │ │ │ │ │ ├── number-max-validation.cy.ts │ │ │ │ │ ├── number-min-validation.cy.ts │ │ │ │ │ ├── number-minus-before-prefix.cy.ts │ │ │ │ │ ├── number-minus-sign.cy.ts │ │ │ │ │ ├── number-precision.cy.ts │ │ │ │ │ ├── number-prefix-postfix.cy.ts │ │ │ │ │ ├── number-thousand-separator.cy.ts │ │ │ │ │ ├── number-zero-integer-part.cy.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── time/ │ │ │ │ ├── time-affixes.cy.ts │ │ │ │ ├── time-basic.cy.ts │ │ │ │ ├── time-fullwidth-to-halfwidth.cy.ts │ │ │ │ ├── time-meridiem.cy.ts │ │ │ │ ├── time-mode.cy.ts │ │ │ │ ├── time-segment-max-values.cy.ts │ │ │ │ └── time-step.cy.ts │ │ │ ├── react/ │ │ │ │ └── element-predicate.cy.ts │ │ │ ├── recipes/ │ │ │ │ ├── card/ │ │ │ │ │ └── card.cy.ts │ │ │ │ ├── content-editable/ │ │ │ │ │ ├── multi-line.cy.ts │ │ │ │ │ └── single-line-time-mask.cy.ts │ │ │ │ ├── network-address/ │ │ │ │ │ ├── ipv4.cy.ts │ │ │ │ │ ├── ipv6.cy.ts │ │ │ │ │ └── mac.cy.ts │ │ │ │ ├── phone/ │ │ │ │ │ └── phone.cy.ts │ │ │ │ ├── placeholder/ │ │ │ │ │ ├── date.cy.ts │ │ │ │ │ ├── us-phone.cy.ts │ │ │ │ │ └── сvc-code.cy.ts │ │ │ │ ├── plugins/ │ │ │ │ │ └── reject.cy.ts │ │ │ │ ├── postfix/ │ │ │ │ │ ├── percentage.cy.ts │ │ │ │ │ └── postprocessor.cy.ts │ │ │ │ ├── prefix/ │ │ │ │ │ ├── dynamic-pattern-mask-expression.cy.ts │ │ │ │ │ └── postprocessor.cy.ts │ │ │ │ └── textarea/ │ │ │ │ └── textarea-latin-letters-digits.cy.ts │ │ │ ├── ssr/ │ │ │ │ └── ssr.cy.ts │ │ │ ├── utils.ts │ │ │ └── vue/ │ │ │ └── vue.cy.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── kit/ │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ └── src/ │ │ ├── index.ts │ │ └── lib/ │ │ ├── constants/ │ │ │ ├── date-segment-max-values.ts │ │ │ ├── default-decimal-pseudo-separators.ts │ │ │ ├── default-min-max-dates.ts │ │ │ ├── default-pseudo-minuses.ts │ │ │ ├── default-time-segment-bounds.ts │ │ │ ├── index.ts │ │ │ ├── meridiem.ts │ │ │ ├── time-fixed-characters.ts │ │ │ ├── time-segment-value-lengths.ts │ │ │ └── unicode-characters.ts │ │ ├── masks/ │ │ │ ├── date/ │ │ │ │ ├── date-mask.ts │ │ │ │ ├── date-params.ts │ │ │ │ ├── index.ts │ │ │ │ ├── tests/ │ │ │ │ │ └── date-mask.spec.ts │ │ │ │ └── utils/ │ │ │ │ ├── index.ts │ │ │ │ ├── parse-date.ts │ │ │ │ ├── stringify-date.ts │ │ │ │ ├── tests/ │ │ │ │ │ ├── parse-date.spec.ts │ │ │ │ │ └── stringify-date.spec.ts │ │ │ │ └── to-date-segments.ts │ │ │ ├── date-range/ │ │ │ │ ├── constants.ts │ │ │ │ ├── date-range-mask.ts │ │ │ │ ├── index.ts │ │ │ │ ├── processors/ │ │ │ │ │ ├── min-max-range-length-postprocessor.ts │ │ │ │ │ └── swap-dates-postprocessor.ts │ │ │ │ └── tests/ │ │ │ │ ├── date-segments-zero-padding.spec.ts │ │ │ │ └── pseudo-range-separators.spec.ts │ │ │ ├── date-time/ │ │ │ │ ├── constants/ │ │ │ │ │ ├── date-time-separator.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── date-time-mask.ts │ │ │ │ ├── date-time-params.ts │ │ │ │ ├── index.ts │ │ │ │ ├── postprocessors/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── min-max-date-time-postprocessor.ts │ │ │ │ ├── preprocessors/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── valid-date-time-preprocessor.ts │ │ │ │ ├── tests/ │ │ │ │ │ ├── date-segments-zero-padding.spec.ts │ │ │ │ │ ├── date-time-separator.spec.ts │ │ │ │ │ └── pseudo-date-end-separator.spec.ts │ │ │ │ └── utils/ │ │ │ │ ├── index.ts │ │ │ │ ├── is-date-time-string-complete.ts │ │ │ │ ├── parse-date-time.ts │ │ │ │ ├── split-date-time-string.ts │ │ │ │ ├── stringify-date-time.ts │ │ │ │ └── tests/ │ │ │ │ ├── parse-date-time.spec.ts │ │ │ │ ├── split-date-time-string.spec.ts │ │ │ │ └── stringify-date-time.spec.ts │ │ │ ├── number/ │ │ │ │ ├── index.ts │ │ │ │ ├── number-mask.ts │ │ │ │ ├── number-params.ts │ │ │ │ ├── plugins/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── leading-zeroes-validation.plugin.ts │ │ │ │ │ ├── min-max.plugin.ts │ │ │ │ │ └── not-empty-integer.plugin.ts │ │ │ │ ├── processors/ │ │ │ │ │ ├── affixes-filter-preprocessor.ts │ │ │ │ │ ├── decimal-zero-padding-postprocessor.ts │ │ │ │ │ ├── empty-postprocessor.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── initialization-only-preprocessor.ts │ │ │ │ │ ├── leading-minus-deletion-preprocessor.ts │ │ │ │ │ ├── leading-zeroes-validation-postprocessor.ts │ │ │ │ │ ├── min-max-postprocessor.ts │ │ │ │ │ ├── non-removable-chars-deletion-preprocessor.ts │ │ │ │ │ ├── not-empty-integer-part-preprocessor.ts │ │ │ │ │ ├── number-prefix-postprocessor.ts │ │ │ │ │ ├── pseudo-character-preprocessor.ts │ │ │ │ │ ├── repeated-decimal-separator-preprocessor.ts │ │ │ │ │ ├── tests/ │ │ │ │ │ │ ├── leading-zeroes-validation-postprocessor.spec.ts │ │ │ │ │ │ └── not-empty-integer-part-preprocessor.spec.ts │ │ │ │ │ ├── thousand-separator-postprocessor.ts │ │ │ │ │ └── zero-precision-preprocessor.ts │ │ │ │ ├── tests/ │ │ │ │ │ └── number-mask.spec.ts │ │ │ │ └── utils/ │ │ │ │ ├── extract-affixes.ts │ │ │ │ ├── generate-mask-expression.ts │ │ │ │ ├── index.ts │ │ │ │ ├── number-parts.ts │ │ │ │ ├── parse-number.ts │ │ │ │ ├── stringify-number-without-exp.ts │ │ │ │ ├── stringify-number.ts │ │ │ │ ├── tests/ │ │ │ │ │ ├── parse-number.spec.ts │ │ │ │ │ ├── stringify-number-without-exp.spec.ts │ │ │ │ │ ├── stringify-number.spec.ts │ │ │ │ │ ├── to-number-parts.spec.ts │ │ │ │ │ └── validate-decimal-pseudo-separators.spec.ts │ │ │ │ ├── validate-decimal-pseudo-separators.ts │ │ │ │ └── with-number-defaults.ts │ │ │ └── time/ │ │ │ ├── index.ts │ │ │ ├── time-mask.ts │ │ │ ├── time-params.ts │ │ │ └── utils/ │ │ │ ├── index.ts │ │ │ ├── parse-time.ts │ │ │ ├── stringify-time.ts │ │ │ └── tests/ │ │ │ ├── parse-time.spec.ts │ │ │ └── stringify-time.spec.ts │ │ ├── plugins/ │ │ │ ├── add-on-focus.ts │ │ │ ├── caret-guard.ts │ │ │ ├── event-handler.ts │ │ │ ├── index.ts │ │ │ ├── reject-event.ts │ │ │ ├── remove-on-blur.ts │ │ │ ├── selection-change.ts │ │ │ └── time/ │ │ │ ├── meridiem-stepping.ts │ │ │ └── time-segments-stepping.ts │ │ ├── processors/ │ │ │ ├── colon-convert-preprocessor.ts │ │ │ ├── date-segments-zero-padding-postprocessor.ts │ │ │ ├── first-date-end-separator-preprocessor.ts │ │ │ ├── fullwidth-to-halfwidth-preprocessor.ts │ │ │ ├── index.ts │ │ │ ├── invalid-time-segment-insertion-preprocessor.ts │ │ │ ├── meridiem-processors.ts │ │ │ ├── min-max-date-postprocessor.ts │ │ │ ├── normalize-date-preprocessor.ts │ │ │ ├── postfix-postprocessor.ts │ │ │ ├── prefix-postprocessor.ts │ │ │ ├── tests/ │ │ │ │ ├── first-date-end-separator-preprocessor.spec.ts │ │ │ │ ├── normalize-date-preprocessor.spec.ts │ │ │ │ ├── postfix-postprocessor.spec.ts │ │ │ │ ├── prefix-postprocessor.spec.ts │ │ │ │ ├── valid-date-preprocessor.spec.ts │ │ │ │ └── with-placeholder.spec.ts │ │ │ ├── valid-date-preprocessor.ts │ │ │ ├── with-placeholder.ts │ │ │ └── zero-placeholders-preprocessor.ts │ │ ├── types/ │ │ │ ├── date-mode.ts │ │ │ ├── date-segments.ts │ │ │ ├── index.ts │ │ │ ├── time-mode.ts │ │ │ └── time-segments.ts │ │ └── utils/ │ │ ├── clamp.ts │ │ ├── count-digits.ts │ │ ├── date/ │ │ │ ├── append-date.ts │ │ │ ├── date-segment-value-length.ts │ │ │ ├── date-to-segments.ts │ │ │ ├── get-date-segments-order.ts │ │ │ ├── get-first-complete-date.ts │ │ │ ├── is-date-string-complete.ts │ │ │ ├── parse-date-range-string.ts │ │ │ ├── parse-date-string.ts │ │ │ ├── raise-segment-value-to-min.ts │ │ │ ├── segments-to-date.ts │ │ │ ├── tests/ │ │ │ │ ├── append-date.spec.ts │ │ │ │ ├── get-date-segment-value-length.spec.ts │ │ │ │ └── parse-date-range-string.spec.ts │ │ │ ├── to-date-string.ts │ │ │ └── validate-date-string.ts │ │ ├── dummy.ts │ │ ├── escape-reg-exp.ts │ │ ├── find-common-beginning-substr.ts │ │ ├── index.ts │ │ ├── is-empty.ts │ │ ├── pad-with-zeroes-until-valid.ts │ │ ├── tests/ │ │ │ ├── clamp.spec.ts │ │ │ ├── escape-reg-exp.spec.ts │ │ │ ├── find-common-beginning-substr.spec.ts │ │ │ ├── get-first-complete-date.spec.ts │ │ │ ├── is-empty.spec.ts │ │ │ ├── to-half-width-colon.spec.ts │ │ │ └── to-half-width-number.spec.ts │ │ ├── time/ │ │ │ ├── create-time-mask-expression.ts │ │ │ ├── enrich-time-segments-with-zeroes.ts │ │ │ ├── index.ts │ │ │ ├── pad-end-time-segments.ts │ │ │ ├── pad-start-time-segments.ts │ │ │ ├── pad-time-segments.ts │ │ │ ├── parse-time-string.ts │ │ │ ├── tests/ │ │ │ │ ├── enrich-time-segments-with-zeroes.spec.ts │ │ │ │ ├── parse-time-string.spec.ts │ │ │ │ └── to-time-string.spec.ts │ │ │ └── to-time-string.ts │ │ ├── to-half-width-colon.ts │ │ └── to-half-width-number.ts │ ├── phone/ │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ └── src/ │ │ ├── index.ts │ │ └── lib/ │ │ └── masks/ │ │ ├── index.ts │ │ └── phone/ │ │ ├── constants/ │ │ │ ├── index.ts │ │ │ └── template-filler.ts │ │ ├── index.ts │ │ ├── phone-mask-non-strict.ts │ │ ├── phone-mask-strict.ts │ │ ├── phone-mask.ts │ │ ├── processors/ │ │ │ ├── browser-autofill-preprocessor.ts │ │ │ ├── cut-init-country-code-preprocessor.ts │ │ │ ├── index.ts │ │ │ ├── paste-non-strict-phone-preprocessor.ts │ │ │ ├── paste-strict-phone-preprocessor.ts │ │ │ ├── phone-length-postprocessor.ts │ │ │ └── sanitize-phone-preprocessor.ts │ │ ├── tests/ │ │ │ ├── get-phone-template.spec.ts │ │ │ └── phone-mask.spec.ts │ │ └── utils/ │ │ ├── cut-phone-by-valid-length.ts │ │ ├── generate-phone-mask.ts │ │ ├── get-country-from-number.ts │ │ ├── get-phone-template.ts │ │ ├── index.ts │ │ └── select-template.ts │ ├── react/ │ │ ├── .babelrc │ │ ├── README.md │ │ ├── jest.config.ts │ │ ├── package.json │ │ ├── project.json │ │ └── src/ │ │ ├── index.ts │ │ └── lib/ │ │ ├── adaptControlledElement.tsx │ │ ├── tests/ │ │ │ ├── controlledInput.spec.tsx │ │ │ ├── elementPredicate.spec.tsx │ │ │ └── useMaskito.spec.tsx │ │ ├── useIsomorphicLayoutEffect.tsx │ │ └── useMaskito.tsx │ └── vue/ │ ├── README.md │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ └── src/ │ ├── index.ts │ └── lib/ │ ├── maskito.spec.ts │ └── maskito.ts ├── tsconfig.build.json ├── tsconfig.json └── tsconfig.spec.json
SYMBOL INDEX (503 symbols across 330 files)
FILE: projects/angular/src/lib/maskito.directive.ts
class MaskitoDirective (line 20) | class MaskitoDirective implements OnDestroy {
method constructor (line 57) | constructor() {
method ngOnDestroy (line 73) | public ngOnDestroy(): void {
method destroy (line 77) | private destroy(): void {
FILE: projects/angular/src/lib/maskito.pipe.ts
class MaskitoPipe (line 9) | class MaskitoPipe implements PipeTransform {
method transform (line 10) | public transform(value: unknown, maskitoOptions: MaskitoOptions | null...
FILE: projects/angular/src/lib/pattern.directive.ts
class MaskitoPattern (line 10) | class MaskitoPattern {
method maskitoPattern (line 13) | public set maskitoPattern(pattern: RegExp | string) {
FILE: projects/angular/src/lib/tests/maskito.directive.spec.ts
constant DIGIT_ONLY (line 12) | const DIGIT_ONLY: MaskitoOptions = {mask: /^\d*$/};
class TestHostComponent (line 15) | @Component({
function getDirective (line 33) | function getDirective(): MaskitoDirective {
function getMaskedElement (line 37) | function getMaskedElement(): Maskito | null {
function makeControlledPredicate (line 103) | function makeControlledPredicate(): {
FILE: projects/angular/src/lib/tests/maskito.spec.ts
class TestComponent (line 9) | @Component({
function getText (line 75) | function getText(): string {
function getValue (line 81) | function getValue(): string {
FILE: projects/core/src/lib/classes/mask-history.ts
method undo (line 13) | protected undo(): void {
method redo (line 22) | protected redo(): void {
method updateHistory (line 31) | protected updateHistory(state: ElementState): void {
method updateElement (line 55) | private updateElement(
FILE: projects/core/src/lib/classes/mask-model/mask-model.ts
class MaskModel (line 12) | class MaskModel implements ElementState {
method constructor (line 18) | constructor(
method addCharacters (line 33) | public addCharacters(newCharacters: string): void {
method deleteCharacters (line 89) | public deleteCharacters(): void {
method getMaskExpression (line 115) | private getMaskExpression(elementState: ElementState): MaskitoMaskExpr...
FILE: projects/core/src/lib/classes/mask-model/tests/dynamic-mask.spec.ts
constant EMPTY_STATE (line 7) | const EMPTY_STATE: ElementState = {
FILE: projects/core/src/lib/classes/mask-model/utils/apply-overwrite-mode.ts
function applyOverwriteMode (line 3) | function applyOverwriteMode(
FILE: projects/core/src/lib/classes/mask-model/utils/calibrate-value-by-mask.ts
function calibrateValueByMask (line 6) | function calibrateValueByMask(
FILE: projects/core/src/lib/classes/mask-model/utils/get-leading-fixed-characters.ts
function getLeadingFixedCharacters (line 4) | function getLeadingFixedCharacters(
FILE: projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-pattern.ts
function guessValidValueByPattern (line 6) | function guessValidValueByPattern(
FILE: projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-reg-exp.ts
function guessValidValueByRegExp (line 3) | function guessValidValueByRegExp(
FILE: projects/core/src/lib/classes/mask-model/utils/is-fixed-character.ts
function isFixedCharacter (line 1) | function isFixedCharacter(char: RegExp | string): char is string {
FILE: projects/core/src/lib/classes/mask-model/utils/remove-fixed-mask-characters.ts
function removeFixedMaskCharacters (line 4) | function removeFixedMaskCharacters(
FILE: projects/core/src/lib/classes/mask-model/utils/validate-value-with-mask.ts
function validateValueWithMask (line 4) | function validateValueWithMask(
FILE: projects/core/src/lib/constants/default-options.ts
constant MASKITO_DEFAULT_OPTIONS (line 3) | const MASKITO_DEFAULT_OPTIONS: Required<MaskitoOptions> = {
FILE: projects/core/src/lib/mask.ts
constant BUILT_IN_PLUGINS (line 24) | const BUILT_IN_PLUGINS = [createDoubleSpacePlugin(), createBrokenDefault...
class Maskito (line 26) | class Maskito extends MaskHistory {
method constructor (line 44) | constructor(
method destroy (line 170) | public destroy(): void {
method updateElementState (line 175) | protected updateElementState(
method elementState (line 189) | private get elementState(): ElementState {
method maxLength (line 198) | private get maxLength(): number {
method updateSelectionRange (line 204) | private updateSelectionRange([from, to]: SelectionRange): void {
method updateValue (line 215) | private updateValue(value: string): void {
method ensureValueFitsMask (line 225) | private ensureValueFitsMask(): void {
method dispatchInputEvent (line 232) | private dispatchInputEvent(
method handleDelete (line 247) | private handleDelete({
method handleInsert (line 288) | private handleInsert(event: TypedInputEvent, data: string): void {
method handleEnter (line 336) | private handleEnter(event: TypedInputEvent): void {
method clampState (line 342) | private clampState({value, selection}: ElementState): ElementState {
FILE: projects/core/src/lib/plugins/broken-prevent-default.plugin.ts
function createBrokenDefaultPlugin (line 16) | function createBrokenDefaultPlugin(): MaskitoPlugin {
FILE: projects/core/src/lib/plugins/change-event-plugin.ts
function maskitoChangeEventPlugin (line 3) | function maskitoChangeEventPlugin(): MaskitoPlugin {
FILE: projects/core/src/lib/plugins/double-space.plugin.ts
constant SPACE (line 6) | const SPACE = ' ';
function createDoubleSpacePlugin (line 32) | function createDoubleSpacePlugin(): MaskitoPlugin {
FILE: projects/core/src/lib/plugins/initial-calibration-plugin.ts
function maskitoInitialCalibrationPlugin (line 4) | function maskitoInitialCalibrationPlugin(
FILE: projects/core/src/lib/plugins/strict-composition-plugin.ts
function maskitoStrictCompositionPlugin (line 4) | function maskitoStrictCompositionPlugin(): MaskitoPlugin {
FILE: projects/core/src/lib/types/element-predicate.ts
type MaskitoElementPredicate (line 3) | type MaskitoElementPredicate = (
FILE: projects/core/src/lib/types/element-state.ts
type ElementState (line 3) | interface ElementState {
FILE: projects/core/src/lib/types/mask-options.ts
type MaskitoOptions (line 6) | interface MaskitoOptions {
FILE: projects/core/src/lib/types/mask-processors.ts
type MaskitoPreprocessor (line 3) | type MaskitoPreprocessor = (
type MaskitoPostprocessor (line 14) | type MaskitoPostprocessor = (
FILE: projects/core/src/lib/types/mask.ts
type MaskitoMaskExpression (line 3) | type MaskitoMaskExpression = Array<RegExp | string> | RegExp;
type MaskitoMask (line 5) | type MaskitoMask =
FILE: projects/core/src/lib/types/maskito-element.ts
type TextfieldLike (line 1) | type TextfieldLike = Pick<
type MaskitoElement (line 10) | type MaskitoElement = HTMLElement & TextfieldLike;
FILE: projects/core/src/lib/types/plugin.ts
type MaskitoPlugin (line 4) | type MaskitoPlugin = (
FILE: projects/core/src/lib/types/selection-range.ts
type SelectionRange (line 1) | type SelectionRange = readonly [from: number, to: number];
FILE: projects/core/src/lib/types/typed-input-event.ts
type TypedInputEvent (line 1) | interface TypedInputEvent extends InputEvent {
FILE: projects/core/src/lib/utils/content-editable.ts
class ContentEditableAdapter (line 5) | class ContentEditableAdapter implements TextfieldLike {
method constructor (line 8) | constructor(private readonly element: HTMLElement) {}
method value (line 10) | public get value(): string {
method value (line 14) | public set value(value) {
method selectionStart (line 19) | public get selectionStart(): number | null {
method selectionEnd (line 23) | public get selectionEnd(): number | null {
method setSelectionRange (line 27) | public setSelectionRange(from: number | null, to: number | null): void {
method select (line 31) | public select(): void {
function maskitoAdaptContentEditable (line 36) | function maskitoAdaptContentEditable(element: HTMLElement): MaskitoEleme...
FILE: projects/core/src/lib/utils/dom/event-listener.ts
class EventListener (line 3) | class EventListener {
method constructor (line 6) | constructor(private readonly element: HTMLElement) {}
method listen (line 8) | public listen<E extends keyof HTMLElementEventMap>(
method destroy (line 25) | public destroy(): void {
FILE: projects/core/src/lib/utils/dom/get-content-editable-selection.ts
function getContentEditableSelection (line 3) | function getContentEditableSelection(element: HTMLElement): SelectionRan...
FILE: projects/core/src/lib/utils/dom/history-events.ts
function isRedo (line 3) | function isRedo(event: KeyboardEvent): boolean {
function isUndo (line 11) | function isUndo(event: KeyboardEvent): boolean {
FILE: projects/core/src/lib/utils/dom/hotkey.ts
function isHotkey (line 27) | function isHotkey(
FILE: projects/core/src/lib/utils/dom/set-content-editable-selection.ts
function setContentEditableSelection (line 3) | function setContentEditableSelection(
FILE: projects/core/src/lib/utils/dom/update-element.ts
function maskitoUpdateElement (line 15) | function maskitoUpdateElement(
FILE: projects/core/src/lib/utils/element-states-equality.ts
function areElementValuesEqual (line 3) | function areElementValuesEqual(
function areElementStatesEqual (line 10) | function areElementStatesEqual(
FILE: projects/core/src/lib/utils/get-line-selection.ts
function getLineSelection (line 3) | function getLineSelection(
FILE: projects/core/src/lib/utils/get-not-empty-selection.ts
function getNotEmptySelection (line 3) | function getNotEmptySelection(
FILE: projects/core/src/lib/utils/get-word-selection.ts
constant TRAILING_SPACES_REG (line 3) | const TRAILING_SPACES_REG = /\s+$/g;
constant LEADING_SPACES_REG (line 4) | const LEADING_SPACES_REG = /^\s+/g;
constant SPACE_REG (line 5) | const SPACE_REG = /\s/;
function getWordSelection (line 7) | function getWordSelection(
FILE: projects/core/src/lib/utils/pipe.ts
function maskitoPipe (line 20) | function maskitoPipe<State extends object, Args extends unknown[]>(
FILE: projects/core/src/lib/utils/transform.ts
function maskitoTransform (line 12) | function maskitoTransform(
FILE: projects/demo-integrations/cypress.config.ts
constant CYPRESS_CONFIG (line 5) | const CYPRESS_CONFIG: Cypress.ConfigOptions = {
method setupNodeEvents (line 17) | setupNodeEvents(on, config) {
FILE: projects/demo-integrations/src/support/assertions/index.ts
type Chainer (line 5) | interface Chainer<Subject> {
FILE: projects/demo-integrations/src/support/commands/index.ts
type Chainable (line 8) | interface Chainable<Subject> {
FILE: projects/demo-integrations/src/support/commands/paste.ts
function paste (line 7) | function paste<T extends Cypress.PrevSubjectMap['element']>(
FILE: projects/demo-integrations/src/support/commands/smart-tick.ts
function smartTick (line 3) | function smartTick<T extends Cypress.PrevSubjectMap<void>[Cypress.PrevSu...
FILE: projects/demo-integrations/src/support/component.ts
type Chainable (line 10) | interface Chainable<Subject> {
FILE: projects/demo-integrations/src/support/constants/real-events-support.ts
constant BROWSER_SUPPORTS_REAL_EVENTS (line 9) | const BROWSER_SUPPORTS_REAL_EVENTS: Cypress.TestConfigOverrides = {
FILE: projects/demo-integrations/src/tests/addons/phone/phone-basic.cy.ts
function openCountry (line 283) | function openCountry(code: string): void {
FILE: projects/demo-integrations/src/tests/addons/phone/phone-non-strict.cy.ts
function openCountry (line 216) | function openCountry(code: string): void {
FILE: projects/demo-integrations/src/tests/addons/phone/phone-separator.cy.ts
function openCountry (line 153) | function openCountry(code: string): void {
FILE: projects/demo-integrations/src/tests/component-testing/angular-predicate/angular-predicate.cy.ts
class ComplexTextfield (line 69) | @Component({
method constructor (line 87) | constructor() {
class TestComponent (line 137) | @Component({
method constructor (line 152) | constructor() {
FILE: projects/demo-integrations/src/tests/component-testing/angular-predicate/multi-test.component.ts
class MultiTestInputComponent (line 23) | class MultiTestInputComponent {
FILE: projects/demo-integrations/src/tests/component-testing/native-max-length/native-maxlength-attribute.cy.ts
class Sandbox (line 176) | @Component({
method clear (line 197) | protected clear(): void {
FILE: projects/demo-integrations/src/tests/component-testing/native-select-method/native-select-method.cy.ts
class TestComponent (line 22) | class TestComponent {
FILE: projects/demo-integrations/src/tests/component-testing/number/runtime-postfix-changes/sandbox.component.ts
class TestPipe4 (line 17) | class TestPipe4 implements PipeTransform {
method transform (line 18) | public transform(postfix: string): MaskitoOptions {
class Sandbox (line 43) | class Sandbox {
FILE: projects/demo-integrations/src/tests/component-testing/phone/phone-with-initial-value.cy.ts
function createMaskitoOptions (line 10) | function createMaskitoOptions(): MaskitoOptions {
FILE: projects/demo-integrations/src/tests/component-testing/react/async-predicate-options-race/reactApp.tsx
constant SWITCH_OPTIONS_TIME (line 7) | const SWITCH_OPTIONS_TIME = 1_000;
constant PREDICATE_RESOLVING_TIME (line 8) | const PREDICATE_RESOLVING_TIME = 2_000;
FILE: projects/demo-integrations/src/tests/component-testing/react/change-event/changeEvent.cy.tsx
function App (line 13) | function App(): JSX.Element {
function App (line 57) | function App(): JSX.Element {
function App (line 116) | function App(): JSX.Element {
FILE: projects/demo-integrations/src/tests/component-testing/utils.ts
class TestInput (line 28) | class TestInput {
FILE: projects/demo-integrations/src/tests/kit/number/utils.ts
function openNumberPage (line 3) | function openNumberPage(queryParams = ''): void {
FILE: projects/demo-integrations/src/tests/utils.ts
function range (line 3) | function range(from: number, to: number): number[] {
function withCaretLabel (line 7) | function withCaretLabel(value: string, caretIndex: number): string {
function repeatKey (line 11) | function repeatKey<T extends Parameters<typeof realPress>[0]>(
FILE: projects/demo/esbuild-plugins/maskito-as-taiga-ui-dep.plugin.js
method setup (line 14) | setup(build) {
FILE: projects/demo/esbuild-plugins/vue-esm.plugin.js
method setup (line 13) | setup(build) {
FILE: projects/demo/src/app/app.component.ts
class App (line 48) | class App {
method constructor (line 51) | constructor() {
FILE: projects/demo/src/app/app.config.ts
constant APP_CONFIG (line 35) | const APP_CONFIG: ApplicationConfig = {
FILE: projects/demo/src/app/app.routes.ts
constant ROUTES (line 7) | const ROUTES: Routes = [
FILE: projects/demo/src/app/modules/example-primary-tabs-icons/angular-logo.component.ts
class AngularLogoComponent (line 10) | class AngularLogoComponent {}
constant ANGULAR_LOGO (line 12) | const ANGULAR_LOGO = new PolymorpheusComponent(AngularLogoComponent);
FILE: projects/demo/src/app/modules/example-primary-tabs-icons/javascript-logo.component.ts
class JavaScriptLogoComponent (line 10) | class JavaScriptLogoComponent {}
constant JAVASCRIPT_LOGO (line 12) | const JAVASCRIPT_LOGO = new PolymorpheusComponent(JavaScriptLogoComponent);
FILE: projects/demo/src/app/modules/example-primary-tabs-icons/react-logo.component.ts
class ReactLogoComponent (line 10) | class ReactLogoComponent {}
constant REACT_LOGO (line 12) | const REACT_LOGO = new PolymorpheusComponent(ReactLogoComponent);
FILE: projects/demo/src/app/modules/example-primary-tabs-icons/vue-logo.component.ts
class VueLogoComponent (line 10) | class VueLogoComponent {}
constant VUE_LOGO (line 12) | const VUE_LOGO = new PolymorpheusComponent(VueLogoComponent);
FILE: projects/demo/src/app/modules/logo/logo.component.ts
class LogoComponent (line 13) | class LogoComponent {}
constant LOGO_CONTENT (line 15) | const LOGO_CONTENT = new PolymorpheusComponent(LogoComponent);
FILE: projects/demo/src/app/server-error-handler.ts
constant KNOWN_ISSUES (line 4) | const KNOWN_ISSUES: ReadonlyArray<RegExp | string> = [
class ServerErrorHandler (line 25) | class ServerErrorHandler implements ErrorHandler {
method handleError (line 26) | public handleError(error: Error | string): void {
FILE: projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/angular-default-tab.ts
constant ANGULAR_DEFAULT_TAB (line 1) | const ANGULAR_DEFAULT_TAB = `import {Component} from '@angular/core';
FILE: projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/js-default-tab.ts
constant JS_DEFAULT_TAB (line 1) | const JS_DEFAULT_TAB = `import {Maskito, MaskitoOptions} from '@maskito/...
FILE: projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/react-default-tab.ts
constant REACT_DEFAULT_TAB (line 1) | const REACT_DEFAULT_TAB = `import * as React from 'react';
FILE: projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/vue-default-tab.ts
constant VUE_DEFAULT_TAB (line 1) | const VUE_DEFAULT_TAB = `import {createApp} from 'vue';
FILE: projects/demo/src/main.server.ts
method getPrerenderParams (line 35) | async getPrerenderParams() {
function withTabs (line 47) | function withTabs(path: string, tabs: string[]): ServerRoute {
FILE: projects/demo/src/pages/documentation/browser-support/browser-support.component.ts
class BrowserSupportComponent (line 11) | class BrowserSupportComponent {
FILE: projects/demo/src/pages/documentation/core-concepts-overview/core-concepts-overview.component.ts
class CoreConceptsOverviewDocPageComponent (line 27) | class CoreConceptsOverviewDocPageComponent {
FILE: projects/demo/src/pages/documentation/element-state/element-state.component.ts
class ElementStateDocPageComponent (line 13) | class ElementStateDocPageComponent {
FILE: projects/demo/src/pages/documentation/mask-expression/mask-expression.component.ts
class MaskExpressionDocPageComponent (line 15) | class MaskExpressionDocPageComponent {
FILE: projects/demo/src/pages/documentation/maskito-libraries/maskito-libraries.component.ts
class MaskitoLibrariesDocPageComponent (line 13) | class MaskitoLibrariesDocPageComponent {
FILE: projects/demo/src/pages/documentation/next-steps/next-steps.component.ts
class NextStepsComponent (line 13) | class NextStepsComponent {
FILE: projects/demo/src/pages/documentation/overwrite-mode/examples/dynamic/component.ts
class OverwriteModeDocExample3 (line 31) | class OverwriteModeDocExample3 {
FILE: projects/demo/src/pages/documentation/overwrite-mode/examples/replace/component.ts
class OverwriteModeDocExample2 (line 34) | class OverwriteModeDocExample2 {
FILE: projects/demo/src/pages/documentation/overwrite-mode/examples/shift/component.ts
class OverwriteModeDocExample1 (line 34) | class OverwriteModeDocExample1 {
FILE: projects/demo/src/pages/documentation/overwrite-mode/overwrite-mode.component.ts
class OverwriteModeDocPageComponent (line 26) | class OverwriteModeDocPageComponent {
FILE: projects/demo/src/pages/documentation/plugins/examples/1-initial-calibration/component.ts
class PluginsDocExample2 (line 26) | class PluginsDocExample2 {
FILE: projects/demo/src/pages/documentation/plugins/examples/2-strict-composition/component.ts
class PluginsDocExample3 (line 22) | class PluginsDocExample3 {
FILE: projects/demo/src/pages/documentation/plugins/examples/3-change-event/component.ts
class PluginsDocExample4 (line 28) | class PluginsDocExample4 {
method log (line 32) | protected log(anything: any): void {
FILE: projects/demo/src/pages/documentation/plugins/plugins.component.ts
class PluginsDocPageComponent (line 38) | class PluginsDocPageComponent {
FILE: projects/demo/src/pages/documentation/processors/processors.component.ts
class ProcessorsDocPageComponent (line 15) | class ProcessorsDocPageComponent {
FILE: projects/demo/src/pages/documentation/real-world-form/index.ts
constant MONEY_AMOUNT_MASK (line 22) | const MONEY_AMOUNT_MASK = maskitoNumberOptionsGenerator({
constant ONLY_LATIN_LETTERS_RE (line 28) | const ONLY_LATIN_LETTERS_RE = /^[a-z]+$/i;
class RealWorldForm (line 46) | class RealWorldForm {
method countryIsoCode (line 98) | protected get countryIsoCode(): string {
method log (line 102) | protected log(something: any): void {
FILE: projects/demo/src/pages/documentation/supported-input-types/examples/password/component.ts
class InputPasswordDocExample (line 35) | class InputPasswordDocExample {
FILE: projects/demo/src/pages/documentation/supported-input-types/examples/search/component.ts
class InputSearchDocExample (line 33) | class InputSearchDocExample {
FILE: projects/demo/src/pages/documentation/supported-input-types/examples/tel/component.ts
class InputTelDocExample (line 44) | class InputTelDocExample {
FILE: projects/demo/src/pages/documentation/supported-input-types/examples/text/component.ts
class InputTextDocExample (line 34) | class InputTextDocExample {
FILE: projects/demo/src/pages/documentation/supported-input-types/examples/url/component.ts
class InputURLDocExample (line 33) | class InputURLDocExample {
FILE: projects/demo/src/pages/documentation/supported-input-types/supported-input-types.component.ts
class SupportedInputTypesDocPageComponent (line 27) | class SupportedInputTypesDocPageComponent {
method getInput (line 58) | protected getInput(type: HTMLInputElement['type']): string {
FILE: projects/demo/src/pages/documentation/transformer/transformer.component.ts
class TransformerDocPageComponent (line 13) | class TransformerDocPageComponent {
FILE: projects/demo/src/pages/documentation/what-is-maskito/what-is-maskito.component.ts
class WhatIsMaskitoDocPageComponent (line 25) | class WhatIsMaskitoDocPageComponent {
FILE: projects/demo/src/pages/frameworks/angular/angular-doc.component.ts
class AngularDocPageComponent (line 33) | class AngularDocPageComponent {
FILE: projects/demo/src/pages/frameworks/angular/examples/1-nested/component.ts
class NestedDocExample1 (line 13) | class NestedDocExample1 {
FILE: projects/demo/src/pages/frameworks/angular/examples/2-nested/component.ts
class NestedDocExample2 (line 13) | class NestedDocExample2 {
FILE: projects/demo/src/pages/frameworks/angular/examples/3-programmatically/component.ts
class ProgrammaticallyDocExample3 (line 12) | class ProgrammaticallyDocExample3 {
method setValue (line 19) | protected setValue(): void {
FILE: projects/demo/src/pages/frameworks/angular/examples/4-pipe/component.ts
class PipeDocExample4 (line 11) | class PipeDocExample4 {
FILE: projects/demo/src/pages/frameworks/angular/examples/5-custom-unmask-handler/index.ts
constant NUMBER_PARAMS (line 13) | const NUMBER_PARAMS: MaskitoNumberParams = {
class UnmaskDocExample5 (line 25) | class UnmaskDocExample5 {
FILE: projects/demo/src/pages/frameworks/angular/examples/5-custom-unmask-handler/unmask.directive.ts
class UnmaskDirective (line 11) | class UnmaskDirective implements AfterViewInit {
method ngAfterViewInit (line 23) | public ngAfterViewInit(): void {
FILE: projects/demo/src/pages/frameworks/angular/examples/6-pattern/component.ts
class PatternDocExample6 (line 11) | class PatternDocExample6 {
FILE: projects/demo/src/pages/frameworks/react/examples/1-use-maskito-basic-usage/example.component.tsx
class ReactExample1 (line 15) | class ReactExample1 {
method constructor (line 16) | constructor() {
FILE: projects/demo/src/pages/frameworks/react/examples/2-element-predicate/example.component.tsx
class ReactExample2 (line 15) | class ReactExample2 {
method constructor (line 16) | constructor() {
FILE: projects/demo/src/pages/frameworks/react/react-doc.component.ts
class ReactDocPageComponent (line 26) | class ReactDocPageComponent {
FILE: projects/demo/src/pages/frameworks/vue/examples/vue-1/component.ts
class VueExample1 (line 10) | class VueExample1 {
FILE: projects/demo/src/pages/frameworks/vue/vue-doc.component.ts
class VueDocPageComponent (line 15) | class VueDocPageComponent {
FILE: projects/demo/src/pages/kit/date-range/date-range-mask-doc.component.ts
type GeneratorOptions (line 21) | type GeneratorOptions = Required<
class DateRangeMaskDocComponent (line 42) | class DateRangeMaskDocComponent implements GeneratorOptions {
method getPlaceholder (line 115) | protected getPlaceholder(
method updateOptions (line 125) | protected updateOptions(): void {
method updateDate (line 129) | protected updateDate(): void {
FILE: projects/demo/src/pages/kit/date-range/examples/1-date-localization/component.ts
class DateRangeMaskDocExample1 (line 36) | class DateRangeMaskDocExample1 {
method hint (line 47) | protected get hint(): string {
FILE: projects/demo/src/pages/kit/date-range/examples/2-min-max/component.ts
class DateRangeMaskDocExample2 (line 33) | class DateRangeMaskDocExample2 {
FILE: projects/demo/src/pages/kit/date-range/examples/3-min-max-length/component.ts
class DateRangeMaskDocExample3 (line 36) | class DateRangeMaskDocExample3 {
FILE: projects/demo/src/pages/kit/date-range/examples/4-range-separator/component.ts
class DateRangeMaskDocExample4 (line 33) | class DateRangeMaskDocExample4 {
FILE: projects/demo/src/pages/kit/date-time/date-time-mask-doc.component.ts
class DateTimeMaskDocComponent (line 42) | class DateTimeMaskDocComponent implements Required<MaskitoDateTimeParams> {
method getPlaceholder (line 117) | protected getPlaceholder(
method updateOptions (line 126) | protected updateOptions(): void {
method updateDate (line 130) | protected updateDate(): void {
FILE: projects/demo/src/pages/kit/date-time/examples/1-date-time-localization/component.ts
class DateTimeMaskDocExample1 (line 33) | class DateTimeMaskDocExample1 {
FILE: projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/component.ts
class DateTimeMaskDocExample2 (line 33) | class DateTimeMaskDocExample2 {
FILE: projects/demo/src/pages/kit/date-time/examples/3-min-max/component.ts
class DateTimeMaskDocExample3 (line 33) | class DateTimeMaskDocExample3 {
FILE: projects/demo/src/pages/kit/date-time/examples/4-time-step/component.ts
class DateTimeMaskDocExample4 (line 33) | class DateTimeMaskDocExample4 {
FILE: projects/demo/src/pages/kit/date-time/examples/5-am-pm/component.ts
class DateTimeMaskDocExample5 (line 32) | class DateTimeMaskDocExample5 {
FILE: projects/demo/src/pages/kit/date/date-mask-doc.component.ts
class DateMaskDocComponent (line 35) | class DateMaskDocComponent implements Required<MaskitoDateParams> {
method updateDate (line 83) | protected updateDate(): void {
method updateOptions (line 89) | protected updateOptions(): void {
FILE: projects/demo/src/pages/kit/date/examples/1-localization/component.ts
class DateMaskDocExample1 (line 33) | class DateMaskDocExample1 {
FILE: projects/demo/src/pages/kit/date/examples/2-min-max/component.ts
class DateMaskDocExample2 (line 33) | class DateMaskDocExample2 {
FILE: projects/demo/src/pages/kit/number/examples/1-high-precision/component.ts
class NumberMaskDocExample1 (line 28) | class NumberMaskDocExample1 {
FILE: projects/demo/src/pages/kit/number/examples/2-separators/component.ts
class NumberMaskDocExample2 (line 27) | class NumberMaskDocExample2 {
FILE: projects/demo/src/pages/kit/number/examples/3-postfix/component.ts
class NumberMaskDocExample3 (line 31) | class NumberMaskDocExample3 {
FILE: projects/demo/src/pages/kit/number/examples/4-decimal-zero-padding/component.ts
class NumberMaskDocExample4 (line 26) | class NumberMaskDocExample4 {
FILE: projects/demo/src/pages/kit/number/examples/5-custom-minus-sign/components.ts
class NumberMaskDocExample5 (line 30) | class NumberMaskDocExample5 {
FILE: projects/demo/src/pages/kit/number/examples/6-minus-before-prefix/components.ts
class NumberMaskDocExample6 (line 30) | class NumberMaskDocExample6 {
FILE: projects/demo/src/pages/kit/number/examples/7-dynamic-decimal-zero-padding/component.ts
class NumberMaskDocExample7 (line 44) | class NumberMaskDocExample7 {
method getMaskOptions (line 49) | protected getMaskOptions(decimalZeroPadding: boolean): MaskitoOptions {
method handleBeforeInput (line 53) | protected handleBeforeInput(event: Event): void {
method getNotEmptySelection (line 72) | private getNotEmptySelection(
FILE: projects/demo/src/pages/kit/number/examples/7-dynamic-decimal-zero-padding/mask.ts
function getMaskitoOptions (line 4) | function getMaskitoOptions(decimalZeroPadding: boolean): MaskitoOptions {
FILE: projects/demo/src/pages/kit/number/examples/8-thousand-separator-pattern/component.ts
class NumberMaskDocExample8 (line 27) | class NumberMaskDocExample8 {
FILE: projects/demo/src/pages/kit/number/examples/9-thousand-separator-pattern-intl/component.ts
class NumberMaskDocExample9 (line 27) | class NumberMaskDocExample9 {
FILE: projects/demo/src/pages/kit/number/number-mask-doc.component.ts
type GeneratorParams (line 28) | type GeneratorParams = Omit<
class NumberMaskDocComponent (line 57) | class NumberMaskDocComponent implements GeneratorParams {
method updateOptions (line 199) | protected updateOptions(): void {
method calculateMask (line 203) | private calculateMask(params: GeneratorParams): MaskitoOptions {
FILE: projects/demo/src/pages/kit/plugins/examples/1-selection-handler/component.ts
class KitPluginsDocExample1 (line 29) | class KitPluginsDocExample1 {
FILE: projects/demo/src/pages/kit/plugins/examples/2-caret-guard/component.ts
class KitPluginsDocExample2 (line 26) | class KitPluginsDocExample2 {
FILE: projects/demo/src/pages/kit/plugins/examples/3-event-handlers/component.ts
class KitPluginsDocExample3 (line 29) | class KitPluginsDocExample3 {
FILE: projects/demo/src/pages/kit/plugins/examples/4-reject/component.ts
class KitPluginsDocExample4 (line 27) | class KitPluginsDocExample4 {
FILE: projects/demo/src/pages/kit/plugins/kit-plugins-doc.component.ts
class KitPluginsDocComponent (line 28) | class KitPluginsDocComponent {
FILE: projects/demo/src/pages/kit/time/examples/1-modes/component.ts
class TimeMaskDocExample1 (line 33) | class TimeMaskDocExample1 {
FILE: projects/demo/src/pages/kit/time/examples/2-am-pm/component.ts
class TimeMaskDocExample2 (line 32) | class TimeMaskDocExample2 {
FILE: projects/demo/src/pages/kit/time/examples/3-step/component.ts
class TimeMaskDocExample3 (line 33) | class TimeMaskDocExample3 {
FILE: projects/demo/src/pages/kit/time/examples/4-affixes/component.ts
class TimeMaskDocExample4 (line 32) | class TimeMaskDocExample4 {
FILE: projects/demo/src/pages/kit/time/examples/5-time-segments-min-max/component.ts
class TimeMaskDocExample5 (line 33) | class TimeMaskDocExample5 {
FILE: projects/demo/src/pages/kit/time/time-mask-doc.component.ts
class TimeMaskDocComponent (line 44) | class TimeMaskDocComponent implements Required<MaskitoTimeParams> {
method updateOptions (line 119) | protected updateOptions(): void {
FILE: projects/demo/src/pages/pages.ts
constant DEMO_PAGES (line 4) | const DEMO_PAGES: TuiDocRoutePages = [
FILE: projects/demo/src/pages/phone/examples/1-basic/component.ts
class PhoneMaskDocExample1 (line 33) | class PhoneMaskDocExample1 {
FILE: projects/demo/src/pages/phone/examples/2-validation/component.ts
function phoneValidator (line 19) | function phoneValidator(countryCode: CountryCode): ValidatorFn {
class PhoneMaskDocExample2 (line 59) | class PhoneMaskDocExample2 {
FILE: projects/demo/src/pages/phone/examples/3-non-strict/component.ts
class PhoneMaskDocExample3 (line 49) | class PhoneMaskDocExample3 {
method countryIsoCode (line 60) | protected get countryIsoCode(): string {
FILE: projects/demo/src/pages/phone/examples/4-lazy-metadata/component.ts
class PhoneMaskDocExample4 (line 33) | class PhoneMaskDocExample4 implements OnInit {
method ngOnInit (line 37) | public ngOnInit(): void {
FILE: projects/demo/src/pages/phone/examples/5-focus-blur-events/component.ts
class PhoneMaskDocExample5 (line 47) | class PhoneMaskDocExample5 {
FILE: projects/demo/src/pages/phone/examples/6-national-format/component.ts
class PhoneMaskDocExample6 (line 47) | class PhoneMaskDocExample6 {
FILE: projects/demo/src/pages/phone/phone-doc.component.ts
type GeneratorOptions (line 36) | type GeneratorOptions = Required<Parameters<typeof maskitoPhoneOptionsGe...
type MetadataName (line 38) | type MetadataName = keyof typeof metadataSets;
class PhoneDocComponent (line 61) | class PhoneDocComponent implements GeneratorOptions {
method metadata (line 131) | public get metadata(): MetadataJson {
method pattern (line 140) | protected get pattern(): string {
method updateOptions (line 148) | protected updateOptions(): void {
method computeOptions (line 152) | private computeOptions(): Required<MaskitoOptions> {
FILE: projects/demo/src/pages/recipes/card/card-doc.component.ts
class CardDocComponent (line 15) | class CardDocComponent {
FILE: projects/demo/src/pages/recipes/card/examples/1-basic/component.ts
class CardDocExample1 (line 16) | class CardDocExample1 {
FILE: projects/demo/src/pages/recipes/content-editable/content-editable-doc.component.ts
class ContentEditableDocComponent (line 23) | class ContentEditableDocComponent {
FILE: projects/demo/src/pages/recipes/content-editable/examples/1-time/component.ts
class ContentEditableDocExample1 (line 23) | class ContentEditableDocExample1 {
FILE: projects/demo/src/pages/recipes/content-editable/examples/2-multi-line/component.ts
class ContentEditableDocExample2 (line 29) | class ContentEditableDocExample2 {
FILE: projects/demo/src/pages/recipes/network-address/examples/1-ipv6/component.ts
class NetworkAddressDocExample1 (line 25) | class NetworkAddressDocExample1 {
FILE: projects/demo/src/pages/recipes/network-address/examples/1-ipv6/mask.ts
constant HEX_GROUP (line 3) | const HEX_GROUP = Array.from({length: 4}, () => /[0-9A-F]/i);
FILE: projects/demo/src/pages/recipes/network-address/examples/2-ipv4/component.ts
class NetworkAddressDocExample2 (line 26) | class NetworkAddressDocExample2 {
FILE: projects/demo/src/pages/recipes/network-address/examples/2-ipv4/mask.ts
constant MAX_OCTET_VALUE (line 3) | const MAX_OCTET_VALUE = 255;
constant MAX_OCTET_LENGTH (line 4) | const MAX_OCTET_LENGTH = 3;
constant MAX_OCTETS (line 5) | const MAX_OCTETS = 4;
constant SEPARATOR (line 6) | const SEPARATOR = '.';
constant DIGIT (line 7) | const DIGIT = /\d/;
FILE: projects/demo/src/pages/recipes/network-address/examples/3-mac/component.ts
class NetworkAddressDocExample3 (line 25) | class NetworkAddressDocExample3 {
FILE: projects/demo/src/pages/recipes/network-address/examples/3-mac/mask.ts
constant HEX_GROUP (line 3) | const HEX_GROUP = Array.from({length: 2}, () => /[0-9A-F]/i);
FILE: projects/demo/src/pages/recipes/network-address/network-address-doc.component.ts
class NetworkAddressDocComponent (line 20) | class NetworkAddressDocComponent {
FILE: projects/demo/src/pages/recipes/phone/examples/1-us-phone/component.ts
class PhoneUSDocExample1 (line 43) | class PhoneUSDocExample1 {
FILE: projects/demo/src/pages/recipes/phone/examples/2-kz-phone/component.ts
class PhoneKZDocExample2 (line 14) | class PhoneKZDocExample2 {
FILE: projects/demo/src/pages/recipes/phone/examples/2-kz-phone/mask.ts
function createCompletePhoneInsertionPreprocessor (line 48) | function createCompletePhoneInsertionPreprocessor(): MaskitoPreprocessor {
FILE: projects/demo/src/pages/recipes/phone/phone-doc.component.ts
class PhoneDocComponent (line 16) | class PhoneDocComponent {
FILE: projects/demo/src/pages/recipes/placeholder/examples/1-cvc-code/component.ts
class PlaceholderDocExample1 (line 32) | class PlaceholderDocExample1 {
FILE: projects/demo/src/pages/recipes/placeholder/examples/2-phone/component.ts
class PlaceholderDocExample2 (line 43) | class PlaceholderDocExample2 {
FILE: projects/demo/src/pages/recipes/placeholder/examples/2-phone/mask.ts
constant PLACEHOLDER (line 13) | const PLACEHOLDER = '+ ( ) ___-____';
FILE: projects/demo/src/pages/recipes/placeholder/examples/3-date/component.ts
class PlaceholderDocExample3 (line 32) | class PlaceholderDocExample3 {
FILE: projects/demo/src/pages/recipes/placeholder/examples/3-date/mask.ts
constant PLACEHOLDER (line 4) | const PLACEHOLDER = 'dd/mm/yyyy';
FILE: projects/demo/src/pages/recipes/placeholder/placeholder-doc.component.ts
class PlaceholderDocComponent (line 24) | class PlaceholderDocComponent {
FILE: projects/demo/src/pages/recipes/postfix/examples/1-pattern-mask/component.ts
class PostfixDocExample1 (line 26) | class PostfixDocExample1 {
FILE: projects/demo/src/pages/recipes/postfix/examples/2-postprocessor/component.ts
class PostfixDocExample2 (line 26) | class PostfixDocExample2 {
FILE: projects/demo/src/pages/recipes/postfix/postfix-doc.component.ts
class PostfixDocComponent (line 23) | class PostfixDocComponent {
FILE: projects/demo/src/pages/recipes/prefix/examples/1-pattern-mask/component.ts
class PrefixDocExample1 (line 26) | class PrefixDocExample1 {
FILE: projects/demo/src/pages/recipes/prefix/examples/2-postprocessor/component.ts
class PrefixDocExample2 (line 26) | class PrefixDocExample2 {
FILE: projects/demo/src/pages/recipes/prefix/prefix-doc.component.ts
class PrefixDocComponent (line 23) | class PrefixDocComponent {
FILE: projects/demo/src/pages/recipes/textarea/examples/1-latin/component.ts
class TextareaDocExample1 (line 24) | class TextareaDocExample1 {
FILE: projects/demo/src/pages/recipes/textarea/textarea-doc.component.ts
class TextareaDocComponent (line 15) | class TextareaDocComponent {
FILE: projects/demo/src/pages/stackblitz/components/stackblitz-edit-button/stackblitz-edit-button.component.ts
class StackblitzEditButtonComponent (line 22) | class StackblitzEditButtonComponent {}
FILE: projects/demo/src/pages/stackblitz/components/stackblitz-starter/stackblitz-starter.component.ts
class StackblitzStarterComponent (line 29) | class StackblitzStarterComponent implements OnInit {
method ngOnInit (line 33) | public ngOnInit(): void {
method openStackblitz (line 39) | protected async openStackblitz(): Promise<void> {
FILE: projects/demo/src/pages/stackblitz/stackblitz.service.ts
class StackblitzService (line 15) | class StackblitzService implements TuiCodeEditor {
method edit (line 29) | public async edit(
method openStarter (line 58) | public openStarter(
FILE: projects/kit/src/lib/constants/date-segment-max-values.ts
constant DATE_SEGMENTS_MAX_VALUES (line 3) | const DATE_SEGMENTS_MAX_VALUES: MaskitoDateSegments<number> = {
FILE: projects/kit/src/lib/constants/default-decimal-pseudo-separators.ts
constant DEFAULT_DECIMAL_PSEUDO_SEPARATORS (line 1) | const DEFAULT_DECIMAL_PSEUDO_SEPARATORS = ['.', ',', 'б', 'ю'];
FILE: projects/kit/src/lib/constants/default-min-max-dates.ts
constant DEFAULT_MIN_DATE (line 1) | const DEFAULT_MIN_DATE = new Date('0001-01-01T00:00');
constant DEFAULT_MAX_DATE (line 2) | const DEFAULT_MAX_DATE = new Date('9999-12-31T23:59:59.999');
FILE: projects/kit/src/lib/constants/default-pseudo-minuses.ts
constant DEFAULT_PSEUDO_MINUSES (line 9) | const DEFAULT_PSEUDO_MINUSES = [
FILE: projects/kit/src/lib/constants/default-time-segment-bounds.ts
constant DEFAULT_TIME_SEGMENT_MAX_VALUES (line 3) | const DEFAULT_TIME_SEGMENT_MAX_VALUES: MaskitoTimeSegments<number> = {
constant DEFAULT_TIME_SEGMENT_MIN_VALUES (line 10) | const DEFAULT_TIME_SEGMENT_MIN_VALUES: MaskitoTimeSegments<number> = {
FILE: projects/kit/src/lib/constants/meridiem.ts
constant ANY_MERIDIEM_CHARACTER_RE (line 3) | const ANY_MERIDIEM_CHARACTER_RE = new RegExp(`[${CHAR_NO_BREAK_SPACE}APM...
constant ALL_MERIDIEM_CHARACTERS_RE (line 4) | const ALL_MERIDIEM_CHARACTERS_RE = new RegExp(`${CHAR_NO_BREAK_SPACE}[AP...
FILE: projects/kit/src/lib/constants/time-fixed-characters.ts
constant TIME_FIXED_CHARACTERS (line 1) | const TIME_FIXED_CHARACTERS = [':', '.'];
FILE: projects/kit/src/lib/constants/time-segment-value-lengths.ts
constant TIME_SEGMENT_VALUE_LENGTHS (line 3) | const TIME_SEGMENT_VALUE_LENGTHS: MaskitoTimeSegments<number> = {
FILE: projects/kit/src/lib/constants/unicode-characters.ts
constant CHAR_NO_BREAK_SPACE (line 4) | const CHAR_NO_BREAK_SPACE = '\u00A0';
constant CHAR_ZERO_WIDTH_SPACE (line 9) | const CHAR_ZERO_WIDTH_SPACE = '\u200B';
constant CHAR_EN_DASH (line 16) | const CHAR_EN_DASH = '\u2013';
constant CHAR_EM_DASH (line 25) | const CHAR_EM_DASH = '\u2014';
constant CHAR_HYPHEN (line 34) | const CHAR_HYPHEN = '\u002D';
constant CHAR_MINUS (line 42) | const CHAR_MINUS = '\u2212';
constant CHAR_JP_HYPHEN (line 48) | const CHAR_JP_HYPHEN = '\u30FC';
constant CHAR_COLON (line 56) | const CHAR_COLON = '\u003A';
constant CHAR_JP_COLON (line 62) | const CHAR_JP_COLON = '\uFF1A';
FILE: projects/kit/src/lib/masks/date-range/constants.ts
constant POSSIBLE_DATE_RANGE_SEPARATOR (line 9) | const POSSIBLE_DATE_RANGE_SEPARATOR = [
constant MIN_DAY (line 17) | const MIN_DAY = 1;
constant MONTHS_IN_YEAR (line 19) | const MONTHS_IN_YEAR = 12;
FILE: projects/kit/src/lib/masks/date-range/date-range-mask.ts
function maskitoDateRangeOptionsGenerator (line 19) | function maskitoDateRangeOptionsGenerator({
FILE: projects/kit/src/lib/masks/date-range/processors/min-max-range-length-postprocessor.ts
function createMinMaxRangeLengthPostprocessor (line 18) | function createMinMaxRangeLengthPostprocessor({
FILE: projects/kit/src/lib/masks/date-range/processors/swap-dates-postprocessor.ts
function createSwapDatesPostprocessor (line 10) | function createSwapDatesPostprocessor({
FILE: projects/kit/src/lib/masks/date-time/constants/date-time-separator.ts
constant DATE_TIME_SEPARATOR (line 1) | const DATE_TIME_SEPARATOR = ', ';
constant POSSIBLE_DATE_TIME_SEPARATOR (line 2) | const POSSIBLE_DATE_TIME_SEPARATOR = [',', ' '];
FILE: projects/kit/src/lib/masks/date-time/date-time-mask.ts
function maskitoDateTimeOptionsGenerator (line 30) | function maskitoDateTimeOptionsGenerator({
FILE: projects/kit/src/lib/masks/date-time/date-time-params.ts
type MaskitoDateTimeParams (line 3) | interface MaskitoDateTimeParams {
FILE: projects/kit/src/lib/masks/date-time/postprocessors/min-max-date-time-postprocessor.ts
function createMinMaxDateTimePostprocessor (line 17) | function createMinMaxDateTimePostprocessor({
FILE: projects/kit/src/lib/masks/date-time/preprocessors/valid-date-time-preprocessor.ts
function createValidDateTimePreprocessor (line 8) | function createValidDateTimePreprocessor({
FILE: projects/kit/src/lib/masks/date-time/utils/is-date-time-string-complete.ts
function isDateTimeStringComplete (line 4) | function isDateTimeStringComplete(
FILE: projects/kit/src/lib/masks/date-time/utils/parse-date-time.ts
function maskitoParseDateTime (line 8) | function maskitoParseDateTime(
FILE: projects/kit/src/lib/masks/date-time/utils/split-date-time-string.ts
constant NON_DIGIT_PLACEHOLDER_RE (line 1) | const NON_DIGIT_PLACEHOLDER_RE = /[^dmy]/g;
constant LEADING_NON_DIGIT_RE (line 2) | const LEADING_NON_DIGIT_RE = /^\D*/;
function splitDateTimeString (line 4) | function splitDateTimeString(
FILE: projects/kit/src/lib/masks/date-time/utils/stringify-date-time.ts
function maskitoStringifyDateTime (line 8) | function maskitoStringifyDateTime(
FILE: projects/kit/src/lib/masks/date/date-mask.ts
function maskitoDateOptionsGenerator (line 13) | function maskitoDateOptionsGenerator({
FILE: projects/kit/src/lib/masks/date/date-params.ts
type MaskitoDateParams (line 3) | interface MaskitoDateParams {
FILE: projects/kit/src/lib/masks/date/utils/parse-date.ts
function maskitoParseDate (line 5) | function maskitoParseDate(
FILE: projects/kit/src/lib/masks/date/utils/stringify-date.ts
function maskitoStringifyDate (line 6) | function maskitoStringifyDate(
FILE: projects/kit/src/lib/masks/date/utils/to-date-segments.ts
function toDateSegments (line 9) | function toDateSegments(date: Date): MaskitoDateSegments {
FILE: projects/kit/src/lib/masks/number/number-mask.ts
function maskitoNumberOptionsGenerator (line 30) | function maskitoNumberOptionsGenerator(
FILE: projects/kit/src/lib/masks/number/number-params.ts
type MaskitoNumberParams (line 1) | interface MaskitoNumberParams extends Pick<
FILE: projects/kit/src/lib/masks/number/plugins/leading-zeroes-validation.plugin.ts
constant DUMMY_SELECTION (line 7) | const DUMMY_SELECTION = [0, 0] as const;
function createLeadingZeroesValidationPlugin (line 14) | function createLeadingZeroesValidationPlugin(
FILE: projects/kit/src/lib/masks/number/plugins/min-max.plugin.ts
function createMinMaxPlugin (line 12) | function createMinMaxPlugin(params: Required<MaskitoNumberParams>): Mask...
FILE: projects/kit/src/lib/masks/number/plugins/not-empty-integer.plugin.ts
function createNotEmptyIntegerPlugin (line 13) | function createNotEmptyIntegerPlugin(
FILE: projects/kit/src/lib/masks/number/processors/affixes-filter-preprocessor.ts
function createAffixesFilterPreprocessor (line 11) | function createAffixesFilterPreprocessor(
FILE: projects/kit/src/lib/masks/number/processors/decimal-zero-padding-postprocessor.ts
function createDecimalZeroPaddingPostprocessor (line 12) | function createDecimalZeroPaddingPostprocessor(
FILE: projects/kit/src/lib/masks/number/processors/empty-postprocessor.ts
function emptyPostprocessor (line 12) | function emptyPostprocessor(
FILE: projects/kit/src/lib/masks/number/processors/initialization-only-preprocessor.ts
function createInitializationOnlyPreprocessor (line 16) | function createInitializationOnlyPreprocessor(
FILE: projects/kit/src/lib/masks/number/processors/leading-minus-deletion-preprocessor.ts
function createLeadingMinusDeletionPreprocessor (line 11) | function createLeadingMinusDeletionPreprocessor(
FILE: projects/kit/src/lib/masks/number/processors/leading-zeroes-validation-postprocessor.ts
function createLeadingZeroesValidationPostprocessor (line 14) | function createLeadingZeroesValidationPostprocessor(
FILE: projects/kit/src/lib/masks/number/processors/min-max-postprocessor.ts
function createMinMaxPostprocessor (line 12) | function createMinMaxPostprocessor(
FILE: projects/kit/src/lib/masks/number/processors/non-removable-chars-deletion-preprocessor.ts
function createNonRemovableCharsDeletionPreprocessor (line 12) | function createNonRemovableCharsDeletionPreprocessor({
FILE: projects/kit/src/lib/masks/number/processors/not-empty-integer-part-preprocessor.ts
function createNotEmptyIntegerPartPreprocessor (line 11) | function createNotEmptyIntegerPartPreprocessor(
FILE: projects/kit/src/lib/masks/number/processors/number-prefix-postprocessor.ts
function createNumberPrefixPostprocessor (line 6) | function createNumberPrefixPostprocessor({
FILE: projects/kit/src/lib/masks/number/processors/pseudo-character-preprocessor.ts
function createPseudoCharactersPreprocessor (line 11) | function createPseudoCharactersPreprocessor({
FILE: projects/kit/src/lib/masks/number/processors/repeated-decimal-separator-preprocessor.ts
function createRepeatedDecimalSeparatorPreprocessor (line 12) | function createRepeatedDecimalSeparatorPreprocessor(
FILE: projects/kit/src/lib/masks/number/processors/tests/leading-zeroes-validation-postprocessor.spec.ts
constant DEFAULT_PARAMS (line 7) | const DEFAULT_PARAMS = {
FILE: projects/kit/src/lib/masks/number/processors/tests/not-empty-integer-part-preprocessor.spec.ts
constant EMPTY_ELEMENT_STATE (line 6) | const EMPTY_ELEMENT_STATE = {
constant DEFAULT_PARAMS (line 11) | const DEFAULT_PARAMS = {
FILE: projects/kit/src/lib/masks/number/processors/thousand-separator-postprocessor.ts
constant SPACE_REG (line 7) | const SPACE_REG = /\s/;
constant SPACE_GLOBAL_REG (line 8) | const SPACE_GLOBAL_REG = /\s/g;
function createThousandSeparatorPostprocessor (line 14) | function createThousandSeparatorPostprocessor(
FILE: projects/kit/src/lib/masks/number/processors/zero-precision-preprocessor.ts
function createZeroPrecisionPreprocessor (line 11) | function createZeroPrecisionPreprocessor(
FILE: projects/kit/src/lib/masks/number/utils/extract-affixes.ts
function extractAffixes (line 4) | function extractAffixes(
FILE: projects/kit/src/lib/masks/number/utils/generate-mask-expression.ts
function generateMaskExpression (line 6) | function generateMaskExpression({
function computeAllOptionalCharsRegExp (line 53) | function computeAllOptionalCharsRegExp(str: string): string {
FILE: projects/kit/src/lib/masks/number/utils/number-parts.ts
type NumberParts (line 5) | interface NumberParts {
function toNumberParts (line 14) | function toNumberParts(
function fromNumberParts (line 58) | function fromNumberParts(
FILE: projects/kit/src/lib/masks/number/utils/parse-number.ts
function maskitoParseNumber (line 21) | function maskitoParseNumber(
FILE: projects/kit/src/lib/masks/number/utils/stringify-number-without-exp.ts
constant LOCALE (line 4) | const LOCALE: Intl.Locale[] = [];
constant DEFAULT (line 5) | const DEFAULT = {
function stringifyNumberWithoutExp (line 41) | function stringifyNumberWithoutExp(value: bigint | number): string {
FILE: projects/kit/src/lib/masks/number/utils/stringify-number.ts
function maskitoStringifyNumber (line 9) | function maskitoStringifyNumber(
FILE: projects/kit/src/lib/masks/number/utils/tests/to-number-parts.spec.ts
constant DEFAULT_PARAMS (line 14) | const DEFAULT_PARAMS = {
FILE: projects/kit/src/lib/masks/number/utils/validate-decimal-pseudo-separators.ts
function validateDecimalPseudoSeparators (line 3) | function validateDecimalPseudoSeparators({
FILE: projects/kit/src/lib/masks/number/utils/with-number-defaults.ts
function withNumberDefaults (line 10) | function withNumberDefaults({
FILE: projects/kit/src/lib/masks/time/time-mask.ts
function maskitoTimeOptionsGenerator (line 25) | function maskitoTimeOptionsGenerator({
function cutExpression (line 98) | function cutExpression(
FILE: projects/kit/src/lib/masks/time/time-params.ts
type MaskitoTimeParams (line 3) | interface MaskitoTimeParams {
FILE: projects/kit/src/lib/masks/time/utils/parse-time.ts
function maskitoParseTime (line 12) | function maskitoParseTime(
FILE: projects/kit/src/lib/masks/time/utils/stringify-time.ts
function maskitoStringifyTime (line 12) | function maskitoStringifyTime(
FILE: projects/kit/src/lib/plugins/add-on-focus.ts
function maskitoAddOnFocusPlugin (line 5) | function maskitoAddOnFocusPlugin(value: string): MaskitoPlugin {
FILE: projects/kit/src/lib/plugins/caret-guard.ts
function maskitoCaretGuard (line 6) | function maskitoCaretGuard(
FILE: projects/kit/src/lib/plugins/event-handler.ts
function maskitoEventHandler (line 3) | function maskitoEventHandler(
FILE: projects/kit/src/lib/plugins/remove-on-blur.ts
function maskitoRemoveOnBlurPlugin (line 5) | function maskitoRemoveOnBlurPlugin(value: string): MaskitoPlugin {
FILE: projects/kit/src/lib/plugins/selection-change.ts
function maskitoSelectionChangeHandler (line 3) | function maskitoSelectionChangeHandler(
FILE: projects/kit/src/lib/plugins/time/meridiem-stepping.ts
function createMeridiemSteppingPlugin (line 6) | function createMeridiemSteppingPlugin(meridiemStartIndex: number): Maski...
FILE: projects/kit/src/lib/plugins/time/time-segments-stepping.ts
function createTimeSegmentsSteppingPlugin (line 6) | function createTimeSegmentsSteppingPlugin({
function createTimeSegmentsIndexes (line 58) | function createTimeSegmentsIndexes(
function getSegmentRange (line 69) | function getSegmentRange(mode: string, segment: string): [number, number] {
function getActiveSegment (line 75) | function getActiveSegment({
function updateSegmentValue (line 93) | function updateSegmentValue({
function mod (line 113) | function mod(value: number, min: number, max: number): number {
FILE: projects/kit/src/lib/processors/colon-convert-preprocessor.ts
function createColonConvertPreprocessor (line 8) | function createColonConvertPreprocessor(): MaskitoPreprocessor {
FILE: projects/kit/src/lib/processors/date-segments-zero-padding-postprocessor.ts
function createDateSegmentsZeroPaddingPostprocessor (line 7) | function createDateSegmentsZeroPaddingPostprocessor({
FILE: projects/kit/src/lib/processors/first-date-end-separator-preprocessor.ts
function createFirstDateEndSeparatorPreprocessor (line 10) | function createFirstDateEndSeparatorPreprocessor({
FILE: projects/kit/src/lib/processors/fullwidth-to-halfwidth-preprocessor.ts
function createFullWidthToHalfWidthPreprocessor (line 8) | function createFullWidthToHalfWidthPreprocessor(): MaskitoPreprocessor {
FILE: projects/kit/src/lib/processors/invalid-time-segment-insertion-preprocessor.ts
function createInvalidTimeSegmentInsertionPreprocessor (line 18) | function createInvalidTimeSegmentInsertionPreprocessor({
FILE: projects/kit/src/lib/processors/meridiem-processors.ts
function createMeridiemPreprocessor (line 11) | function createMeridiemPreprocessor(
function createMeridiemPostprocessor (line 42) | function createMeridiemPostprocessor(
FILE: projects/kit/src/lib/processors/min-max-date-postprocessor.ts
constant LEAP_YEAR (line 15) | const LEAP_YEAR = '1972';
function createMinMaxDatePostprocessor (line 17) | function createMinMaxDatePostprocessor({
FILE: projects/kit/src/lib/processors/normalize-date-preprocessor.ts
function normalizeDatePreprocessor (line 5) | function normalizeDatePreprocessor({
FILE: projects/kit/src/lib/processors/postfix-postprocessor.ts
function maskitoPostfixPostprocessorGenerator (line 5) | function maskitoPostfixPostprocessorGenerator(
FILE: projects/kit/src/lib/processors/prefix-postprocessor.ts
function maskitoPrefixPostprocessorGenerator (line 5) | function maskitoPrefixPostprocessorGenerator(
FILE: projects/kit/src/lib/processors/tests/normalize-date-preprocessor.spec.ts
function getCheckFunction (line 112) | function getCheckFunction(
FILE: projects/kit/src/lib/processors/tests/prefix-postprocessor.spec.ts
type ElementState (line 6) | type ElementState = ReturnType<MaskitoPostprocessor>;
FILE: projects/kit/src/lib/processors/valid-date-preprocessor.ts
function createValidDatePreprocessor (line 5) | function createValidDatePreprocessor({
FILE: projects/kit/src/lib/processors/with-placeholder.ts
function maskitoWithPlaceholder (line 9) | function maskitoWithPlaceholder(
FILE: projects/kit/src/lib/processors/zero-placeholders-preprocessor.ts
function createZeroPlaceholdersPreprocessor (line 3) | function createZeroPlaceholdersPreprocessor(postfix = ''): MaskitoPrepro...
FILE: projects/kit/src/lib/types/date-mode.ts
type MaskitoDateMode (line 1) | type MaskitoDateMode =
FILE: projects/kit/src/lib/types/date-segments.ts
type MaskitoDateSegments (line 1) | interface MaskitoDateSegments<T = string> {
FILE: projects/kit/src/lib/types/time-mode.ts
type MaskitoTimeMode (line 1) | type MaskitoTimeMode =
FILE: projects/kit/src/lib/types/time-segments.ts
type MaskitoTimeSegments (line 1) | interface MaskitoTimeSegments<T = string> {
FILE: projects/kit/src/lib/utils/clamp.ts
function clamp (line 4) | function clamp<T extends Date | bigint | number>(
function min (line 14) | function min<T extends Date | bigint | number>(x: T, ...values: T[]): T {
function max (line 18) | function max<T extends Date | bigint | number>(x: T, ...values: T[]): T {
FILE: projects/kit/src/lib/utils/count-digits.ts
function countDigits (line 1) | function countDigits(str: string): number {
FILE: projects/kit/src/lib/utils/date/append-date.ts
function appendDate (line 4) | function appendDate(
function getMonthDaysCount (line 65) | function getMonthDaysCount(month: number, isLeapYear: boolean): number {
function isLeapYear (line 79) | function isLeapYear(year: number): boolean {
FILE: projects/kit/src/lib/utils/date/date-to-segments.ts
function dateToSegments (line 3) | function dateToSegments(date: Date): MaskitoDateSegments & MaskitoTimeSe...
FILE: projects/kit/src/lib/utils/date/get-date-segments-order.ts
constant ALL_POSSIBLE_SEGMENTS (line 3) | const ALL_POSSIBLE_SEGMENTS: ReadonlyArray<keyof MaskitoDateSegments> = [
function getDateSegmentsOrder (line 9) | function getDateSegmentsOrder(
FILE: projects/kit/src/lib/utils/date/get-first-complete-date.ts
function getFirstCompleteDate (line 3) | function getFirstCompleteDate(
FILE: projects/kit/src/lib/utils/date/is-date-string-complete.ts
function isDateStringComplete (line 1) | function isDateStringComplete(
FILE: projects/kit/src/lib/utils/date/parse-date-range-string.ts
function parseDateRangeString (line 3) | function parseDateRangeString(
FILE: projects/kit/src/lib/utils/date/parse-date-string.ts
function parseDateString (line 3) | function parseDateString(
FILE: projects/kit/src/lib/utils/date/raise-segment-value-to-min.ts
function raiseSegmentValueToMin (line 4) | function raiseSegmentValueToMin(
FILE: projects/kit/src/lib/utils/date/segments-to-date.ts
function segmentsToDate (line 3) | function segmentsToDate(
FILE: projects/kit/src/lib/utils/date/to-date-string.ts
function toDateString (line 18) | function toDateString(
FILE: projects/kit/src/lib/utils/date/validate-date-string.ts
function validateDateString (line 8) | function validateDateString({
FILE: projects/kit/src/lib/utils/dummy.ts
function identity (line 1) | function identity<T>(x: T): T {
function noop (line 6) | function noop(): void {}
FILE: projects/kit/src/lib/utils/escape-reg-exp.ts
function escapeRegExp (line 9) | function escapeRegExp(str: string): string {
FILE: projects/kit/src/lib/utils/find-common-beginning-substr.ts
function findCommonBeginningSubstr (line 1) | function findCommonBeginningSubstr(a: string, b: string): string {
FILE: projects/kit/src/lib/utils/is-empty.ts
function isEmpty (line 1) | function isEmpty(entity?: object | null): boolean {
FILE: projects/kit/src/lib/utils/pad-with-zeroes-until-valid.ts
constant ALL_ZEROES_RE (line 1) | const ALL_ZEROES_RE = /^0+$/;
function padWithZeroesUntilValid (line 3) | function padWithZeroesUntilValid(
FILE: projects/kit/src/lib/utils/time/create-time-mask-expression.ts
function createTimeMaskExpression (line 4) | function createTimeMaskExpression(mode: MaskitoTimeMode): Array<RegExp |...
FILE: projects/kit/src/lib/utils/time/enrich-time-segments-with-zeroes.ts
constant TRAILING_TIME_SEGMENT_SEPARATOR_REG (line 9) | const TRAILING_TIME_SEGMENT_SEPARATOR_REG = new RegExp(
function enrichTimeSegmentsWithZeroes (line 18) | function enrichTimeSegmentsWithZeroes(
FILE: projects/kit/src/lib/utils/time/pad-end-time-segments.ts
function padEndTimeSegments (line 12) | function padEndTimeSegments(
FILE: projects/kit/src/lib/utils/time/pad-start-time-segments.ts
function padStartTimeSegments (line 12) | function padStartTimeSegments(
FILE: projects/kit/src/lib/utils/time/pad-time-segments.ts
function padTimeSegments (line 14) | function padTimeSegments(
FILE: projects/kit/src/lib/utils/time/parse-time-string.ts
constant SEGMENT_FULL_NAME (line 3) | const SEGMENT_FULL_NAME: Record<string, keyof MaskitoTimeSegments> = {
function parseTimeString (line 13) | function parseTimeString(
FILE: projects/kit/src/lib/utils/time/to-time-string.ts
constant LEADING_NON_DIGITS (line 3) | const LEADING_NON_DIGITS = /^\D*/;
constant TRAILING_NON_DIGITS (line 4) | const TRAILING_NON_DIGITS = /\D*$/;
function toTimeString (line 6) | function toTimeString({
FILE: projects/kit/src/lib/utils/to-half-width-colon.ts
function toHalfWidthColon (line 8) | function toHalfWidthColon(fullWidthColon: string): string {
FILE: projects/kit/src/lib/utils/to-half-width-number.ts
function toHalfWidthNumber (line 6) | function toHalfWidthNumber(fullWidthNumber: string): string {
FILE: projects/phone/src/lib/masks/phone/constants/template-filler.ts
constant TEMPLATE_FILLER (line 1) | const TEMPLATE_FILLER = 'x';
FILE: projects/phone/src/lib/masks/phone/phone-mask-non-strict.ts
function maskitoPhoneNonStrictOptionsGenerator (line 12) | function maskitoPhoneNonStrictOptionsGenerator({
FILE: projects/phone/src/lib/masks/phone/phone-mask-strict.ts
function maskitoPhoneStrictOptionsGenerator (line 15) | function maskitoPhoneStrictOptionsGenerator({
FILE: projects/phone/src/lib/masks/phone/phone-mask.ts
type MaskitoPhoneParams (line 7) | interface MaskitoPhoneParams {
function maskitoPhoneOptionsGenerator (line 21) | function maskitoPhoneOptionsGenerator({
FILE: projects/phone/src/lib/masks/phone/processors/browser-autofill-preprocessor.ts
function extractNumberValue (line 12) | function extractNumberValue(
function convertToNationalFormat (line 31) | function convertToNationalFormat(
function browserAutofillPreprocessorGenerator (line 55) | function browserAutofillPreprocessorGenerator({
FILE: projects/phone/src/lib/masks/phone/processors/cut-init-country-code-preprocessor.ts
function cutInitCountryCodePreprocessor (line 14) | function cutInitCountryCodePreprocessor({
FILE: projects/phone/src/lib/masks/phone/processors/paste-non-strict-phone-preprocessor.ts
function parsePhone (line 11) | function parsePhone({
function pasteNonStrictPhonePreprocessorGenerator (line 33) | function pasteNonStrictPhonePreprocessorGenerator({
FILE: projects/phone/src/lib/masks/phone/processors/paste-strict-phone-preprocessor.ts
function pasteStrictPhonePreprocessorGenerator (line 6) | function pasteStrictPhonePreprocessorGenerator({
FILE: projects/phone/src/lib/masks/phone/processors/phone-length-postprocessor.ts
constant MIN_LENGTH (line 6) | const MIN_LENGTH = 3;
function phoneLengthPostprocessorGenerator (line 7) | function phoneLengthPostprocessorGenerator(
FILE: projects/phone/src/lib/masks/phone/utils/cut-phone-by-valid-length.ts
function cutPhoneByValidLength (line 3) | function cutPhoneByValidLength({
FILE: projects/phone/src/lib/masks/phone/utils/generate-phone-mask.ts
function generatePhoneMask (line 5) | function generatePhoneMask({
FILE: projects/phone/src/lib/masks/phone/utils/get-country-from-number.ts
function maskitoGetCountryFromNumber (line 3) | function maskitoGetCountryFromNumber(
FILE: projects/phone/src/lib/masks/phone/utils/get-phone-template.ts
function getPhoneTemplate (line 10) | function getPhoneTemplate({
function getInternationalPhoneTemplate (line 43) | function getInternationalPhoneTemplate({
function getNationalPhoneTemplate (line 75) | function getNationalPhoneTemplate({
FILE: projects/phone/src/lib/masks/phone/utils/select-template.ts
function selectTemplate (line 1) | function selectTemplate({
FILE: projects/react/src/lib/adaptControlledElement.tsx
function adaptReactControlledElement (line 18) | function adaptReactControlledElement(element: MaskitoElement): MaskitoEl...
function getPrototype (line 47) | function getPrototype(element: MaskitoElement): HTMLInputElement | HTMLT...
FILE: projects/react/src/lib/tests/controlledInput.spec.tsx
function TestComponent (line 14) | function TestComponent({
function App (line 85) | function App(): JSX.Element {
function App (line 165) | function App(): JSX.Element {
FILE: projects/react/src/lib/tests/elementPredicate.spec.tsx
function TestComponent (line 23) | function TestComponent({elementPredicate = predicate}): JSX.Element {
FILE: projects/react/src/lib/tests/useMaskito.spec.tsx
function TestComponent (line 27) | function TestComponent({onChangeHandler}: Readonly<{onChangeHandler?: (v...
function ConditionalInputComponent (line 38) | function ConditionalInputComponent({showInput}: Readonly<{showInput: boo...
FILE: projects/react/src/lib/useMaskito.tsx
function isThenable (line 13) | function isThenable<T = unknown>(x: PromiseLike<T> | T): x is PromiseLik...
FILE: projects/vue/src/lib/maskito.ts
function update (line 12) | async function update(
Condensed preview — 757 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,832K chars).
[
{
"path": ".cspell.json",
"chars": 581,
"preview": "{\n \"$schema\": \"https://raw.githubusercontent.com/streetsidesoftware/cspell/master/cspell.schema.json\",\n \"import\": "
},
{
"path": ".editorconfig",
"chars": 246,
"preview": "# Editor configuration, see https://editorconfig.org\nroot = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size ="
},
{
"path": ".firebaserc",
"chars": 49,
"preview": "{\n \"projects\": {\n \"default\": \"maskito\"\n }\n}\n"
},
{
"path": ".github/CODEOWNERS",
"chars": 26,
"preview": "* @taiga-family/core-team\n"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 3344,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 1327,
"preview": "# Contributing\n\n> Thank you for considering contributing to our project. Your help if very welcome!\n\nWhen contributing, "
},
{
"path": ".github/ISSUE_TEMPLATE/1-bug-report.yml",
"chars": 2180,
"preview": "name: '🐞 - Bug Report'\ntitle: '🐞 - '\ndescription: Report a bug in the Maskito\nlabels: ['bug']\ntype: Bug\n\nbody:\n - type:"
},
{
"path": ".github/ISSUE_TEMPLATE/2-feature-request.yml",
"chars": 687,
"preview": "name: '🚀 - Feature Request'\ntitle: '🚀 - '\ndescription: Suggest a feature for Maskito\nlabels: ['feature']\ntype: Feature\n\n"
},
{
"path": ".github/ISSUE_TEMPLATE/3-documentation.yml",
"chars": 1077,
"preview": "name: '📚 - Documentation'\ntitle: '📚 - '\ndescription: Report an issue in Maskito's documentation\nlabels: ['documentation'"
},
{
"path": ".github/renovate.json",
"chars": 443,
"preview": "{\n \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n \"extends\": [\"github>taiga-family/renovate-conf"
},
{
"path": ".github/workflows/assign-author.yml",
"chars": 402,
"preview": "name: 🤖 PR author as an assignee\non:\n pull_request:\n types: [opened]\n\njobs:\n assign:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/auto-merge.yml",
"chars": 1446,
"preview": "name: 🤖 PR auto merge\non:\n pull_request:\n\nenv:\n PR_JOBS_NAME: '[ \"Packages\", \"Demo\", \"Firebase\", \"Lint result\", \"tests"
},
{
"path": ".github/workflows/build.yml",
"chars": 720,
"preview": "name: Build\non:\n pull_request:\n push:\n branches: [main]\n\njobs:\n build-packages:\n name: Packages\n runs-on: ub"
},
{
"path": ".github/workflows/deploy-preview.yml",
"chars": 888,
"preview": "name: Deploy / preview\n\non: pull_request\n\njobs:\n build_and_preview:\n name: Firebase\n runs-on: ubuntu-latest\n s"
},
{
"path": ".github/workflows/deploy.yml",
"chars": 708,
"preview": "name: Deploy\non:\n workflow_dispatch:\n push:\n branches: [main]\n\njobs:\n deploy:\n runs-on: ubuntu-latest\n if: $"
},
{
"path": ".github/workflows/e2e.yml",
"chars": 4368,
"preview": "name: E2E\non: [pull_request]\n\nenv:\n CACHE_DIST_KEY: dist-${{ github.ref }}-${{ github.sha }}\n CYPRESS_CACHE_FOLDER: ./"
},
{
"path": ".github/workflows/lint.yml",
"chars": 2211,
"preview": "name: Lint\non: [pull_request]\n\njobs:\n typecheck:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v"
},
{
"path": ".github/workflows/release.yml",
"chars": 1372,
"preview": "name: ⚠️ Release\n\non:\n workflow_dispatch:\n inputs:\n mode:\n type: choice\n description: Bump versio"
},
{
"path": ".github/workflows/test.yml",
"chars": 1933,
"preview": "name: Tests\n\non:\n pull_request:\n push:\n branches:\n - main\n\njobs:\n tests:\n runs-on: ubuntu-latest\n steps"
},
{
"path": ".gitignore",
"chars": 761,
"preview": "# compiled output\n/dist\n/tmp\n/out-tsc\n# Only exists if Bazel was run\n/bazel-out\n\n# dependencies\n**/node_modules/\n\n# prof"
},
{
"path": ".husky/commit-msg",
"chars": 33,
"preview": "npx --no -- commitlint --edit $1\n"
},
{
"path": ".husky/pre-commit",
"chars": 34,
"preview": "npx lint-staged\nnpm run typecheck\n"
},
{
"path": ".npmrc",
"chars": 34,
"preview": "engine-strict=true\nloglevel=error\n"
},
{
"path": ".release-it.js",
"chars": 57,
"preview": "module.exports = require('@taiga-ui/release-it-config');\n"
},
{
"path": ".ws-context",
"chars": 153,
"preview": "{\n \"framework\": \"angular\",\n \"projects/vue/**\": {\n \"framework\": \"vue\"\n },\n \"projects/react/**\": {\n "
},
{
"path": "CHANGELOG.md",
"chars": 57534,
"preview": "### [5.2.2](https://github.com/taiga-family/maskito/compare/v5.2.1...v5.2.2) (2026-03-31)\n\n### 🐞 Bug Fixes\n\n- **kit**: `"
},
{
"path": "LICENSE",
"chars": 10750,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 3803,
"preview": "# Maskito\n\n[](https://npmjs.com/package/@maskito/core)\n[](https://npmjs.com/package/@maski"
},
{
"path": "projects/angular/jest.config.ts",
"chars": 472,
"preview": "export default {\n displayName: 'angular',\n preset: '../../jest.preset.js',\n setupFilesAfterEnv: ['<rootDir>/src"
},
{
"path": "projects/angular/ng-package.json",
"chars": 164,
"preview": "{\n \"$schema\": \"../../node_modules/ng-packagr/ng-package.schema.json\",\n \"dest\": \"../../dist/angular\",\n \"lib\": {\n"
},
{
"path": "projects/angular/package.json",
"chars": 1593,
"preview": "{\n \"name\": \"@maskito/angular\",\n \"version\": \"5.2.2\",\n \"description\": \"The Angular-specific Maskito's library\",\n "
},
{
"path": "projects/angular/project.json",
"chars": 1557,
"preview": "{\n \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n \"name\": \"angular\",\n \"prefix\": \"maskito\",\n "
},
{
"path": "projects/angular/src/index.ts",
"chars": 118,
"preview": "export * from './lib/maskito.directive';\nexport * from './lib/maskito.pipe';\nexport * from './lib/pattern.directive';\n"
},
{
"path": "projects/angular/src/lib/maskito.directive.ts",
"chars": 2265,
"preview": "import {\n Directive,\n effect,\n ElementRef,\n inject,\n model,\n NgZone,\n type OnDestroy,\n untracked"
},
{
"path": "projects/angular/src/lib/maskito.pipe.ts",
"chars": 469,
"preview": "import {Pipe, type PipeTransform} from '@angular/core';\nimport {\n MASKITO_DEFAULT_OPTIONS,\n type MaskitoOptions,\n "
},
{
"path": "projects/angular/src/lib/pattern.directive.ts",
"chars": 546,
"preview": "import {Directive, inject} from '@angular/core';\n\nimport {MaskitoDirective} from './maskito.directive';\n\n@Directive({\n "
},
{
"path": "projects/angular/src/lib/tests/maskito.directive.spec.ts",
"chars": 5655,
"preview": "import {ChangeDetectionStrategy, Component, signal} from '@angular/core';\nimport {type ComponentFixture, TestBed} from '"
},
{
"path": "projects/angular/src/lib/tests/maskito.spec.ts",
"chars": 2785,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {type ComponentFixture, TestBed} from '@angular"
},
{
"path": "projects/angular/src/test-setup.ts",
"chars": 90,
"preview": "import {setupZoneTestEnv} from 'jest-preset-angular/setup-env/zone';\n\nsetupZoneTestEnv();\n"
},
{
"path": "projects/angular/tsconfig.lib.prod.json",
"chars": 111,
"preview": "{\n \"extends\": \"../../tsconfig.build.json\",\n \"compilerOptions\": {\n \"declarationMap\": false\n }\n}\n"
},
{
"path": "projects/core/README.md",
"chars": 845,
"preview": "# @maskito/core\n\n[](https://npmjs.com/package/@maskito/cor"
},
{
"path": "projects/core/jest.config.ts",
"chars": 181,
"preview": "export default {\n displayName: 'core',\n preset: '../../jest.preset.js',\n moduleFileExtensions: ['ts', 'tsx', 'j"
},
{
"path": "projects/core/package.json",
"chars": 1248,
"preview": "{\n \"name\": \"@maskito/core\",\n \"version\": \"5.2.2\",\n \"description\": \"The main zero-dependency and framework-agnost"
},
{
"path": "projects/core/project.json",
"chars": 1549,
"preview": "{\n \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n \"name\": \"core\",\n \"projectType\": \"library\",\n"
},
{
"path": "projects/core/src/index.ts",
"chars": 623,
"preview": "export {\n MASKITO_DEFAULT_ELEMENT_PREDICATE,\n MASKITO_DEFAULT_OPTIONS,\n} from './lib/constants';\nexport {Maskito} "
},
{
"path": "projects/core/src/lib/classes/index.ts",
"chars": 95,
"preview": "export {MaskHistory} from './mask-history';\nexport {MaskModel} from './mask-model/mask-model';\n"
},
{
"path": "projects/core/src/lib/classes/mask-history.ts",
"chars": 1595,
"preview": "import type {ElementState, TypedInputEvent} from '../types';\n\nexport abstract class MaskHistory {\n private now: Eleme"
},
{
"path": "projects/core/src/lib/classes/mask-model/mask-model.ts",
"chars": 4587,
"preview": "import type {\n ElementState,\n MaskitoMaskExpression,\n MaskitoOptions,\n SelectionRange,\n} from '../../types';"
},
{
"path": "projects/core/src/lib/classes/mask-model/tests/dynamic-mask.spec.ts",
"chars": 3399,
"preview": "import {describe, expect, it} from '@jest/globals';\nimport {MASKITO_DEFAULT_OPTIONS} from '@maskito/core';\n\nimport type "
},
{
"path": "projects/core/src/lib/classes/mask-model/tests/mask-model-fixed-characters.spec.ts",
"chars": 9815,
"preview": "import {describe, expect, it} from '@jest/globals';\n\nimport {MASKITO_DEFAULT_OPTIONS} from '../../../constants';\nimport "
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/apply-overwrite-mode.ts",
"chars": 544,
"preview": "import type {ElementState, MaskitoOptions} from '../../../types';\n\nexport function applyOverwriteMode(\n {value, selec"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/calibrate-value-by-mask.ts",
"chars": 852,
"preview": "import type {ElementState, MaskitoMaskExpression} from '../../../types';\nimport {guessValidValueByPattern} from './guess"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/get-leading-fixed-characters.ts",
"chars": 828,
"preview": "import type {ElementState} from '../../../types';\nimport {isFixedCharacter} from './is-fixed-character';\n\nexport functio"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-pattern.ts",
"chars": 2270,
"preview": "import type {ElementState} from '../../../types';\nimport {getLeadingFixedCharacters} from './get-leading-fixed-character"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-reg-exp.ts",
"chars": 867,
"preview": "import type {ElementState} from '../../../types';\n\nexport function guessValidValueByRegExp(\n {value, selection}: Elem"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/is-fixed-character.ts",
"chars": 113,
"preview": "export function isFixedCharacter(char: RegExp | string): char is string {\n return typeof char === 'string';\n}\n"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/remove-fixed-mask-characters.ts",
"chars": 1249,
"preview": "import type {ElementState, MaskitoMaskExpression} from '../../../types';\nimport {isFixedCharacter} from './is-fixed-char"
},
{
"path": "projects/core/src/lib/classes/mask-model/utils/validate-value-with-mask.ts",
"chars": 683,
"preview": "import type {MaskitoMaskExpression} from '../../../types';\nimport {isFixedCharacter} from './is-fixed-character';\n\nexpor"
},
{
"path": "projects/core/src/lib/constants/default-element-predicate.ts",
"chars": 417,
"preview": "import type {MaskitoElementPredicate} from '../types';\nimport {maskitoAdaptContentEditable} from '../utils/content-edita"
},
{
"path": "projects/core/src/lib/constants/default-options.ts",
"chars": 227,
"preview": "import type {MaskitoOptions} from '../types';\n\nexport const MASKITO_DEFAULT_OPTIONS: Required<MaskitoOptions> = {\n ma"
},
{
"path": "projects/core/src/lib/constants/index.ts",
"chars": 80,
"preview": "export * from './default-element-predicate';\nexport * from './default-options';\n"
},
{
"path": "projects/core/src/lib/mask.ts",
"chars": 12015,
"preview": "import {MaskHistory, MaskModel} from './classes';\nimport {MASKITO_DEFAULT_OPTIONS} from './constants';\nimport {createBro"
},
{
"path": "projects/core/src/lib/plugins/broken-prevent-default.plugin.ts",
"chars": 1885,
"preview": "import type {MaskitoPlugin} from '@maskito/core';\n\nimport type {TypedInputEvent} from '../types';\nimport {EventListener}"
},
{
"path": "projects/core/src/lib/plugins/change-event-plugin.ts",
"chars": 930,
"preview": "import type {MaskitoPlugin} from '../types';\n\nexport function maskitoChangeEventPlugin(): MaskitoPlugin {\n return (el"
},
{
"path": "projects/core/src/lib/plugins/double-space.plugin.ts",
"chars": 2511,
"preview": "import type {MaskitoPlugin} from '@maskito/core';\n\nimport type {TypedInputEvent} from '../types';\nimport {EventListener}"
},
{
"path": "projects/core/src/lib/plugins/index.ts",
"chars": 218,
"preview": "export * from './broken-prevent-default.plugin';\nexport * from './change-event-plugin';\nexport * from './double-space.pl"
},
{
"path": "projects/core/src/lib/plugins/initial-calibration-plugin.ts",
"chars": 537,
"preview": "import type {MaskitoOptions, MaskitoPlugin} from '../types';\nimport {maskitoTransform, maskitoUpdateElement} from '../ut"
},
{
"path": "projects/core/src/lib/plugins/strict-composition-plugin.ts",
"chars": 1160,
"preview": "import type {ElementState, MaskitoPlugin, TypedInputEvent} from '../types';\nimport {areElementStatesEqual, maskitoTransf"
},
{
"path": "projects/core/src/lib/types/element-predicate.ts",
"chars": 169,
"preview": "import type {MaskitoElement} from './maskito-element';\n\nexport type MaskitoElementPredicate = (\n element: HTMLElement"
},
{
"path": "projects/core/src/lib/types/element-state.ts",
"chars": 158,
"preview": "import type {SelectionRange} from './selection-range';\n\nexport interface ElementState {\n readonly value: string;\n "
},
{
"path": "projects/core/src/lib/types/index.ts",
"chars": 294,
"preview": "export * from './element-predicate';\nexport * from './element-state';\nexport * from './mask';\nexport * from './mask-opti"
},
{
"path": "projects/core/src/lib/types/mask-options.ts",
"chars": 593,
"preview": "import type {ElementState} from './element-state';\nimport type {MaskitoMask} from './mask';\nimport type {MaskitoPostproc"
},
{
"path": "projects/core/src/lib/types/mask-processors.ts",
"chars": 429,
"preview": "import type {ElementState} from './element-state';\n\nexport type MaskitoPreprocessor = (\n _: {\n elementState: E"
},
{
"path": "projects/core/src/lib/types/mask.ts",
"chars": 239,
"preview": "import type {ElementState} from './element-state';\n\nexport type MaskitoMaskExpression = Array<RegExp | string> | RegExp;"
},
{
"path": "projects/core/src/lib/types/maskito-element.ts",
"chars": 234,
"preview": "export type TextfieldLike = Pick<\n HTMLInputElement,\n | 'maxLength'\n | 'select'\n | 'selectionEnd'\n | 'sel"
},
{
"path": "projects/core/src/lib/types/plugin.ts",
"chars": 232,
"preview": "import type {MaskitoOptions} from './mask-options';\nimport type {MaskitoElement} from './maskito-element';\n\nexport type "
},
{
"path": "projects/core/src/lib/types/selection-range.ts",
"chars": 66,
"preview": "export type SelectionRange = readonly [from: number, to: number];\n"
},
{
"path": "projects/core/src/lib/types/typed-input-event.ts",
"chars": 878,
"preview": "export interface TypedInputEvent extends InputEvent {\n inputType:\n | 'deleteByCut' // Ctrl (Command) + X\n "
},
{
"path": "projects/core/src/lib/utils/content-editable.ts",
"chars": 1861,
"preview": "import type {MaskitoElement, TextfieldLike} from '../types';\nimport {getContentEditableSelection} from './dom/get-conten"
},
{
"path": "projects/core/src/lib/utils/dom/event-listener.ts",
"chars": 871,
"preview": "import type {TypedInputEvent} from '../../types';\n\nexport class EventListener {\n private readonly listeners: Array<()"
},
{
"path": "projects/core/src/lib/utils/dom/get-content-editable-selection.ts",
"chars": 367,
"preview": "import type {SelectionRange} from '../../types';\n\nexport function getContentEditableSelection(element: HTMLElement): Sel"
},
{
"path": "projects/core/src/lib/utils/dom/history-events.ts",
"chars": 654,
"preview": "import {HotkeyCode, HotkeyModifier, isHotkey} from './hotkey';\n\nexport function isRedo(event: KeyboardEvent): boolean {\n"
},
{
"path": "projects/core/src/lib/utils/dom/hotkey.ts",
"chars": 1526,
"preview": "export const HotkeyModifier = {\n CTRL: 1 << 0,\n ALT: 1 << 1,\n SHIFT: 1 << 2,\n META: 1 << 3,\n} as const;\n\n// "
},
{
"path": "projects/core/src/lib/utils/dom/set-content-editable-selection.ts",
"chars": 642,
"preview": "import type {SelectionRange} from '../../types';\n\nexport function setContentEditableSelection(\n element: HTMLElement,"
},
{
"path": "projects/core/src/lib/utils/dom/update-element.ts",
"chars": 1487,
"preview": "import type {ElementState, MaskitoElement} from '../../types';\n\n/**\n * Sets value to element, and dispatches input event"
},
{
"path": "projects/core/src/lib/utils/element-states-equality.ts",
"chars": 562,
"preview": "import type {ElementState} from '../types';\n\nexport function areElementValuesEqual(\n sampleState: ElementState,\n ."
},
{
"path": "projects/core/src/lib/utils/get-line-selection.ts",
"chars": 565,
"preview": "import type {ElementState, SelectionRange} from '../types';\n\nexport function getLineSelection(\n {value, selection}: E"
},
{
"path": "projects/core/src/lib/utils/get-not-empty-selection.ts",
"chars": 475,
"preview": "import type {ElementState, SelectionRange} from '../types';\n\nexport function getNotEmptySelection(\n {value, selection"
},
{
"path": "projects/core/src/lib/utils/get-word-selection.ts",
"chars": 1307,
"preview": "import type {ElementState, SelectionRange} from '../types';\n\nconst TRAILING_SPACES_REG = /\\s+$/g;\nconst LEADING_SPACES_R"
},
{
"path": "projects/core/src/lib/utils/index.ts",
"chars": 473,
"preview": "export * from './content-editable';\nexport * from './dom/event-listener';\nexport * from './dom/get-content-editable-sele"
},
{
"path": "projects/core/src/lib/utils/pipe.ts",
"chars": 690,
"preview": "import type {MaskitoPostprocessor, MaskitoPreprocessor} from '../types';\n\n/**\n * @internal\n */\nexport function maskitoPi"
},
{
"path": "projects/core/src/lib/utils/test/get-not-empty-selection.spec.ts",
"chars": 2710,
"preview": "import {describe, expect, it} from '@jest/globals';\n\nimport type {ElementState} from '../../types';\nimport {getNotEmptyS"
},
{
"path": "projects/core/src/lib/utils/test/get-word-selection.spec.ts",
"chars": 5371,
"preview": "import {describe, expect, it} from '@jest/globals';\n\nimport {getWordSelection} from '../get-word-selection';\n\ndescribe('"
},
{
"path": "projects/core/src/lib/utils/test/pipe.spec.ts",
"chars": 6966,
"preview": "import {describe, expect, it} from '@jest/globals';\n\nimport type {ElementState, MaskitoPostprocessor, MaskitoPreprocesso"
},
{
"path": "projects/core/src/lib/utils/test/transform.spec.ts",
"chars": 3514,
"preview": "import {describe, expect, it} from '@jest/globals';\n\nimport type {MaskitoOptions} from '../../types';\nimport {maskitoTra"
},
{
"path": "projects/core/src/lib/utils/transform.ts",
"chars": 1277,
"preview": "import {MaskModel} from '../classes';\nimport {MASKITO_DEFAULT_OPTIONS} from '../constants';\nimport type {ElementState, M"
},
{
"path": "projects/demo/.gitignore",
"chars": 554,
"preview": "# compiled output\n/dist\n/tmp\n/out-tsc\n# Only exists if Bazel was run\n/bazel-out\n\n# dependencies\n/node_modules\n\n# profili"
},
{
"path": "projects/demo/esbuild-plugins/maskito-as-taiga-ui-dep.plugin.js",
"chars": 1259,
"preview": "const {resolve, join} = require('node:path');\nconst {existsSync} = require('node:fs');\n\n/**\n * Maskito repo uses Taiga U"
},
{
"path": "projects/demo/esbuild-plugins/vue-esm.plugin.js",
"chars": 649,
"preview": "const {resolve} = require('node:path');\n\n/**\n * Otherwise, demo application logs warning:\n * ```\n * Component provided t"
},
{
"path": "projects/demo/jest.config.ts",
"chars": 466,
"preview": "export default {\n displayName: 'demo',\n preset: '../../jest.preset.js',\n setupFilesAfterEnv: ['<rootDir>/src/te"
},
{
"path": "projects/demo/package.json",
"chars": 1295,
"preview": "{\n \"name\": \"@maskito/demo\",\n \"private\": true,\n \"devDependencies\": {\n \"@angular/animations\": \"19.2.20\",\n "
},
{
"path": "projects/demo/project.json",
"chars": 6012,
"preview": "{\n \"$schema\": \"../../node_modules/nx/schemas/project-schema.json\",\n \"name\": \"demo\",\n \"prefix\": \"app\",\n \"proj"
},
{
"path": "projects/demo/src/app/app.component.html",
"chars": 956,
"preview": "<tui-doc-main>\n <ng-container ngProjectAs=\"tuiDocHeader\">\n <a\n appearance=\"icon\"\n href=\""
},
{
"path": "projects/demo/src/app/app.component.spec.ts",
"chars": 1283,
"preview": "import {APP_BASE_HREF} from '@angular/common';\nimport {TestBed} from '@angular/core/testing';\nimport {RouterTestingHarne"
},
{
"path": "projects/demo/src/app/app.component.ts",
"chars": 2078,
"preview": "import {ViewportScroller} from '@angular/common';\nimport {ChangeDetectionStrategy, Component, inject} from '@angular/cor"
},
{
"path": "projects/demo/src/app/app.config.ts",
"chars": 5650,
"preview": "import {isPlatformBrowser, LocationStrategy, PathLocationStrategy} from '@angular/common';\nimport {provideHttpClient} fr"
},
{
"path": "projects/demo/src/app/app.routes.ts",
"chars": 6187,
"preview": "import type {Routes} from '@angular/router';\nimport {DemoPath} from '@demo/constants';\nimport {tuiProvideRoutePageTab} f"
},
{
"path": "projects/demo/src/app/app.style.less",
"chars": 196,
"preview": "@import '@taiga-ui/core/styles/taiga-ui-local.less';\n\n:host {\n display: block;\n font: var(--tui-font-text-m);\n "
},
{
"path": "projects/demo/src/app/constants/demo-path.ts",
"chars": 1219,
"preview": "export const DemoPath = {\n WhatIsMaskito: 'getting-started/what-is-maskito',\n MaskitoLibraries: 'getting-started/m"
},
{
"path": "projects/demo/src/app/constants/doc-example-primary-tab.ts",
"chars": 168,
"preview": "export const DocExamplePrimaryTab = {\n MaskitoOptions: 'mask',\n JavaScript: 'JavaScript',\n Angular: 'Angular',\n"
},
{
"path": "projects/demo/src/app/constants/index.ts",
"chars": 72,
"preview": "export * from './demo-path';\nexport * from './doc-example-primary-tab';\n"
},
{
"path": "projects/demo/src/app/modules/example-primary-tabs-icons/angular-logo.component.ts",
"chars": 451,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {PolymorpheusComponent} from '@taiga-ui/polymor"
},
{
"path": "projects/demo/src/app/modules/example-primary-tabs-icons/index.ts",
"chars": 127,
"preview": "export * from './angular-logo.component';\nexport * from './javascript-logo.component';\nexport * from './react-logo.compo"
},
{
"path": "projects/demo/src/app/modules/example-primary-tabs-icons/javascript-logo.component.ts",
"chars": 466,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {PolymorpheusComponent} from '@taiga-ui/polymor"
},
{
"path": "projects/demo/src/app/modules/example-primary-tabs-icons/react-logo.component.ts",
"chars": 441,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {PolymorpheusComponent} from '@taiga-ui/polymor"
},
{
"path": "projects/demo/src/app/modules/example-primary-tabs-icons/vue-logo.component.ts",
"chars": 431,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {PolymorpheusComponent} from '@taiga-ui/polymor"
},
{
"path": "projects/demo/src/app/modules/logo/logo.component.ts",
"chars": 517,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {Tu"
},
{
"path": "projects/demo/src/app/modules/logo/logo.style.less",
"chars": 411,
"preview": "@import '@taiga-ui/core/styles/taiga-ui-local.less';\n\n:host {\n display: flex;\n align-items: center;\n\n @media @t"
},
{
"path": "projects/demo/src/app/modules/logo/logo.template.html",
"chars": 243,
"preview": "<a\n routerLink=\"/\"\n tuiLink\n class=\"logo-link\"\n>\n <span class=\"logo-name\">\n <img\n alt=\"Mas"
},
{
"path": "projects/demo/src/app/server-error-handler.ts",
"chars": 1523,
"preview": "import {type ErrorHandler, Injectable} from '@angular/core';\n\n// TODO\nconst KNOWN_ISSUES: ReadonlyArray<RegExp | string>"
},
{
"path": "projects/demo/src/app/utils/add-default-tabs-processor/add-default-tabs-processor.ts",
"chars": 946,
"preview": "import {DocExamplePrimaryTab} from '@demo/constants';\nimport type {TuiHandler} from '@taiga-ui/cdk';\n\nimport {ANGULAR_DE"
},
{
"path": "projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/angular-default-tab.ts",
"chars": 388,
"preview": "export const ANGULAR_DEFAULT_TAB = `import {Component} from '@angular/core';\nimport {MaskitoDirective} from '@maskito/an"
},
{
"path": "projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/js-default-tab.ts",
"chars": 327,
"preview": "export const JS_DEFAULT_TAB = `import {Maskito, MaskitoOptions} from '@maskito/core';\nimport maskitoOptions from './mask"
},
{
"path": "projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/react-default-tab.ts",
"chars": 267,
"preview": "export const REACT_DEFAULT_TAB = `import * as React from 'react';\nimport {useMaskito} from '@maskito/react';\n\nimport opt"
},
{
"path": "projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/vue-default-tab.ts",
"chars": 262,
"preview": "export const VUE_DEFAULT_TAB = `import {createApp} from 'vue';\nimport {maskito} from '@maskito/vue';\n\nimport options fro"
},
{
"path": "projects/demo/src/app/utils/index.ts",
"chars": 73,
"preview": "export * from './add-default-tabs-processor/add-default-tabs-processor';\n"
},
{
"path": "projects/demo/src/assets/manifest.webmanifest",
"chars": 180,
"preview": "{\n \"icons\": [\n {\"src\": \"/favicon-192.png\", \"type\": \"image/png\", \"sizes\": \"192x192\"},\n {\"src\": \"/favicon"
},
{
"path": "projects/demo/src/environments/environment.prod.ts",
"chars": 47,
"preview": "export const environment = {production: true};\n"
},
{
"path": "projects/demo/src/environments/environment.ts",
"chars": 48,
"preview": "export const environment = {production: false};\n"
},
{
"path": "projects/demo/src/index.html",
"chars": 1114,
"preview": "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta\n content=\"text/htm"
},
{
"path": "projects/demo/src/main.server.ts",
"chars": 2274,
"preview": "import {type ApplicationRef, ErrorHandler, mergeApplicationConfig} from '@angular/core';\nimport {bootstrapApplication, t"
},
{
"path": "projects/demo/src/main.ts",
"chars": 235,
"preview": "import {bootstrapApplication} from '@angular/platform-browser';\n\nimport {App} from './app/app.component';\nimport {APP_CO"
},
{
"path": "projects/demo/src/pages/documentation/browser-support/browser-support.component.ts",
"chars": 1122,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {TuiAddonDoc} from '@taiga-ui/addon-doc';\n\n@Com"
},
{
"path": "projects/demo/src/pages/documentation/browser-support/browser-support.template.html",
"chars": 1479,
"preview": "<tui-doc-page header=\"Browser support\">\n <h2 class=\"tui-text_h4 tui-space_top-0 tui-space_bottom-3\">Desktop</h2>\n "
},
{
"path": "projects/demo/src/pages/documentation/core-concepts-overview/core-concepts-overview.component.ts",
"chars": 1456,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {De"
},
{
"path": "projects/demo/src/pages/documentation/core-concepts-overview/core-concepts-overview.styles.less",
"chars": 371,
"preview": "@import '@taiga-ui/core/styles/taiga-ui-local.less';\n\n.cards {\n display: flex;\n flex-wrap: wrap;\n justify-conte"
},
{
"path": "projects/demo/src/pages/documentation/core-concepts-overview/core-concepts-overview.template.html",
"chars": 5294,
"preview": "<tui-doc-page header=\"Core concepts\">\n <section class=\"tui-space_bottom-4\">\n <p class=\"tui-space_top-0\">\n "
},
{
"path": "projects/demo/src/pages/documentation/core-concepts-overview/examples/maskito-public-api-demo.md",
"chars": 426,
"preview": "```ts\nimport {Maskito, maskitoInitialCalibrationPlugin} from '@maskito/core';\n\nconst maskedInput = new Maskito(element, "
},
{
"path": "projects/demo/src/pages/documentation/element-state/element-state.component.ts",
"chars": 815,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {De"
},
{
"path": "projects/demo/src/pages/documentation/element-state/element-state.template.html",
"chars": 1407,
"preview": "<tui-doc-page header=\"Element state\">\n <section class=\"tui-space_bottom-6\">\n <p class=\"tui-space_top-0\">\n "
},
{
"path": "projects/demo/src/pages/documentation/element-state/examples/element-state-demo.md",
"chars": 305,
"preview": "```ts\ninterface ElementState {\n // the value of a masked <input> or <textarea>\n readonly value: string;\n readonly sel"
},
{
"path": "projects/demo/src/pages/documentation/mask-expression/examples/basic-time-example.md",
"chars": 134,
"preview": "```ts\nimport {Maskito} from '@maskito/core';\n\nconst timeInput = new Maskito(element, {\n mask: [/\\d/, /\\d/, ':', /\\d/, /"
},
{
"path": "projects/demo/src/pages/documentation/mask-expression/examples/dynamic-mask-expression-demo.md",
"chars": 213,
"preview": "```ts\nimport {Maskito} from '@maskito/core';\n\nlet howManyWordsAllowed = 5;\n\nconst maxWordInput = new Maskito(element, {\n"
},
{
"path": "projects/demo/src/pages/documentation/mask-expression/examples/reg-exp-mask-expression-demo.md",
"chars": 118,
"preview": "```ts\nimport {Maskito} from '@maskito/core';\n\nconst onlyDigitsInput = new Maskito(element, {\n mask: /^\\d+$/,\n});\n```\n"
},
{
"path": "projects/demo/src/pages/documentation/mask-expression/mask-expression.component.ts",
"chars": 1005,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {De"
},
{
"path": "projects/demo/src/pages/documentation/mask-expression/mask-expression.template.html",
"chars": 6769,
"preview": "<tui-doc-page header=\"Mask expression\">\n <div>\n <strong>Mask expression</strong>\n is the the main conce"
},
{
"path": "projects/demo/src/pages/documentation/maskito-libraries/maskito-libraries.component.ts",
"chars": 1019,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {De"
},
{
"path": "projects/demo/src/pages/documentation/maskito-libraries/maskito-libraries.template.html",
"chars": 5357,
"preview": "<tui-doc-page header=\"Maskito libraries\">\n <p class=\"tui-space_top-0\">\n <strong>Maskito</strong>\n is a "
},
{
"path": "projects/demo/src/pages/documentation/next-steps/next-steps.component.ts",
"chars": 777,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink, RouterLinkActive} from '@angular/r"
},
{
"path": "projects/demo/src/pages/documentation/next-steps/next-steps.template.html",
"chars": 1226,
"preview": "<section class=\"tui-space_top-12\">\n <h2>Next steps</h2>\n\n <p>The following sections are recommended to explore cor"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/examples/dynamic/component.ts",
"chars": 1174,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/examples/dynamic/mask.ts",
"chars": 308,
"preview": "import type {MaskitoOptions} from '@maskito/core';\n\nconst maskitoOptions: MaskitoOptions = {\n mask: /^[^а-яё]+$/i,\n "
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/examples/replace/component.ts",
"chars": 1106,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/examples/replace/mask.ts",
"chars": 177,
"preview": "import type {MaskitoOptions} from '@maskito/core';\n\nconst maskitoOptions: MaskitoOptions = {\n mask: /^\\d+$/,\n over"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/examples/shift/component.ts",
"chars": 1104,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/examples/shift/mask.ts",
"chars": 175,
"preview": "import type {MaskitoOptions} from '@maskito/core';\n\nconst maskitoOptions: MaskitoOptions = {\n mask: /^\\d+$/,\n over"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/overwrite-mode.component.ts",
"chars": 1744,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {De"
},
{
"path": "projects/demo/src/pages/documentation/overwrite-mode/overwrite-mode.template.html",
"chars": 2913,
"preview": "<tui-doc-page header=\"Overwrite mode\">\n <p class=\"tui-space_top-0\">\n <strong>Overwrite mode</strong>\n r"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/1-initial-calibration/component.ts",
"chars": 815,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/1-initial-calibration/index.md",
"chars": 395,
"preview": "```ts\nimport {Maskito} from '@maskito/core';\n\nimport maskitoOptions from './mask';\n\nconst element = document.querySelect"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/1-initial-calibration/mask.ts",
"chars": 234,
"preview": "import {maskitoInitialCalibrationPlugin, type MaskitoOptions} from '@maskito/core';\n\nconst maskitoOptions: MaskitoOption"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/2-strict-composition/component.ts",
"chars": 744,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/2-strict-composition/mask.ts",
"chars": 203,
"preview": "import {type MaskitoOptions, maskitoStrictCompositionPlugin} from '@maskito/core';\n\nexport default {\n mask: /^[0-90-9"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/3-change-event/component.ts",
"chars": 970,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/3-change-event/mask.ts",
"chars": 397,
"preview": "import {maskitoChangeEventPlugin, type MaskitoOptions} from '@maskito/core';\nimport {maskitoNumberOptionsGenerator} from"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/oversimplified-number-mask.md",
"chars": 300,
"preview": "```ts\nimport {MaskitoOptions} from '@maskito/core';\n\nexport default {\n /**\n * ^ – beginning of the string\n * \\d – a"
},
{
"path": "projects/demo/src/pages/documentation/plugins/examples/pads-zero-plugin.ts",
"chars": 1051,
"preview": "import {\n /**\n * HTMLElement + some common properties from:\n * - HTMLInputElement\n * - HTMLTextAreaElemen"
},
{
"path": "projects/demo/src/pages/documentation/plugins/plugins.component.ts",
"chars": 2781,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ro"
},
{
"path": "projects/demo/src/pages/documentation/plugins/plugins.style.less",
"chars": 278,
"preview": "@import '@taiga-ui/core/styles/taiga-ui-local.less';\n\n.cards {\n display: flex;\n flex-wrap: wrap;\n gap: 1rem;\n\n "
},
{
"path": "projects/demo/src/pages/documentation/plugins/plugins.template.html",
"chars": 10055,
"preview": "<tui-doc-page header=\"Plugins\">\n <ng-template pageTab=\"Documentation\">\n <p class=\"tui-space_top-0\">\n "
},
{
"path": "projects/demo/src/pages/documentation/processors/examples/postprocessor-in-action.md",
"chars": 590,
"preview": "```ts\nimport {Maskito} from '@maskito/core';\n\nconst numberInput = new Maskito(element, {\n mask: /^\\d+(,\\d*)?$/,\n postp"
},
{
"path": "projects/demo/src/pages/documentation/processors/examples/preprocessor-first-arg-demo.md",
"chars": 328,
"preview": "```ts\ntype firstArgDemo = {\n // current input's element state BEFORE any changes are applied\n elementState: {\n valu"
},
{
"path": "projects/demo/src/pages/documentation/processors/examples/preprocessor-in-action-demo.md",
"chars": 447,
"preview": "```ts\nimport {Maskito} from '@maskito/core';\n\nconst numberInput = new Maskito(element, {\n mask: /^\\d+(,\\d*)?$/, // digi"
},
{
"path": "projects/demo/src/pages/documentation/processors/examples/processor-second-arg-demo.md",
"chars": 72,
"preview": "```ts\n'insert' | 'deleteForward' | 'deleteBackward' | 'validation';\n```\n"
},
{
"path": "projects/demo/src/pages/documentation/processors/processors.component.ts",
"chars": 1141,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {RouterLink} from '@angular/router';\nimport {De"
},
{
"path": "projects/demo/src/pages/documentation/processors/processors.template.html",
"chars": 7120,
"preview": "<tui-doc-page header=\"Processors\">\n <section class=\"tui-space_bottom-6\">\n <p class=\"tui-space_top-0\">\n "
},
{
"path": "projects/demo/src/pages/documentation/real-world-form/index.html",
"chars": 5123,
"preview": "<form\n #formElement\n autocomplete=\"on\"\n class=\"tui-form\"\n [formGroup]=\"form\"\n (ngSubmit)=\"log(form.value)"
},
{
"path": "projects/demo/src/pages/documentation/real-world-form/index.less",
"chars": 240,
"preview": ":host {\n display: flex;\n justify-content: center;\n align-items: center;\n padding-block-start: 2rem;\n}\n\nform "
},
{
"path": "projects/demo/src/pages/documentation/real-world-form/index.ts",
"chars": 3260,
"preview": "import {ChangeDetectionStrategy, Component, inject} from '@angular/core';\nimport {FormControl, FormGroup, ReactiveFormsM"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/password/component.ts",
"chars": 1134,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/password/mask.ts",
"chars": 120,
"preview": "import type {MaskitoOptions} from '@maskito/core';\n\nexport default {mask: [/\\d/, /\\d/, /\\d/]} satisfies MaskitoOptions;\n"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/search/component.ts",
"chars": 1037,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/search/mask.ts",
"chars": 113,
"preview": "import type {MaskitoOptions} from '@maskito/core';\n\nexport default {mask: /^[a-z]+$/i} satisfies MaskitoOptions;\n"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/tel/component.ts",
"chars": 1336,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/tel/mask.ts",
"chars": 212,
"preview": "import {maskitoPhoneOptionsGenerator} from '@maskito/phone';\nimport metadata from 'libphonenumber-js/metadata.min.json';"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/text/component.ts",
"chars": 1059,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/text/mask.ts",
"chars": 120,
"preview": "import {maskitoTimeOptionsGenerator} from '@maskito/kit';\n\nexport default maskitoTimeOptionsGenerator({mode: 'HH:MM'});\n"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/url/component.ts",
"chars": 1019,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {FormsModule} from '@angular/forms';\nimport {Ma"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/examples/url/mask.ts",
"chars": 182,
"preview": "import type {MaskitoOptions} from '@maskito/core';\n\nexport default {\n // oversimplified version of url mask for demo "
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/supported-input-types.component.ts",
"chars": 2284,
"preview": "import {ChangeDetectionStrategy, Component} from '@angular/core';\nimport {DocExamplePrimaryTab} from '@demo/constants';\n"
},
{
"path": "projects/demo/src/pages/documentation/supported-input-types/supported-input-types.template.html",
"chars": 4067,
"preview": "<tui-doc-page header=\"Supported <input /> types\">\n <tui-notification\n appearance=\"warning\"\n size=\"m\"\n "
},
{
"path": "projects/demo/src/pages/documentation/transformer/examples/utility-in-action-demo.md",
"chars": 498,
"preview": "```ts\nimport {maskitoTransform} from '@maskito/core';\nimport {maskitoNumberOptionsGenerator} from '@maskito/kit';\n\nconst"
}
]
// ... and 557 more files (download for full content)
About this extraction
This page contains the full source code of the Tinkoff/maskito GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 757 files (1.6 MB), approximately 432.2k tokens, and a symbol index with 503 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.