{"id":20492528,"url":"https://github.com/redmadrobot/input-mask-ios","last_synced_at":"2025-05-16T06:04:34.288Z","repository":{"id":44708998,"uuid":"71347562","full_name":"RedMadRobot/input-mask-ios","owner":"RedMadRobot","description":"User input masking library repo.","archived":false,"fork":false,"pushed_at":"2024-08-19T12:34:20.000Z","size":9269,"stargazers_count":585,"open_issues_count":9,"forks_count":93,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-05-16T06:04:07.081Z","etag":null,"topics":["formatter","ios","pattern","swift","template","text","validator"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RedMadRobot.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-19T10:50:50.000Z","updated_at":"2025-02-13T10:47:21.000Z","dependencies_parsed_at":"2024-11-15T17:33:30.561Z","dependency_job_id":"abc32a08-bc36-4663-9d12-9818f9a95dd5","html_url":"https://github.com/RedMadRobot/input-mask-ios","commit_stats":{"total_commits":205,"total_committers":13,"mean_commits":15.76923076923077,"dds":0.2829268292682927,"last_synced_commit":"b01794f2c00d42f8cd2928087c3fd61fe65d12d0"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Finput-mask-ios","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Finput-mask-ios/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Finput-mask-ios/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RedMadRobot%2Finput-mask-ios/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RedMadRobot","download_url":"https://codeload.github.com/RedMadRobot/input-mask-ios/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254478186,"owners_count":22077675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formatter","ios","pattern","swift","template","text","validator"],"created_at":"2024-11-15T17:29:28.522Z","updated_at":"2025-05-16T06:04:34.248Z","avatar_url":"https://github.com/RedMadRobot.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"Documentation/Assets/logo.png\" alt=\"Input Mask\" /\u003e\r\n\r\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FRedMadRobot%2Finput-mask-ios%2Fbadge%3Ftype%3Dswift-versions\u0026style=for-the-badge)](https://swiftpackageindex.com/RedMadRobot/input-mask-ios) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FRedMadRobot%2Finput-mask-ios%2Fbadge%3Ftype%3Dplatforms\u0026style=for-the-badge)](https://swiftpackageindex.com/RedMadRobot/input-mask-ios) [![Pod Version Badge](https://img.shields.io/badge/POD-v7.3.2-blue?logo=cocoapods\u0026style=for-the-badge)](https://cocoapods.org/pods/InputMask) [![Awesome](https://img.shields.io/badge/-mentioned_in_awesome_iOS-CCA6C4.svg?colorA=CCA6C4\u0026colorB=261120\u0026logoWidth=20\u0026logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMTAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI%2BICAgIDxwYXRoIGZpbGw9IiMyNjExMjAiIGQ9Ik0xOS4xNCA0LjVMMTQuMjMgMGwtLjY5Ljc1IDQuMDkgMy43NUgxLjUxTDUuNi43NSA0LjkxIDAgMCA0LjV2Mi45N0MwIDguODEgMS4yOSA5LjkgMi44OCA5LjloMy4wM2MxLjU5IDAgMi44OC0xLjA5IDIuODgtMi40M1Y1LjUyaDEuNTd2MS45NWMwIDEuMzQgMS4yOSAyLjQzIDIuODggMi40M2gzLjAzYzEuNTkgMCAyLjg4LTEuMDkgMi44OC0yLjQzbC0uMDEtMi45N3oiLz48L3N2Zz4%3D\u0026style=for-the-badge)](https://github.com/vsouza/awesome-ios) [![Actions](https://img.shields.io/github/actions/workflow/status/RedMadRobot/input-mask-ios/swift.yml?style=for-the-badge)](https://github.com/RedMadRobot/input-mask-ios/actions/workflows/swift.yml) [![Android](https://img.shields.io/badge/-android_version-red?color=teal\u0026logo=android\u0026style=for-the-badge)](https://github.com/RedMadRobot/input-mask-android) [![Telegram](https://img.shields.io/badge/-telegram_author-red?color=blue\u0026logo=telegram\u0026style=for-the-badge)](https://t.me/jeorge_taflanidi) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=for-the-badge)](#license)\r\n\r\nInput masks restrict data input and allow you to guide users to enter correct values.  \r\nCheck out our [wiki](https://github.com/RedMadRobot/input-mask-ios/wiki) for quick start and further reading.  \r\n\r\n## ⚙️ Features\r\n\r\n- Apply formatting to your text fields, see [examples](#examples)\r\n- Filter out nonessential symbols (e.g. extract `0123456` from `+1 (999) 012-34-56`)\r\n- For international phone numbers \r\n    - guess the country from the entered digits\r\n    - apply corresponding value restrictions (e.g. a 🇺🇸US phone will have a format like `+1 201 456-7890`)\r\n- Apply number/currency formatting \r\n- SwiftUI support\r\n- macOS support\r\n\r\n\u003ca name=\"examples\" /\u003e\r\n\r\n## 💳 Examples\r\n\r\n- Phone numbers: `+1 ([000]) [000] [00] [00]`\r\n- Dates: `[00]{.}[00]{.}[9900]`\r\n- Serial numbers: `[AA]-[00000099]`\r\n- IPv4: `[099]{.}[099]{.}[099]{.}[099]`\r\n- Visa/MasterCard numbers: `[0000] [0000] [0000] [0000]`\r\n- UK IBAN: `GB[00] [____] [0000] [0000] [0000] [00]`\r\n\r\n\u003ca name=\"installation\" /\u003e\r\n\r\n## 🛠️ Installation\r\n\r\n### Swift Package Manager\r\n\r\n```swift\r\ndependencies: [\r\n    .Package(url: \"https://github.com/RedMadRobot/input-mask-ios\", majorVersion: 7)\r\n]\r\n```\r\n\r\n### CocoaPods\r\n\r\n```ruby\r\npod 'InputMask'\r\n```\r\n\r\n### Manual\r\n\r\n0. `git clone` this repository;\r\n1. Add `InputMask.xcodeproj` into your project/workspace;\r\n2. Go to your target's settings, add `InputMask.framework` under the `Embedded Binaries` section\r\n3. For `ObjC` projects:\r\n\t* (~Xcode 8.x) make sure `Build Options` has `Embedded Content Contains Swift Code` enabled;\r\n\t* import bridging header.\r\n\r\n## 📢 Communication, Questions \u0026 Issues\r\n\r\nPlease take a closer look at our [Known issues](#knownissues) section before you incorporate our library into your project.\r\n\r\nFor your bugreports and feature requests please file new issues [via GitHub](https://github.com/RedMadRobot/input-mask-ios/issues/new/choose).\r\n\r\nShould you have any questions, please search for closed [issues](https://github.com/RedMadRobot/input-mask-ios/issues?q=is%3Aclosed) or ask questions at **[StackOverflow](https://stackoverflow.com/questions/tagged/input-mask)** with the `input-mask` tag.\r\n\r\n\u003ca name=\"knownissues\" /\u003e\r\n\r\n## ❗Known issues\r\n\r\n### `UITextFieldTextDidChange` notification and target-action `editingChanged` event\r\n\r\n`UITextField` with assigned `MaskedTextFieldDelegate` object won't issue `UITextFieldTextDidChange` notifications and `editingChanged` control events. This happens due to the `textField(_:shouldChangeCharactersIn:replacementString:)` method implementation, which always returns `false`.\r\n\r\nConsider using following workaround in case if you do really need to catch editing events:\r\n\r\n```swift\r\nclass NotifyingMaskedTextFieldDelegate: MaskedTextFieldDelegate {\r\n    weak var editingListener: NotifyingMaskedTextFieldDelegateListener?\r\n    \r\n    override func textField(\r\n        _ textField: UITextField,\r\n        shouldChangeCharactersIn range: NSRange,\r\n        replacementString string: String\r\n    ) -\u003e Bool {\r\n        defer {\r\n            self.editingListener?.onEditingChanged(inTextField: textField)\r\n        }\r\n        return super.textField(textField, shouldChangeCharactersIn: range, replacementString: string)\r\n    }\r\n}\r\n\r\n\r\nprotocol NotifyingMaskedTextFieldDelegateListener: class {\r\n    func onEditingChanged(inTextField: UITextField)\r\n}\r\n```\r\n\r\nPlease, avoid at all costs sending SDK events and notifications manually.\r\n\r\n### Carthage vs. IBDesignables, IBInspectables, views and their outlets\r\n\r\nInterface Builder struggles to support modules imported in a form of a dynamic framework. For instance, custom views annotated as IBDesignable, containing IBInspectable and IBOutlet fields aren't recognized properly from the drag'n'dropped \\*.framework.\r\n\r\nIn case you are using our library as a Carthage-built dynamic framework, be aware you won't be able to easily wire your `MaskedTextFieldDelegate` objects and their listeners from storyboards in your project. There is a couple of workarounds described in [the corresponding discussion](https://github.com/Carthage/Carthage/issues/335), though.\r\n\r\nAlso, consider filing a radar to Apple, like [this one](https://openradar.appspot.com/23114017).\r\n\r\n### Cut action doesn't put text into the pasteboard\r\n\r\nWhen you cut text, characters get deleted yet you won't be able to paste them somewhere as they aren't actually in your pasteboard.\r\n\r\niOS hardwires `UIMenuController`'s cut action to the `UITextFieldDelegate`'s `textField(_:shouldChangeCharactersIn:replacementString:)` return value. This means \"Cut\" behaviour actually depends on the ability to edit the text.\r\n\r\nBad news are, our library returns `false` in `textField(_:shouldChangeCharactersIn:replacementString:)`, and heavily depends on this `false`. It would require us to rewrite a lot of logic in order to change this design, and there's no guarantee we'll be able to do so.\r\n\r\nEssentially, there's no distinct way to differentiate \"Cut selection\" and \"Delete selection\" actions on the `UITextFieldDelegate` side. However, you may consider using a workaround, which will require you to subclass `UITextField` overriding its `cut(sender:)` method like this:\r\n\r\n```swift\r\nclass UITextFieldMonkeyPatch: UITextField {\r\n    override func cut(_ sender: Any?) {\r\n        copy(sender)\r\n        super.cut(sender)\r\n    }\r\n}\r\n```\r\n\r\nFrom our library perspective, this looks like a highly invasive solution. Thus, in the long term, we are going to investigate a \"costly\" method to bring the behaviour matching the iOS SDK logic. Yet, here \"long term\" might mean months.\r\n\r\n### Incorrect cursor position after pasting\r\n\r\nShortly after new text is being pasted from the clipboard, every ```UITextInput``` receives a new value for its `selectedTextRange` property from the system. This new range is not consistent with the formatted text and calculated caret position most of the time, yet it's being assigned just after ```set caretPosition``` call.\r\n     \r\nTo ensure correct caret position is set, it might be assigned asynchronously (presumably after a vanishingly small delay), if caret movement is set to be non-atomic; see `MaskedTextFieldDelegate.atomicCursorMovement` property.\r\n\r\n### `MaskedTextInputListener`\r\n\r\nIn case you are wondering why do we have two separate `UITextFieldDelegate` and `UITextViewDelegate` implementations, the answer is simple: prior to **iOS 11** `UITextField` and `UITextView` had different behaviour in some key situations, which made it difficult to implement common logic. \r\n\r\nBoth had the same [bug](http://jon-nolen.blogspot.com/2013/10/uitextview-returns-nil-for-uitextinput.html) with the `UITextInput.beginningOfDocument` property, which rendered impossible to use the generic `UITextInput` protocol `UITextField` and `UITextView` have in common.\r\n\r\nSince **iOS 11** most of the things received their fixes (except for the `UITextView` [edge case](https://github.com/RedMadRobot/input-mask-ios/blob/master/Source/InputMask/InputMask/Classes/View/MaskedTextInputListener.swift#L140)). In case your project is not going to support anything below 11, consider using the modern `MaskedTextInputListener`.\r\n\r\n## 🙏 Special thanks\r\n\r\nThese folks rock:\r\n\r\n* Mikhail [while366](https://github.com/while366) Zhadko\r\n* Sergey [SergeyCHiP](https://github.com/SergeyCHiP) Germanovich\r\n* Luiz [LuizZak](https://github.com/LuizZak) Fernando\r\n* Ivan [vani](https://github.com/vani2) Vavilov\r\n* Diego [diegotl](https://github.com/diegotl) Trevisan\r\n* Martin [martintreurnicht](https://github.com/martintreurnicht) Treurnicht\r\n* Alexander [CFIFok](https://github.com/CFIFok) Kurilovich\r\n\r\n\u003ca name=\"license\" /\u003e\r\n\r\n## ♻️ License\r\n\r\nThe library is distributed under the MIT [LICENSE](https://github.com/RedMadRobot/input-mask-ios/blob/master/LICENSE).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredmadrobot%2Finput-mask-ios","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredmadrobot%2Finput-mask-ios","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredmadrobot%2Finput-mask-ios/lists"}