├── .github ├── CODEOWNERS ├── workflows │ ├── assign-author.yml │ ├── deploy.yml │ ├── build.yml │ └── deploy-preview.yml ├── ISSUE_TEMPLATE │ └── 2-feature-request.yml └── renovate.json ├── .npmrc ├── .husky ├── commit-msg └── pre-commit ├── projects ├── demo-integrations │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── support │ │ │ ├── constants │ │ │ │ ├── index.ts │ │ │ │ └── real-events-support.ts │ │ │ ├── component-react.ts │ │ │ ├── e2e.ts │ │ │ ├── component-index.html │ │ │ ├── assertions │ │ │ │ └── index.ts │ │ │ ├── component.ts │ │ │ └── commands │ │ │ │ └── index.ts │ │ ├── tests │ │ │ ├── utils.ts │ │ │ ├── kit │ │ │ │ ├── number │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── number-examples.cy.ts │ │ │ │ └── date-range │ │ │ │ │ └── date-range-custom-range-separator.cy.ts │ │ │ ├── vue │ │ │ │ └── vue.cy.ts │ │ │ ├── component-testing │ │ │ │ ├── react │ │ │ │ │ └── awesome-input.tsx │ │ │ │ └── angular │ │ │ │ │ └── pattern.cy.ts │ │ │ ├── ssr │ │ │ │ └── ssr.cy.ts │ │ │ └── recipes │ │ │ │ └── plugins │ │ │ │ └── reject.cy.ts │ │ └── plugins │ │ │ └── index.js │ ├── package.json │ ├── tsconfig.json │ ├── vite.config.ts │ └── cypress-react.config.ts ├── vue │ ├── src │ │ └── index.ts │ ├── tsconfig.lib.json │ ├── jest.config.ts │ └── README.md ├── react │ ├── src │ │ ├── index.ts │ │ └── lib │ │ │ └── useIsomorphicLayoutEffect.ts │ ├── tsconfig.lib.json │ ├── .babelrc │ ├── jest.config.ts │ └── README.md ├── kit │ ├── src │ │ └── lib │ │ │ ├── masks │ │ │ ├── date-range │ │ │ │ ├── index.ts │ │ │ │ └── constants.ts │ │ │ ├── date-time │ │ │ │ ├── constants │ │ │ │ │ ├── index.ts │ │ │ │ │ └── date-time-separator.ts │ │ │ │ ├── preprocessors │ │ │ │ │ └── index.ts │ │ │ │ ├── postprocessors │ │ │ │ │ └── index.ts │ │ │ │ ├── utils │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── split-date-time-string.ts │ │ │ │ │ └── is-date-time-string-complete.ts │ │ │ │ ├── index.ts │ │ │ │ └── date-time-params.ts │ │ │ ├── time │ │ │ │ ├── utils │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ └── time-params.ts │ │ │ ├── date │ │ │ │ ├── index.ts │ │ │ │ ├── utils │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── to-date-segments.ts │ │ │ │ │ ├── parse-date.ts │ │ │ │ │ └── stringify-date.ts │ │ │ │ └── date-params.ts │ │ │ └── number │ │ │ │ ├── plugins │ │ │ │ └── index.ts │ │ │ │ ├── utils │ │ │ │ ├── index.ts │ │ │ │ ├── validate-decimal-pseudo-separators.ts │ │ │ │ └── stringify-number.ts │ │ │ │ ├── index.ts │ │ │ │ ├── number-params.ts │ │ │ │ └── processors │ │ │ │ ├── index.ts │ │ │ │ └── number-prefix-postprocessor.ts │ │ │ ├── constants │ │ │ ├── time-fixed-characters.ts │ │ │ ├── default-decimal-pseudo-separators.ts │ │ │ ├── default-min-max-dates.ts │ │ │ ├── date-segment-max-values.ts │ │ │ ├── time-segment-value-lengths.ts │ │ │ ├── meridiem.ts │ │ │ ├── default-pseudo-minuses.ts │ │ │ ├── index.ts │ │ │ └── default-time-segment-bounds.ts │ │ │ ├── utils │ │ │ ├── count-digits.ts │ │ │ ├── dummy.ts │ │ │ ├── is-empty.ts │ │ │ ├── time │ │ │ │ ├── index.ts │ │ │ │ ├── create-time-mask-expression.ts │ │ │ │ ├── to-time-string.ts │ │ │ │ ├── pad-end-time-segments.ts │ │ │ │ ├── pad-start-time-segments.ts │ │ │ │ └── tests │ │ │ │ │ └── enrich-time-segments-with-zeroes.spec.ts │ │ │ ├── find-common-beginning-substr.ts │ │ │ ├── date │ │ │ │ ├── is-date-string-complete.ts │ │ │ │ ├── date-segment-value-length.ts │ │ │ │ ├── get-first-complete-date.ts │ │ │ │ ├── parse-date-range-string.ts │ │ │ │ ├── get-date-segments-order.ts │ │ │ │ ├── tests │ │ │ │ │ └── get-date-segment-value-length.spec.ts │ │ │ │ ├── date-to-segments.ts │ │ │ │ ├── segments-to-date.ts │ │ │ │ └── raise-segment-value-to-min.ts │ │ │ ├── tests │ │ │ │ ├── to-half-width-colon.spec.ts │ │ │ │ ├── is-empty.spec.ts │ │ │ │ ├── find-common-beginning-substr.spec.ts │ │ │ │ └── get-first-complete-date.spec.ts │ │ │ ├── to-half-width-number.ts │ │ │ ├── to-half-width-colon.ts │ │ │ ├── escape-reg-exp.ts │ │ │ ├── clamp.ts │ │ │ └── index.ts │ │ │ ├── types │ │ │ ├── date-segments.ts │ │ │ ├── index.ts │ │ │ ├── time-segments.ts │ │ │ ├── date-mode.ts │ │ │ └── time-mode.ts │ │ │ ├── plugins │ │ │ ├── add-on-focus.ts │ │ │ ├── remove-on-blur.ts │ │ │ ├── index.ts │ │ │ ├── event-handler.ts │ │ │ ├── reject-event.ts │ │ │ └── caret-guard.ts │ │ │ └── processors │ │ │ ├── colon-convert-preprocessor.ts │ │ │ └── fullwidth-to-halfwidth-preprocessor.ts │ ├── tsconfig.lib.json │ ├── jest.config.ts │ └── README.md ├── core │ ├── tsconfig.lib.json │ ├── src │ │ ├── lib │ │ │ ├── types │ │ │ │ ├── selection-range.ts │ │ │ │ ├── element-state.ts │ │ │ │ ├── element-predicate.ts │ │ │ │ ├── plugin.ts │ │ │ │ ├── mask.ts │ │ │ │ ├── maskito-element.ts │ │ │ │ ├── index.ts │ │ │ │ ├── mask-processors.ts │ │ │ │ ├── mask-options.ts │ │ │ │ └── typed-input-event.ts │ │ │ ├── constants │ │ │ │ ├── index.ts │ │ │ │ ├── default-options.ts │ │ │ │ └── default-element-predicate.ts │ │ │ ├── classes │ │ │ │ ├── index.ts │ │ │ │ └── mask-model │ │ │ │ │ └── utils │ │ │ │ │ ├── is-fixed-character.ts │ │ │ │ │ ├── apply-overwrite-mode.ts │ │ │ │ │ ├── validate-value-with-mask.ts │ │ │ │ │ ├── calibrate-value-by-mask.ts │ │ │ │ │ ├── get-leading-fixed-characters.ts │ │ │ │ │ └── guess-valid-value-by-reg-exp.ts │ │ │ ├── plugins │ │ │ │ ├── index.ts │ │ │ │ └── initial-calibration-plugin.ts │ │ │ └── utils │ │ │ │ ├── dom │ │ │ │ ├── get-content-editable-selection.ts │ │ │ │ ├── history-events.ts │ │ │ │ ├── set-content-editable-selection.ts │ │ │ │ └── event-listener.ts │ │ │ │ ├── index.ts │ │ │ │ ├── get-not-empty-selection.ts │ │ │ │ ├── element-states-equality.ts │ │ │ │ ├── get-line-selection.ts │ │ │ │ └── pipe.ts │ │ └── index.ts │ ├── jest.config.ts │ └── README.md ├── phone │ ├── src │ │ ├── lib │ │ │ └── masks │ │ │ │ ├── phone │ │ │ │ ├── constants │ │ │ │ │ ├── index.ts │ │ │ │ │ └── template-filler.ts │ │ │ │ ├── utils │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── get-country-from-number.ts │ │ │ │ │ ├── select-template.ts │ │ │ │ │ ├── cut-phone-by-valid-length.ts │ │ │ │ │ ├── get-phone-template.ts │ │ │ │ │ └── generate-phone-mask.ts │ │ │ │ ├── processors │ │ │ │ │ ├── index.ts │ │ │ │ │ └── phone-length-postprocessor.ts │ │ │ │ ├── index.ts │ │ │ │ └── phone-mask.ts │ │ │ │ └── index.ts │ │ └── index.ts │ ├── tsconfig.lib.json │ ├── jest.config.ts │ └── README.md ├── demo │ ├── src │ │ ├── app │ │ │ ├── utils │ │ │ │ ├── index.ts │ │ │ │ └── add-default-tabs-processor │ │ │ │ │ └── default-tabs │ │ │ │ │ ├── vue-default-tab.ts │ │ │ │ │ ├── react-default-tab.ts │ │ │ │ │ ├── js-default-tab.ts │ │ │ │ │ └── angular-default-tab.ts │ │ │ ├── constants │ │ │ │ ├── index.ts │ │ │ │ └── doc-example-primary-tab.ts │ │ │ ├── modules │ │ │ │ ├── example-primary-tabs-icons │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── vue-logo.component.ts │ │ │ │ │ ├── react-logo.component.ts │ │ │ │ │ ├── angular-logo.component.ts │ │ │ │ │ └── javascript-logo.component.ts │ │ │ │ └── logo │ │ │ │ │ ├── logo.template.html │ │ │ │ │ ├── logo.style.less │ │ │ │ │ └── logo.component.ts │ │ │ └── app.style.less │ │ ├── environments │ │ │ ├── environment.ts │ │ │ └── environment.prod.ts │ │ ├── pages │ │ │ ├── frameworks │ │ │ │ ├── angular │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 4-pipe │ │ │ │ │ │ ├── template.html │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── 1-nested │ │ │ │ │ │ ├── template.html │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── 3-programmatically │ │ │ │ │ │ ├── template.html │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── 6-pattern │ │ │ │ │ │ ├── template.html │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── import-maskito.md │ │ │ │ │ │ ├── 5-custom-unmask-handler │ │ │ │ │ │ └── index.html │ │ │ │ │ │ ├── basic-directive-approach.md │ │ │ │ │ │ ├── 2-nested │ │ │ │ │ │ ├── template.html │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ └── custom-input-example.md │ │ │ │ ├── vue │ │ │ │ │ └── examples │ │ │ │ │ │ ├── best-bad-practice.md │ │ │ │ │ │ ├── use-maskito-basic-usage.md │ │ │ │ │ │ ├── query-nested-input.md │ │ │ │ │ │ └── vue-1 │ │ │ │ │ │ └── component.ts │ │ │ │ └── react │ │ │ │ │ ├── react-doc.style.less │ │ │ │ │ └── examples │ │ │ │ │ ├── best-bad-practice.md │ │ │ │ │ ├── merge-ref.md │ │ │ │ │ ├── 1-use-maskito-basic-usage │ │ │ │ │ ├── use-maskito-basic-usage.tsx │ │ │ │ │ └── example.component.tsx │ │ │ │ │ ├── controlled-input.md │ │ │ │ │ ├── 2-element-predicate │ │ │ │ │ ├── awesome-input.tsx │ │ │ │ │ ├── example.component.tsx │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── 3-merge-ref │ │ │ │ │ └── index.tsx │ │ │ │ │ └── 3-react-hook-form │ │ │ │ │ ├── with-maskito-register.ts │ │ │ │ │ └── index.tsx │ │ │ ├── documentation │ │ │ │ ├── processors │ │ │ │ │ └── examples │ │ │ │ │ │ ├── processor-second-arg-demo.md │ │ │ │ │ │ ├── preprocessor-first-arg-demo.md │ │ │ │ │ │ ├── preprocessor-in-action-demo.md │ │ │ │ │ │ └── postprocessor-in-action.md │ │ │ │ ├── supported-input-types │ │ │ │ │ └── examples │ │ │ │ │ │ ├── search │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── text │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── password │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── url │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── tel │ │ │ │ │ │ └── mask.ts │ │ │ │ ├── mask-expression │ │ │ │ │ └── examples │ │ │ │ │ │ ├── reg-exp-mask-expression-demo.md │ │ │ │ │ │ ├── basic-time-example.md │ │ │ │ │ │ └── dynamic-mask-expression-demo.md │ │ │ │ ├── overwrite-mode │ │ │ │ │ └── examples │ │ │ │ │ │ ├── shift │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── replace │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── dynamic │ │ │ │ │ │ └── mask.ts │ │ │ │ ├── what-is-maskito │ │ │ │ │ └── what-is-maskito.style.less │ │ │ │ ├── plugins │ │ │ │ │ ├── examples │ │ │ │ │ │ ├── 2-strict-composition │ │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── 1-initial-calibration │ │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ │ ├── index.md │ │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── oversimplified-number-mask.md │ │ │ │ │ │ └── 3-change-event │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ └── plugins.style.less │ │ │ │ ├── real-world-form │ │ │ │ │ └── index.less │ │ │ │ ├── element-state │ │ │ │ │ ├── examples │ │ │ │ │ │ └── element-state-demo.md │ │ │ │ │ └── element-state.component.ts │ │ │ │ ├── core-concepts-overview │ │ │ │ │ ├── core-concepts-overview.styles.less │ │ │ │ │ └── examples │ │ │ │ │ │ └── maskito-public-api-demo.md │ │ │ │ ├── transformer │ │ │ │ │ ├── examples │ │ │ │ │ │ └── utility-in-action-demo.md │ │ │ │ │ └── transformer.component.ts │ │ │ │ └── next-steps │ │ │ │ │ └── next-steps.component.ts │ │ │ ├── phone │ │ │ │ ├── phone-doc.style.less │ │ │ │ └── examples │ │ │ │ │ ├── 1-basic │ │ │ │ │ └── mask.ts │ │ │ │ │ ├── 2-validation │ │ │ │ │ └── mask.ts │ │ │ │ │ ├── 3-non-strict │ │ │ │ │ └── mask.ts │ │ │ │ │ ├── 4-lazy-metadata │ │ │ │ │ └── simple.md │ │ │ │ │ └── 5-focus-blur-events │ │ │ │ │ └── mask.ts │ │ │ ├── kit │ │ │ │ ├── date │ │ │ │ │ ├── date-mask-doc.style.less │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-localization │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-min-max │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── maskito-parse-stringify-date-demo.md │ │ │ │ ├── time │ │ │ │ │ ├── time-mask-doc.style.less │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-modes │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 5-time-segments-min-max │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── maskito-parse-stringify-time-demo.md │ │ │ │ │ │ ├── 4-affixes │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-step │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── 2-am-pm │ │ │ │ │ │ └── mask.ts │ │ │ │ ├── number │ │ │ │ │ ├── examples │ │ │ │ │ │ ├── 1-high-precision │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 5-custom-minus-sign │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 6-minus-before-prefix │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-separators │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 4-decimal-zero-padding │ │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── 7-dynamic-decimal-zero-padding │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── 3-postfix │ │ │ │ │ │ │ └── mask.ts │ │ │ │ │ └── helpers │ │ │ │ │ │ ├── stringify-number.md │ │ │ │ │ │ ├── parse-number-as-number-type.md │ │ │ │ │ │ └── parse-number-as-bigint-type.md │ │ │ │ ├── date-range │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-date-localization │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 4-range-separator │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-min-max-length │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ └── 2-min-max │ │ │ │ │ │ └── mask.ts │ │ │ │ ├── date-time │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 4-time-step │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 1-date-time-localization │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 2-date-time-separator │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── 3-min-max │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── maskito-parse-stringify-date-time-demo.md │ │ │ │ │ │ └── 5-am-pm │ │ │ │ │ │ └── mask.ts │ │ │ │ └── plugins │ │ │ │ │ └── examples │ │ │ │ │ ├── 4-reject │ │ │ │ │ ├── index.md │ │ │ │ │ ├── animation.css │ │ │ │ │ └── mask.ts │ │ │ │ │ ├── 2-caret-guard │ │ │ │ │ ├── mask.ts │ │ │ │ │ └── component.ts │ │ │ │ │ └── 1-selection-handler │ │ │ │ │ └── mask.ts │ │ │ ├── recipes │ │ │ │ ├── textarea │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-latin │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ └── maskito-with-textarea.md │ │ │ │ ├── content-editable │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-time │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ ├── 2-multi-line │ │ │ │ │ │ └── mask.ts │ │ │ │ │ │ ├── vanilla-js-tab.md │ │ │ │ │ │ └── maskito-with-content-editable.md │ │ │ │ ├── card │ │ │ │ │ └── examples │ │ │ │ │ │ └── 1-basic │ │ │ │ │ │ └── style.less │ │ │ │ ├── placeholder │ │ │ │ │ └── examples │ │ │ │ │ │ └── 1-cvc-code │ │ │ │ │ │ └── mask.ts │ │ │ │ ├── prefix │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-pattern-mask │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ └── 2-postprocessor │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ └── component.ts │ │ │ │ ├── postfix │ │ │ │ │ └── examples │ │ │ │ │ │ ├── 1-pattern-mask │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ └── component.ts │ │ │ │ │ │ └── 2-postprocessor │ │ │ │ │ │ ├── mask.ts │ │ │ │ │ │ └── component.ts │ │ │ │ └── phone │ │ │ │ │ └── examples │ │ │ │ │ ├── 2-kz-phone │ │ │ │ │ ├── template.html │ │ │ │ │ └── component.ts │ │ │ │ │ └── 1-us-phone │ │ │ │ │ └── mask.ts │ │ │ └── stackblitz │ │ │ │ ├── index.ts │ │ │ │ ├── components │ │ │ │ ├── stackblitz-starter │ │ │ │ │ └── stackblitz-starter.style.less │ │ │ │ └── stackblitz-edit-button │ │ │ │ │ ├── stackblitz-edit-button.style.less │ │ │ │ │ └── stackblitz-edit-button.component.ts │ │ │ │ └── files │ │ │ │ ├── example.ts.md │ │ │ │ └── starter.ts.md │ │ ├── assets │ │ │ ├── favicon │ │ │ │ ├── favicon-192.png │ │ │ │ ├── favicon-512.png │ │ │ │ ├── safari-favicon.png │ │ │ │ └── apple-touch-icon.png │ │ │ ├── manifest.webmanifest │ │ │ └── icons │ │ │ │ ├── vue.svg │ │ │ │ ├── react.svg │ │ │ │ └── stackblitz.svg │ │ ├── main.ts │ │ ├── test-setup.ts │ │ ├── styles.less │ │ └── typings.d.ts │ ├── tsconfig.app.json │ ├── jest.config.ts │ ├── .gitignore │ └── esbuild-plugins │ │ └── vue-esm.plugin.js └── angular │ ├── src │ ├── test-setup.ts │ ├── index.ts │ └── lib │ │ ├── maskito.pipe.ts │ │ └── pattern.directive.ts │ ├── tsconfig.lib.prod.json │ ├── ng-package.json │ ├── jest.config.ts │ └── README.md ├── .release-it.js ├── .firebaserc ├── jest.config.ts ├── .editorconfig ├── firebase.json ├── tsconfig.eslint.json ├── jest.preset.js ├── tsconfig.build.json ├── tsconfig.spec.json ├── codecov.yml ├── .cspell.json ├── .gitignore └── tsconfig.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @taiga-family/core-team 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | loglevel=error 3 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | npm run typecheck 3 | -------------------------------------------------------------------------------- /projects/demo-integrations/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /projects/vue/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/maskito'; 2 | -------------------------------------------------------------------------------- /projects/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/useMaskito'; 2 | -------------------------------------------------------------------------------- /.release-it.js: -------------------------------------------------------------------------------- 1 | module.exports = require('@taiga-ui/release-it-config'); 2 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "maskito" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-range/index.ts: -------------------------------------------------------------------------------- 1 | export * from './date-range-mask'; 2 | -------------------------------------------------------------------------------- /projects/core/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json" 3 | } 4 | -------------------------------------------------------------------------------- /projects/kit/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json" 3 | } 4 | -------------------------------------------------------------------------------- /projects/phone/src/lib/masks/phone/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './template-filler'; 2 | -------------------------------------------------------------------------------- /projects/phone/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json" 3 | } 4 | -------------------------------------------------------------------------------- /projects/vue/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json" 3 | } 4 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './date-time-separator'; 2 | -------------------------------------------------------------------------------- /projects/demo-integrations/src/support/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './real-events-support'; 2 | -------------------------------------------------------------------------------- /projects/phone/src/lib/masks/phone/constants/template-filler.ts: -------------------------------------------------------------------------------- 1 | export const TEMPLATE_FILLER = 'x'; 2 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/time-fixed-characters.ts: -------------------------------------------------------------------------------- 1 | export const TIME_FIXED_CHARACTERS = [':', '.']; 2 | -------------------------------------------------------------------------------- /projects/demo-integrations/src/support/component-react.ts: -------------------------------------------------------------------------------- 1 | import './assertions'; 2 | import './commands'; 3 | -------------------------------------------------------------------------------- /projects/demo/src/app/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './add-default-tabs-processor/add-default-tabs-processor'; 2 | -------------------------------------------------------------------------------- /projects/demo/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | }; 4 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/preprocessors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './valid-date-time-preprocessor'; 2 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/selection-range.ts: -------------------------------------------------------------------------------- 1 | export type SelectionRange = readonly [from: number, to: number]; 2 | -------------------------------------------------------------------------------- /projects/demo/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | }; 4 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/angular/examples/4-pipe/template.html: -------------------------------------------------------------------------------- 1 | Balance: ${{ value | maskito: options }} 2 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/postprocessors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './min-max-date-time-postprocessor'; 2 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/time/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './parse-time'; 2 | export * from './stringify-time'; 3 | -------------------------------------------------------------------------------- /projects/phone/src/index.ts: -------------------------------------------------------------------------------- 1 | export {maskitoGetCountryFromNumber, maskitoPhoneOptionsGenerator} from './lib/masks'; 2 | -------------------------------------------------------------------------------- /projects/demo/src/app/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './demo-path'; 2 | export * from './doc-example-primary-tab'; 3 | -------------------------------------------------------------------------------- /projects/core/src/lib/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from './default-element-predicate'; 2 | export * from './default-options'; 3 | -------------------------------------------------------------------------------- /projects/phone/src/lib/masks/index.ts: -------------------------------------------------------------------------------- 1 | export {maskitoGetCountryFromNumber, maskitoPhoneOptionsGenerator} from './phone'; 2 | -------------------------------------------------------------------------------- /projects/angular/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import {setupZoneTestEnv} from 'jest-preset-angular/setup-env/zone'; 2 | 3 | setupZoneTestEnv(); 4 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date/index.ts: -------------------------------------------------------------------------------- 1 | export * from './date-mask'; 2 | export * from './date-params'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/time/index.ts: -------------------------------------------------------------------------------- 1 | export * from './time-mask'; 2 | export * from './time-params'; 3 | export * from './utils'; 4 | -------------------------------------------------------------------------------- /projects/core/src/lib/classes/index.ts: -------------------------------------------------------------------------------- 1 | export {MaskHistory} from './mask-history'; 2 | export {MaskModel} from './mask-model/mask-model'; 3 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/default-decimal-pseudo-separators.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_DECIMAL_PSEUDO_SEPARATORS = ['.', ',', 'б', 'ю']; 2 | -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon/favicon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/maskito/HEAD/projects/demo/src/assets/favicon/favicon-192.png -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon/favicon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/maskito/HEAD/projects/demo/src/assets/favicon/favicon-512.png -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/count-digits.ts: -------------------------------------------------------------------------------- 1 | export function countDigits(str: string): number { 2 | return str.replaceAll(/\W/g, '').length; 3 | } 4 | -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon/safari-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/maskito/HEAD/projects/demo/src/assets/favicon/safari-favicon.png -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date/utils/index.ts: -------------------------------------------------------------------------------- 1 | export {maskitoParseDate} from './parse-date'; 2 | export {maskitoStringifyDate} from './stringify-date'; 3 | -------------------------------------------------------------------------------- /projects/kit/src/lib/types/date-segments.ts: -------------------------------------------------------------------------------- 1 | export interface MaskitoDateSegments { 2 | day: T; 3 | month: T; 4 | year: T; 5 | } 6 | -------------------------------------------------------------------------------- /projects/angular/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/maskito.directive'; 2 | export * from './lib/maskito.pipe'; 3 | export * from './lib/pattern.directive'; 4 | -------------------------------------------------------------------------------- /projects/demo/src/assets/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taiga-family/maskito/HEAD/projects/demo/src/assets/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/processors/examples/processor-second-arg-demo.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | 'insert' | 'deleteForward' | 'deleteBackward' | 'validation'; 3 | ``` 4 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/constants/date-time-separator.ts: -------------------------------------------------------------------------------- 1 | export const DATE_TIME_SEPARATOR = ', '; 2 | export const POSSIBLE_DATE_TIME_SEPARATOR = [',', ' ']; 3 | -------------------------------------------------------------------------------- /projects/kit/src/lib/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './date-mode'; 2 | export * from './date-segments'; 3 | export * from './time-mode'; 4 | export * from './time-segments'; 5 | -------------------------------------------------------------------------------- /projects/demo/src/pages/phone/phone-doc.style.less: -------------------------------------------------------------------------------- 1 | .phone { 2 | max-inline-size: 25rem; 3 | 4 | &:not(:last-child) { 5 | margin-block-end: 1rem; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/kit/src/lib/types/time-segments.ts: -------------------------------------------------------------------------------- 1 | export interface MaskitoTimeSegments { 2 | hours: T; 3 | minutes: T; 4 | seconds: T; 5 | milliseconds: T; 6 | } 7 | -------------------------------------------------------------------------------- /projects/core/src/lib/classes/mask-model/utils/is-fixed-character.ts: -------------------------------------------------------------------------------- 1 | export function isFixedCharacter(char: RegExp | string): char is string { 2 | return typeof char === 'string'; 3 | } 4 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date/date-mask-doc.style.less: -------------------------------------------------------------------------------- 1 | .input-date { 2 | max-inline-size: 25rem; 3 | 4 | &:not(:last-child) { 5 | margin-block-end: 1rem; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/time/time-mask-doc.style.less: -------------------------------------------------------------------------------- 1 | .input-time { 2 | max-inline-size: 25rem; 3 | 4 | &:not(:last-child) { 5 | margin-block-end: 1rem; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/number/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './leading-zeroes-validation.plugin'; 2 | export * from './min-max.plugin'; 3 | export * from './not-empty-integer.plugin'; 4 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/angular/examples/1-nested/template.html: -------------------------------------------------------------------------------- 1 | 5 | Name on the card 6 | 7 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/default-min-max-dates.ts: -------------------------------------------------------------------------------- 1 | export const DEFAULT_MIN_DATE = new Date('0001-01-01T00:00'); 2 | export const DEFAULT_MAX_DATE = new Date('9999-12-31T23:59:59.999'); 3 | -------------------------------------------------------------------------------- /projects/angular/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "include": ["**/*"], 4 | "compilerOptions": { 5 | "declarationMap": false 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/demo/src/app/modules/example-primary-tabs-icons/index.ts: -------------------------------------------------------------------------------- 1 | export * from './angular-logo.component'; 2 | export * from './javascript-logo.component'; 3 | export * from './react-logo.component'; 4 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/time/examples/1-modes/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoTimeOptionsGenerator({ 4 | mode: 'HH:MM:SS', 5 | }); 6 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/textarea/examples/1-latin/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | export default { 4 | mask: /^[a-z1-9\s.,/]+$/i, 5 | } satisfies MaskitoOptions; 6 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/dummy.ts: -------------------------------------------------------------------------------- 1 | export function identity(x: T): T { 2 | return x; 3 | } 4 | 5 | // eslint-disable-next-line @typescript-eslint/no-empty-function 6 | export function noop(): void {} 7 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/is-empty.ts: -------------------------------------------------------------------------------- 1 | export function isEmpty(entity: object | null | undefined): boolean { 2 | return !entity || (typeof entity === 'object' && Object.keys(entity).length === 0); 3 | } 4 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import {getJestProjectsAsync} from '@nx/jest'; 2 | import type {Config} from 'jest'; 3 | 4 | export default async (): Promise => ({ 5 | projects: await getJestProjectsAsync(), 6 | }); 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date/examples/1-localization/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateOptionsGenerator({mode: 'yyyy/mm/dd', separator: '/'}); 4 | -------------------------------------------------------------------------------- /projects/react/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.build.json", 3 | "files": ["../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/supported-input-types/examples/search/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | export default { 4 | mask: /^[a-z]+$/i, 5 | } satisfies MaskitoOptions; 6 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/content-editable/examples/1-time/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoTimeOptionsGenerator({ 4 | mode: 'HH:MM', 5 | }); 6 | -------------------------------------------------------------------------------- /projects/angular/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/angular", 4 | "lib": { 5 | "entryFile": "src/index.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/element-state.ts: -------------------------------------------------------------------------------- 1 | import type {SelectionRange} from './selection-range'; 2 | 3 | export interface ElementState { 4 | readonly value: string; 5 | readonly selection: SelectionRange; 6 | } 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/supported-input-types/examples/text/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoTimeOptionsGenerator({ 4 | mode: 'HH:MM', 5 | }); 6 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/vue/examples/best-bad-practice.md: -------------------------------------------------------------------------------- 1 | ```html 2 | 3 | 4 | 5 | 6 | 7 | ``` 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/content-editable/examples/2-multi-line/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | export default { 4 | mask: /^[a-z\s.,/!?]+$/i, 5 | } satisfies MaskitoOptions; 6 | -------------------------------------------------------------------------------- /projects/react/src/lib/useIsomorphicLayoutEffect.ts: -------------------------------------------------------------------------------- 1 | import {useEffect, useLayoutEffect} from 'react'; 2 | 3 | export const useIsomorphicLayoutEffect = 4 | typeof window !== 'undefined' ? useLayoutEffect : useEffect; 5 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/supported-input-types/examples/password/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | export default { 4 | mask: [/\d/, /\d/, /\d/], 5 | } satisfies MaskitoOptions; 6 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './is-date-time-string-complete'; 2 | export * from './parse-date-time'; 3 | export * from './split-date-time-string'; 4 | export * from './stringify-date-time'; 5 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/element-predicate.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoElement} from './maskito-element'; 2 | 3 | export type MaskitoElementPredicate = ( 4 | element: HTMLElement, 5 | ) => MaskitoElement | Promise; 6 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/mask-expression/examples/reg-exp-mask-expression-demo.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import {Maskito} from '@maskito/core'; 3 | 4 | const onlyDigitsInput = new Maskito(element, { 5 | mask: /^\d+$/, 6 | }); 7 | ``` 8 | -------------------------------------------------------------------------------- /projects/react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@nx/react/babel", 5 | { 6 | "runtime": "automatic" 7 | } 8 | ] 9 | ], 10 | "plugins": [] 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/mask-expression/examples/basic-time-example.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import {Maskito} from '@maskito/core'; 3 | 4 | const timeInput = new Maskito(element, { 5 | mask: [/\d/, /\d/, ':', /\d/, /\d/], 6 | }); 7 | ``` 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/number/examples/1-high-precision/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoNumberOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoNumberOptionsGenerator({ 4 | maximumFractionDigits: 8, 5 | min: 0, 6 | }); 7 | -------------------------------------------------------------------------------- /projects/demo/src/assets/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "icons": [ 3 | {"src": "/favicon-192.png", "type": "image/png", "sizes": "192x192"}, 4 | {"src": "/favicon-512.png", "type": "image/png", "sizes": "512x512"} 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date/date-params.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoDateMode} from '../../types'; 2 | 3 | export interface MaskitoDateParams { 4 | mode: MaskitoDateMode; 5 | separator?: string; 6 | max?: Date; 7 | min?: Date; 8 | } 9 | -------------------------------------------------------------------------------- /projects/demo/src/app/constants/doc-example-primary-tab.ts: -------------------------------------------------------------------------------- 1 | export const DocExamplePrimaryTab = { 2 | MaskitoOptions: 'mask', 3 | JavaScript: 'JavaScript', 4 | Angular: 'Angular', 5 | React: 'React', 6 | Vue: 'Vue', 7 | } as const; 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/number/examples/5-custom-minus-sign/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoNumberOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoNumberOptionsGenerator({ 4 | minusSign: '-', 5 | thousandSeparator: '', 6 | }); 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/stackblitz/index.ts: -------------------------------------------------------------------------------- 1 | export * from './components/stackblitz-edit-button/stackblitz-edit-button.component'; 2 | export * from './components/stackblitz-starter/stackblitz-starter.component'; 3 | export * from './stackblitz.service'; 4 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/date-segment-max-values.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoDateSegments} from '../types'; 2 | 3 | export const DATE_SEGMENTS_MAX_VALUES: MaskitoDateSegments = { 4 | day: 31, 5 | month: 12, 6 | year: 9999, 7 | }; 8 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/index.ts: -------------------------------------------------------------------------------- 1 | export * from './constants'; 2 | export * from './date-time-mask'; 3 | export * from './date-time-params'; 4 | export * from './postprocessors'; 5 | export * from './preprocessors'; 6 | export * from './utils'; 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/react/react-doc.style.less: -------------------------------------------------------------------------------- 1 | .no-tabs { 2 | padding-block-start: 0; 3 | 4 | ::ng-deep .t-example { 5 | margin-block-start: 0; 6 | } 7 | } 8 | 9 | section { 10 | margin-block-start: 3.5rem; 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-range/examples/1-date-localization/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateRangeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateRangeOptionsGenerator({ 4 | mode: 'mm/dd/yyyy', 5 | dateSeparator: '/', 6 | }); 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-range/examples/4-range-separator/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateRangeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateRangeOptionsGenerator({ 4 | mode: 'dd/mm/yyyy', 5 | rangeSeparator: ' ~ ', 6 | }); 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/phone/examples/1-basic/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoPhoneOptionsGenerator} from '@maskito/phone'; 2 | import metadata from 'libphonenumber-js/min/metadata'; 3 | 4 | export default maskitoPhoneOptionsGenerator({countryIsoCode: 'KZ', metadata}); 5 | -------------------------------------------------------------------------------- /projects/kit/src/lib/types/date-mode.ts: -------------------------------------------------------------------------------- 1 | export type MaskitoDateMode = 2 | | 'dd/mm' 3 | | 'dd/mm/yyyy' 4 | | 'mm/dd' 5 | | 'mm/dd/yyyy' 6 | | 'mm/yy' 7 | | 'mm/yyyy' 8 | | 'yyyy' 9 | | 'yyyy/mm' 10 | | 'yyyy/mm/dd'; 11 | -------------------------------------------------------------------------------- /projects/phone/src/lib/masks/phone/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cut-phone-by-valid-length'; 2 | export * from './generate-phone-mask'; 3 | export * from './get-country-from-number'; 4 | export * from './get-phone-template'; 5 | export * from './select-template'; 6 | -------------------------------------------------------------------------------- /projects/core/src/lib/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './broken-prevent-default.plugin'; 2 | export * from './change-event-plugin'; 3 | export * from './double-space.plugin'; 4 | export * from './initial-calibration-plugin'; 5 | export * from './strict-composition-plugin'; 6 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-time/examples/4-time-step/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateTimeOptionsGenerator({ 4 | dateMode: 'dd/mm/yyyy', 5 | timeMode: 'HH:MM', 6 | timeStep: 1, 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/phone/examples/2-validation/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoPhoneOptionsGenerator} from '@maskito/phone'; 2 | import metadata from 'libphonenumber-js/mobile/metadata'; 3 | 4 | export default maskitoPhoneOptionsGenerator({countryIsoCode: 'HU', metadata}); 5 | -------------------------------------------------------------------------------- /projects/demo/src/pages/stackblitz/components/stackblitz-starter/stackblitz-starter.style.less: -------------------------------------------------------------------------------- 1 | @import '@taiga-ui/core/styles/taiga-ui-local.less'; 2 | 3 | .loader { 4 | .fullsize(fixed); 5 | 6 | z-index: 1; 7 | background: var(--tui-background-base); 8 | } 9 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/overwrite-mode/examples/shift/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | const maskitoOptions: MaskitoOptions = { 4 | mask: /^\d+$/, 5 | overwriteMode: 'shift', 6 | }; 7 | 8 | export default maskitoOptions; 9 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/angular/examples/3-programmatically/template.html: -------------------------------------------------------------------------------- 1 | 5 | 11 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date/examples/2-min-max/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateOptionsGenerator({ 4 | mode: 'dd/mm/yyyy', 5 | min: new Date(2000, 0, 1), 6 | max: new Date(2025, 4, 10), 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/app/app.style.less: -------------------------------------------------------------------------------- 1 | @import '@taiga-ui/core/styles/taiga-ui-local.less'; 2 | 3 | :host { 4 | display: block; 5 | font: var(--tui-font-text-m); 6 | color: var(--tui-text-primary); 7 | } 8 | 9 | .link { 10 | margin-inline-start: 1rem; 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import {bootstrapApplication} from '@angular/platform-browser'; 2 | 3 | import {App} from './app/app.component'; 4 | import {APP_CONFIG} from './app/app.config'; 5 | 6 | bootstrapApplication(App, APP_CONFIG).catch((err: unknown) => console.error(err)); 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/overwrite-mode/examples/replace/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | const maskitoOptions: MaskitoOptions = { 4 | mask: /^\d+$/, 5 | overwriteMode: 'replace', 6 | }; 7 | 8 | export default maskitoOptions; 9 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/supported-input-types/examples/url/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | export default { 4 | // oversimplified version of url mask for demo purposes 5 | mask: /^[\w/:.@]+$/, 6 | } satisfies MaskitoOptions; 7 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/number/examples/6-minus-before-prefix/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoNumberOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoNumberOptionsGenerator({ 4 | minusSign: '-', 5 | prefix: '$', 6 | negativePattern: 'minusFirst', 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/stackblitz/components/stackblitz-edit-button/stackblitz-edit-button.style.less: -------------------------------------------------------------------------------- 1 | @import '@taiga-ui/core/styles/taiga-ui-local.less'; 2 | 3 | button { 4 | @media @tui-mobile { 5 | font-size: 0; 6 | margin-inline-end: -1rem; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/time-segment-value-lengths.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoTimeSegments} from '../types'; 2 | 3 | export const TIME_SEGMENT_VALUE_LENGTHS: MaskitoTimeSegments = { 4 | hours: 2, 5 | minutes: 2, 6 | seconds: 2, 7 | milliseconds: 3, 8 | }; 9 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/number/examples/2-separators/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoNumberOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoNumberOptionsGenerator({ 4 | decimalSeparator: ',', 5 | thousandSeparator: '.', 6 | maximumFractionDigits: 2, 7 | }); 8 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/plugin.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from './mask-options'; 2 | import type {MaskitoElement} from './maskito-element'; 3 | 4 | export type MaskitoPlugin = ( 5 | element: MaskitoElement, 6 | options: Required, 7 | ) => (() => void) | void; 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-range/examples/3-min-max-length/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateRangeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateRangeOptionsGenerator({ 4 | mode: 'dd/mm/yyyy', 5 | minLength: {day: 3}, 6 | maxLength: {month: 1}, 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-time/examples/1-date-time-localization/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateTimeOptionsGenerator({ 4 | dateMode: 'mm/dd/yyyy', 5 | timeMode: 'HH:MM', 6 | dateSeparator: '/', 7 | }); 8 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/mask.ts: -------------------------------------------------------------------------------- 1 | import type {ElementState} from './element-state'; 2 | 3 | export type MaskitoMaskExpression = Array | RegExp; 4 | 5 | export type MaskitoMask = 6 | | MaskitoMaskExpression 7 | | ((elementState: ElementState) => MaskitoMaskExpression); 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-range/examples/2-min-max/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateRangeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateRangeOptionsGenerator({ 4 | mode: 'dd/mm/yyyy', 5 | min: new Date('1711-11-19'), 6 | max: new Date('1765-04-15'), 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateTimeOptionsGenerator({ 4 | dateMode: 'dd/mm/yyyy', 5 | timeMode: 'HH:MM', 6 | dateTimeSeparator: '; ', 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/card/examples/1-basic/style.less: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | display: flex; 3 | max-inline-size: 30rem; 4 | } 5 | 6 | .number { 7 | flex: 1 1 11rem; 8 | } 9 | 10 | .cvv { 11 | flex: 1 0 4rem; 12 | } 13 | 14 | .expired { 15 | flex: 1 0 5rem; 16 | } 17 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/meridiem.ts: -------------------------------------------------------------------------------- 1 | import {CHAR_NO_BREAK_SPACE} from './unicode-characters'; 2 | 3 | export const ANY_MERIDIEM_CHARACTER_RE = new RegExp(`[${CHAR_NO_BREAK_SPACE}APM]+$`, 'g'); 4 | export const ALL_MERIDIEM_CHARACTERS_RE = new RegExp(`${CHAR_NO_BREAK_SPACE}[AP]M$`, 'g'); 5 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/time/examples/5-time-segments-min-max/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoTimeOptionsGenerator({ 4 | mode: 'HH:MM', 5 | timeSegmentMaxValues: {hours: 12}, 6 | timeSegmentMinValues: {hours: 1}, 7 | }); 8 | -------------------------------------------------------------------------------- /projects/demo/src/test-setup.ts: -------------------------------------------------------------------------------- 1 | import '@taiga-ui/testing/setup-jest'; 2 | 3 | import {enableProdMode} from '@angular/core'; 4 | 5 | /** 6 | * - https://github.com/angular/angular/issues/54096 7 | * - https://github.com/thymikee/jest-preset-angular/issues/2582 8 | */ 9 | enableProdMode(); 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/angular/examples/6-pattern/template.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/placeholder/examples/1-cvc-code/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | import {maskitoWithPlaceholder} from '@maskito/kit'; 3 | 4 | export default { 5 | ...maskitoWithPlaceholder('xxx'), 6 | mask: /^\d{0,3}$/, 7 | } satisfies MaskitoOptions; 8 | -------------------------------------------------------------------------------- /projects/kit/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'kit', 3 | preset: '../../jest.preset.js', 4 | transform: { 5 | '^.+\\.[tj]sx?$': 'ts-jest', 6 | }, 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 8 | coverageDirectory: '../../coverage/kit', 9 | }; 10 | -------------------------------------------------------------------------------- /projects/phone/src/lib/masks/phone/processors/index.ts: -------------------------------------------------------------------------------- 1 | export {cutInitCountryCodePreprocessor} from './cut-init-country-code-preprocessor'; 2 | export {phoneLengthPostprocessorGenerator} from './phone-length-postprocessor'; 3 | export {validatePhonePreprocessorGenerator} from './validate-phone-preprocessor'; 4 | -------------------------------------------------------------------------------- /projects/core/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'core', 3 | preset: '../../jest.preset.js', 4 | transform: { 5 | '^.+\\.[tj]sx?$': 'ts-jest', 6 | }, 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 8 | coverageDirectory: '../../coverage/core', 9 | }; 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/what-is-maskito/what-is-maskito.style.less: -------------------------------------------------------------------------------- 1 | .cards { 2 | display: flex; 3 | flex-wrap: wrap; 4 | justify-content: space-between; 5 | gap: 2rem; 6 | 7 | & [tuiCardLarge] { 8 | flex: 1; 9 | min-inline-size: 18rem; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/src/pages/phone/examples/3-non-strict/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoPhoneOptionsGenerator} from '@maskito/phone'; 2 | import metadata from 'libphonenumber-js/min/metadata'; 3 | 4 | export default maskitoPhoneOptionsGenerator({ 5 | metadata, 6 | strict: false, 7 | countryIsoCode: 'RU', 8 | }); 9 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/number/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './extract-affixes'; 2 | export * from './generate-mask-expression'; 3 | export * from './number-parts'; 4 | export * from './parse-number'; 5 | export * from './stringify-number-without-exp'; 6 | export * from './validate-decimal-pseudo-separators'; 7 | -------------------------------------------------------------------------------- /projects/kit/src/lib/types/time-mode.ts: -------------------------------------------------------------------------------- 1 | export type MaskitoTimeMode = 2 | | 'HH AA' 3 | | 'HH:MM AA' 4 | | 'HH:MM:SS AA' 5 | | 'HH:MM:SS.MSS AA' 6 | | 'HH:MM:SS.MSS' 7 | | 'HH:MM:SS' 8 | | 'HH:MM' 9 | | 'HH' 10 | | 'MM:SS.MSS' 11 | | 'MM:SS' 12 | | 'SS.MSS'; 13 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/time/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-time-mask-expression'; 2 | export * from './enrich-time-segments-with-zeroes'; 3 | export * from './pad-end-time-segments'; 4 | export * from './pad-start-time-segments'; 5 | export * from './parse-time-string'; 6 | export * from './to-time-string'; 7 | -------------------------------------------------------------------------------- /projects/core/src/lib/constants/default-options.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '../types'; 2 | 3 | export const MASKITO_DEFAULT_OPTIONS: Required = { 4 | mask: /^.*$/, 5 | preprocessors: [], 6 | postprocessors: [], 7 | plugins: [], 8 | overwriteMode: 'shift', 9 | }; 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/supported-input-types/examples/tel/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoPhoneOptionsGenerator} from '@maskito/phone'; 2 | import metadata from 'libphonenumber-js/metadata.min.json'; 3 | 4 | export default maskitoPhoneOptionsGenerator({ 5 | metadata, 6 | countryIsoCode: 'US', 7 | }); 8 | -------------------------------------------------------------------------------- /projects/phone/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'phone', 3 | preset: '../../jest.preset.js', 4 | transform: { 5 | '^.+\\.[tj]sx?$': 'ts-jest', 6 | }, 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 8 | coverageDirectory: '../../coverage/phone', 9 | }; 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /projects/react/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'react', 3 | preset: '../../jest.preset.js', 4 | transform: { 5 | '^.+\\.[tj]sx?$': 'ts-jest', 6 | }, 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 8 | coverageDirectory: '../../coverage/projects/react', 9 | }; 10 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/maskito-element.ts: -------------------------------------------------------------------------------- 1 | export type TextfieldLike = Pick< 2 | HTMLInputElement, 3 | | 'maxLength' 4 | | 'select' 5 | | 'selectionEnd' 6 | | 'selectionStart' 7 | | 'setSelectionRange' 8 | | 'value' 9 | >; 10 | export type MaskitoElement = HTMLElement & TextfieldLike; 11 | -------------------------------------------------------------------------------- /projects/demo/src/assets/icons/vue.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist/demo/browser", 4 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], 5 | "rewrites": [ 6 | { 7 | "source": "**", 8 | "destination": "/index.html" 9 | } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/plugins/examples/2-strict-composition/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | import {maskitoStrictCompositionPlugin} from '@maskito/core'; 3 | 4 | export default { 5 | mask: /^[0-90-9]*$/, 6 | plugins: [maskitoStrictCompositionPlugin()], 7 | } satisfies MaskitoOptions; 8 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/angular/examples/import-maskito.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import {Component} from '@angular/core'; 3 | import {MaskitoDirective} from '@maskito/angular'; 4 | 5 | @Component({ 6 | // ... 7 | imports: [ 8 | MaskitoDirective, 9 | // ... 10 | ], 11 | }) 12 | export class YourComponent {} 13 | ``` 14 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/number/examples/4-decimal-zero-padding/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoNumberOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoNumberOptionsGenerator({ 4 | minimumFractionDigits: 2, 5 | maximumFractionDigits: 2, 6 | decimalSeparator: '.', 7 | min: 0, 8 | prefix: '$', 9 | }); 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/mask-expression/examples/dynamic-mask-expression-demo.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import {Maskito} from '@maskito/core'; 3 | 4 | let howManyWordsAllowed = 5; 5 | 6 | const maxWordInput = new Maskito(element, { 7 | mask: (elementState) => new RegExp('^(\\w+\\s?){0,' + howManyWordsAllowed + '}$'), 8 | }); 9 | ``` 10 | -------------------------------------------------------------------------------- /projects/demo-integrations/src/tests/utils.ts: -------------------------------------------------------------------------------- 1 | export function range(from: number, to: number): number[] { 2 | return new Array(to - from + 1).fill(null).map((_, i) => from + i); 3 | } 4 | 5 | export function withCaretLabel(value: string, caretIndex: number): string { 6 | return `${value.slice(0, caretIndex)}|${value.slice(caretIndex)}`; 7 | } 8 | -------------------------------------------------------------------------------- /projects/demo-integrations/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@maskito/demo-cypress", 3 | "private": true, 4 | "devDependencies": { 5 | "@nx/cypress": "21.6.3", 6 | "@nx/vite": "21.6.3", 7 | "@vitejs/plugin-react": "4.7.0", 8 | "cypress": "14.5.4", 9 | "cypress-real-events": "1.15.0" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/src/app/modules/logo/logo.template.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | Maskito 13 | 14 | 15 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/react/examples/best-bad-practice.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | // Best Practice ✅ 3 | useMaskito({ 4 | options: maskitoOptions, 5 | elementPredicate: predicate, 6 | }); 7 | 8 | // Anti-Pattern ❌ 9 | useMaskito({ 10 | options: {mask: /^.*$/}, 11 | elementPredicate: () => e.querySelector('input#my-input'), 12 | }); 13 | ``` 14 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/find-common-beginning-substr.ts: -------------------------------------------------------------------------------- 1 | export function findCommonBeginningSubstr(a: string, b: string): string { 2 | let res = ''; 3 | 4 | for (let i = 0; i < a.length; i++) { 5 | if (a[i] !== b[i]) { 6 | return res; 7 | } 8 | 9 | res += a[i]; 10 | } 11 | 12 | return res; 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "baseUrl": ".", 6 | "strict": false 7 | }, 8 | "include": ["projects", "scripts", "jest.config.ts", "eslint.config.ts"], 9 | "exclude": ["**/node_modules", "**/schematics/**", "**/.*/", "*.js"] 10 | } 11 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | const {resolve} = require('path'); 3 | 4 | module.exports = { 5 | ...nxPreset, 6 | globals: { 7 | 'ts-jest': { 8 | tsconfig: resolve(__dirname, 'tsconfig.spec.json'), 9 | stringifyContentPathRegex: '\\.(html|svg)$', 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /projects/core/src/lib/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './element-predicate'; 2 | export * from './element-state'; 3 | export * from './mask'; 4 | export * from './mask-options'; 5 | export * from './mask-processors'; 6 | export * from './maskito-element'; 7 | export * from './plugin'; 8 | export * from './selection-range'; 9 | export * from './typed-input-event'; 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/prefix/examples/1-pattern-mask/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | 3 | export default { 4 | mask: ({value}) => { 5 | const digitsCount = value.replaceAll(/\D/g, '').length; 6 | 7 | return ['$', ...new Array(digitsCount || 1).fill(/\d/)]; 8 | }, 9 | } satisfies MaskitoOptions; 10 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/date/is-date-string-complete.ts: -------------------------------------------------------------------------------- 1 | export function isDateStringComplete( 2 | dateString: string, 3 | dateModeTemplate: string, 4 | ): boolean { 5 | if (dateString.length < dateModeTemplate.length) { 6 | return false; 7 | } 8 | 9 | return dateString.split(/\D/).every((segment) => !/^0+$/.exec(segment)); 10 | } 11 | -------------------------------------------------------------------------------- /projects/phone/src/lib/masks/phone/index.ts: -------------------------------------------------------------------------------- 1 | export {TEMPLATE_FILLER} from './constants'; 2 | export {maskitoPhoneOptionsGenerator} from './phone-mask'; 3 | export { 4 | cutInitCountryCodePreprocessor, 5 | phoneLengthPostprocessorGenerator, 6 | validatePhonePreprocessorGenerator, 7 | } from './processors'; 8 | export {maskitoGetCountryFromNumber} from './utils'; 9 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/real-world-form/index.less: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | padding-block-start: 2rem; 6 | } 7 | 8 | form { 9 | inline-size: 80%; 10 | max-inline-size: 40rem; 11 | } 12 | 13 | .password-icon { 14 | pointer-events: all; 15 | cursor: pointer; 16 | } 17 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-time/examples/3-min-max/mask.ts: -------------------------------------------------------------------------------- 1 | import {maskitoDateTimeOptionsGenerator} from '@maskito/kit'; 2 | 3 | export default maskitoDateTimeOptionsGenerator({ 4 | dateMode: 'dd/mm/yyyy', 5 | timeMode: 'HH:MM', 6 | dateSeparator: '-', 7 | min: new Date(2010, 1, 15, 12, 30, 0), 8 | max: new Date(2020, 8, 15, 18, 30, 0), 9 | }); 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/plugins/examples/1-initial-calibration/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | import {maskitoInitialCalibrationPlugin} from '@maskito/core'; 3 | 4 | const maskitoOptions: MaskitoOptions = { 5 | mask: /^\d{0,3}$/, 6 | plugins: [maskitoInitialCalibrationPlugin()], 7 | }; 8 | 9 | export default maskitoOptions; 10 | -------------------------------------------------------------------------------- /projects/kit/src/lib/constants/default-pseudo-minuses.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CHAR_EM_DASH, 3 | CHAR_EN_DASH, 4 | CHAR_HYPHEN, 5 | CHAR_JP_HYPHEN, 6 | CHAR_MINUS, 7 | } from './unicode-characters'; 8 | 9 | export const DEFAULT_PSEUDO_MINUSES = [ 10 | CHAR_HYPHEN, 11 | CHAR_EN_DASH, 12 | CHAR_EM_DASH, 13 | CHAR_JP_HYPHEN, 14 | CHAR_MINUS, 15 | ]; 16 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/tests/to-half-width-colon.spec.ts: -------------------------------------------------------------------------------- 1 | import {describe, expect, it} from '@jest/globals'; 2 | 3 | import {toHalfWidthColon} from '../to-half-width-colon'; 4 | 5 | describe('`toHalfWidthColon` utility converts full width colon to half width colon', () => { 6 | it(': => :', () => { 7 | expect(toHalfWidthColon(':')).toBe(':'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/vue-default-tab.ts: -------------------------------------------------------------------------------- 1 | export const VUE_DEFAULT_TAB = `import {createApp} from 'vue'; 2 | import {maskito} from '@maskito/vue'; 3 | 4 | import options from './mask'; 5 | 6 | const app = createApp({ 7 | template: '', 8 | directives: {maskito}, 9 | data: () => ({ options }), 10 | });`; 11 | -------------------------------------------------------------------------------- /projects/kit/src/lib/masks/date-time/date-time-params.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoDateMode, MaskitoTimeMode} from '../../types'; 2 | 3 | export interface MaskitoDateTimeParams { 4 | dateMode: MaskitoDateMode; 5 | timeMode: MaskitoTimeMode; 6 | dateSeparator?: string; 7 | max?: Date; 8 | min?: Date; 9 | dateTimeSeparator?: string; 10 | timeStep?: number; 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo-integrations/src/tests/kit/number/utils.ts: -------------------------------------------------------------------------------- 1 | import {DemoPath} from '@demo/constants'; 2 | 3 | export function openNumberPage(queryParams = ''): void { 4 | cy.visit(`/${DemoPath.Number}/API?${queryParams}`); 5 | cy.get('#demo-content input') 6 | .should('be.visible') 7 | .first() 8 | .focus() 9 | .clear() 10 | .as('input'); 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo-integrations/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "typeRoots": ["../../node_modules/@types", "../../node_modules/cypress/types"], 5 | "types": ["cypress", "node"] 6 | }, 7 | "include": ["cypress.config.ts", "cypress-react.config.ts", "**/*.ts", "**/*.tsx", "**/*.d.ts"], 8 | "exclude": [] 9 | } 10 | -------------------------------------------------------------------------------- /projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/react-default-tab.ts: -------------------------------------------------------------------------------- 1 | export const REACT_DEFAULT_TAB = `import * as React from 'react'; 2 | import {useMaskito} from '@maskito/react'; 3 | 4 | import options from './mask'; 5 | 6 | export default function App() { 7 | const maskedInputRef = useMaskito({options}); 8 | 9 | return ; 10 | }`; 11 | -------------------------------------------------------------------------------- /projects/demo/src/pages/recipes/textarea/examples/maskito-with-textarea.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import {Maskito} from '@maskito/core'; 3 | 4 | const element: HTMLTextAreaElement = document.querySelector('textarea')!; 5 | 6 | const maskedTextarea = new Maskito(element, { 7 | mask: /^[a-z\s]+$/i, 8 | }); 9 | 10 | // Call it when the element is detached from DOM 11 | maskedTextarea.destroy(); 12 | ``` 13 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["**/*.spec.ts", "**/*.spec.tsx", "**/jest.config.ts"], 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "types": [], 8 | "inlineSources": true 9 | }, 10 | "angularCompilerOptions": { 11 | "compilationMode": "partial" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "module": "esnext", 6 | "types": ["jest", "node"], 7 | "verbatimModuleSyntax": false 8 | }, 9 | "exclude": ["**/schematics/**/*", "projects/demo-integrations"], 10 | "include": ["**/*.spec.ts", "**/*.d.ts", "**/*.spec.tsx"] 11 | } 12 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/plugins/plugins.style.less: -------------------------------------------------------------------------------- 1 | @import '@taiga-ui/core/styles/taiga-ui-local.less'; 2 | 3 | .cards { 4 | display: flex; 5 | flex-wrap: wrap; 6 | gap: 1rem; 7 | 8 | & [tuiCardLarge] { 9 | flex: 1; 10 | min-inline-size: 20rem; 11 | 12 | @media @tui-desktop-min { 13 | max-inline-size: 45%; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/to-half-width-number.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Replace fullwidth numbers with half width number 3 | * @param fullWidthNumber full width number 4 | * @returns processed half width number 5 | */ 6 | export function toHalfWidthNumber(fullWidthNumber: string): string { 7 | return fullWidthNumber.replaceAll(/[0-9]/g, (s) => 8 | String.fromCharCode(s.charCodeAt(0) - 0xfee0), 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /projects/vue/jest.config.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | displayName: 'vue', 3 | preset: '../../jest.preset.js', 4 | transform: { 5 | '^.+\\.[tj]sx?$': 'ts-jest', 6 | }, 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 8 | coverageDirectory: '../../coverage/projects/vue', 9 | testEnvironmentOptions: { 10 | customExportConditions: ['node', 'node-addons'], 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /projects/kit/src/lib/utils/date/date-segment-value-length.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoDateSegments} from '../../types'; 2 | 3 | export const getDateSegmentValueLength: ( 4 | dateString: string, 5 | ) => MaskitoDateSegments = (dateString: string) => ({ 6 | day: dateString.match(/d/g)?.length ?? 0, 7 | month: dateString.match(/m/g)?.length ?? 0, 8 | year: dateString.match(/y/g)?.length ?? 0, 9 | }); 10 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/plugins/examples/4-reject/index.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import './animation.css'; 3 | 4 | import {Maskito} from '@maskito/core'; 5 | 6 | import maskitoOptions from './mask'; 7 | 8 | const element = document.querySelector('input')!; 9 | const maskedInput = new Maskito(element, maskitoOptions); 10 | 11 | console.info('Call this function when the element is detached from DOM', maskedInput.destroy); 12 | ``` 13 | -------------------------------------------------------------------------------- /projects/demo/src/app/utils/add-default-tabs-processor/default-tabs/js-default-tab.ts: -------------------------------------------------------------------------------- 1 | export const JS_DEFAULT_TAB = `import {Maskito, MaskitoOptions} from '@maskito/core'; 2 | import maskitoOptions from './mask'; 3 | 4 | const element = document.querySelector('input,textarea')!; 5 | const maskedInput = new Maskito(element, maskitoOptions); 6 | 7 | // Call this function when the element is detached from DOM 8 | maskedInput.destroy();`; 9 | -------------------------------------------------------------------------------- /projects/demo/src/pages/documentation/element-state/examples/element-state-demo.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | interface ElementState { 3 | // the value of a masked or 20 | 21 | `, 22 | changeDetection: ChangeDetectionStrategy.OnPush, 23 | }) 24 | export class TextareaDocExample1 { 25 | protected readonly mask = mask; 26 | protected value = ''; 27 | } 28 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/date-time/examples/5-am-pm/mask.ts: -------------------------------------------------------------------------------- 1 | import type {MaskitoOptions} from '@maskito/core'; 2 | import type {MaskitoDateMode, MaskitoTimeMode} from '@maskito/kit'; 3 | import { 4 | maskitoDateTimeOptionsGenerator, 5 | maskitoSelectionChangeHandler, 6 | } from '@maskito/kit'; 7 | 8 | const dateTimeSeparator = ', '; 9 | const dateMode: MaskitoDateMode = 'dd/mm/yyyy'; 10 | const timeMode: MaskitoTimeMode = 'HH:MM AA'; 11 | 12 | const dateTimeOptions = maskitoDateTimeOptionsGenerator({ 13 | dateMode, 14 | timeMode, 15 | dateTimeSeparator, 16 | dateSeparator: '/', 17 | }); 18 | 19 | export default { 20 | ...dateTimeOptions, 21 | plugins: [ 22 | ...dateTimeOptions.plugins, 23 | maskitoSelectionChangeHandler((element) => { 24 | element.inputMode = 25 | element.selectionStart! >= `${dateMode + dateTimeSeparator}HH:MM`.length 26 | ? 'text' 27 | : 'numeric'; 28 | }), 29 | ], 30 | } satisfies MaskitoOptions; 31 | -------------------------------------------------------------------------------- /projects/demo/src/pages/kit/plugins/examples/2-caret-guard/component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {FormsModule} from '@angular/forms'; 3 | import {MaskitoDirective} from '@maskito/angular'; 4 | import {TuiTextfield} from '@taiga-ui/core'; 5 | 6 | import mask from './mask'; 7 | 8 | @Component({ 9 | selector: 'kit-plugins-doc-example-2', 10 | imports: [FormsModule, MaskitoDirective, TuiTextfield], 11 | template: ` 12 | 16 | 22 | 23 | `, 24 | changeDetection: ChangeDetectionStrategy.OnPush, 25 | }) 26 | export class KitPluginsDocExample2 { 27 | protected value = '$100 per day'; 28 | protected maskitoOptions = mask; 29 | } 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@taiga-ui/tsconfig", 3 | "exclude": ["projects/demo-integrations", "projects/**/*.spec.ts", "projects/**/*.spec.tsx"], 4 | "angularCompilerOptions": { 5 | "strictTemplates": true 6 | }, 7 | "compilerOptions": { 8 | "baseUrl": "./", 9 | "outDir": "./dist/out-tsc", 10 | "typeRoots": ["node_modules/@types", "node_modules/@taiga-ui/tsconfig/@types"], 11 | "sourceMap": true, 12 | "jsx": "react-jsx", 13 | "checkJs": false, 14 | "paths": { 15 | "@demo/constants": ["projects/demo/src/app/constants/index.ts"], 16 | "@maskito/angular": ["projects/angular/src/index.ts"], 17 | "@maskito/core": ["projects/core/src/index.ts"], 18 | "@maskito/kit": ["projects/kit/src/index.ts"], 19 | "@maskito/phone": ["projects/phone/src/index.ts"], 20 | "@maskito/react": ["projects/react/src/index.ts"], 21 | "@maskito/vue": ["projects/vue/src/index.ts"] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>taiga-family/renovate-config"], 4 | "postUpgradeTasks": { 5 | "commands": [ 6 | "echo 'TODO: workaround for https://github.com/npm/cli/issues/7019'", 7 | "rm -rf package-lock.json node_modules **/node_modules", 8 | "npm i --workspaces --include-workspace-root", 9 | "echo '------------------'", 10 | "echo 'TODO: workaround for https://github.com/npm/cli/issues/6787#issuecomment-1751005219'", 11 | "npm i --workspaces --include-workspace-root" 12 | ], 13 | "executionMode": "branch", 14 | "fileFilters": ["package-lock.json"] 15 | }, 16 | "packageRules": [ 17 | { 18 | "matchPackageNames": ["/^@nx.*/", "/^nx$/", "cypress"], 19 | "enabled": false 20 | }, 21 | { 22 | "matchPackageNames": ["jest-preset-angular"], 23 | "enabled": false 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /projects/demo/src/pages/frameworks/angular/examples/1-nested/component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component} from '@angular/core'; 2 | import {FormsModule} from '@angular/forms'; 3 | import {MaskitoDirective} from '@maskito/angular'; 4 | import type {MaskitoElementPredicate, MaskitoOptions} from '@maskito/core'; 5 | import {TuiInputModule} from '@taiga-ui/legacy'; 6 | 7 | @Component({ 8 | selector: 'nested-doc-example-1', 9 | imports: [FormsModule, MaskitoDirective, TuiInputModule], 10 | templateUrl: './template.html', 11 | changeDetection: ChangeDetectionStrategy.OnPush, 12 | }) 13 | export class NestedDocExample1 { 14 | protected value = ''; 15 | 16 | public readonly nameMask: MaskitoOptions = { 17 | mask: /^[a-zA-Z\s]+$/, 18 | postprocessors: [ 19 | ({value, selection}) => ({value: value.toUpperCase(), selection}), 20 | ], 21 | }; 22 | 23 | public readonly predicate: MaskitoElementPredicate = (element) => 24 | element.querySelector('tui-input input')!; 25 | } 26 | -------------------------------------------------------------------------------- /projects/core/src/lib/classes/mask-model/utils/guess-valid-value-by-reg-exp.ts: -------------------------------------------------------------------------------- 1 | import type {ElementState} from '../../../types'; 2 | 3 | export function guessValidValueByRegExp( 4 | {value, selection}: ElementState, 5 | maskRegExp: RegExp, 6 | ): ElementState { 7 | const [from, to] = selection; 8 | let newFrom = from; 9 | let newTo = to; 10 | 11 | const validatedValue = Array.from(value).reduce((validatedValuePart, char, i) => { 12 | const newPossibleValue = validatedValuePart + char; 13 | 14 | if (from === i) { 15 | newFrom = validatedValuePart.length; 16 | } 17 | 18 | if (to === i) { 19 | newTo = validatedValuePart.length; 20 | } 21 | 22 | return newPossibleValue.match(maskRegExp) ? newPossibleValue : validatedValuePart; 23 | }, ''); 24 | 25 | return { 26 | value: validatedValue, 27 | selection: [ 28 | Math.min(newFrom, validatedValue.length), 29 | Math.min(newTo, validatedValue.length), 30 | ], 31 | }; 32 | } 33 | --------------------------------------------------------------------------------