{"id":18031741,"url":"https://github.com/dagronf/dsfpasscodeview","last_synced_at":"2026-03-06T16:30:57.294Z","repository":{"id":63907299,"uuid":"403420904","full_name":"dagronf/DSFPasscodeView","owner":"dagronf","description":"A passcode entry field for macOS similar to Apple's two-factor authentication field.","archived":false,"fork":false,"pushed_at":"2022-08-24T04:36:53.000Z","size":143,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-23T04:31:38.932Z","etag":null,"topics":["appkit","macos","passcode"],"latest_commit_sha":null,"homepage":"","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/dagronf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-05T21:59:29.000Z","updated_at":"2023-12-05T05:55:54.000Z","dependencies_parsed_at":"2022-11-29T13:21:14.833Z","dependency_job_id":null,"html_url":"https://github.com/dagronf/DSFPasscodeView","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFPasscodeView","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFPasscodeView/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFPasscodeView/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dagronf%2FDSFPasscodeView/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dagronf","download_url":"https://codeload.github.com/dagronf/DSFPasscodeView/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245791332,"owners_count":20672665,"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":["appkit","macos","passcode"],"created_at":"2024-10-30T10:10:37.781Z","updated_at":"2025-10-21T18:15:24.089Z","avatar_url":"https://github.com/dagronf.png","language":"Swift","readme":"# DSFPasscodeView\n\nA passcode entry field for macOS similar to Apple's two-factor authentication field.\n\n\u003cp align=\"center\"\u003e\n   \u003cimg src=\"https://github.com/dagronf/dagronf.github.io/blob/master/art/projects/DSFPasscodeView/dark-mode.gif?raw=true\" /\u003e\n   \u003cbr\u003e\u003cbr\u003e\n   \u003cimg src=\"https://github.com/dagronf/dagronf.github.io/blob/master/art/projects/DSFPasscodeView/light-mode.gif?raw=true\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/tag/dagronf/DSFPasscodeView\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/macOS-10.11+-blue\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Xcode-12+-yellow\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Swift-5.1-orange.svg\" /\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-lightgrey\" /\u003e\n    \u003ca href=\"https://swift.org/package-manager\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\n## About\n\nThe control is made up of multiple groups of passcode 'cells'. Each cell holds a single 'character', and you define groups of cells using a group separator. The pattern you define provides the layout -- containing `#` for a passcode cell and `-` for a group separator.\n\nFor example, to create a passcode of six characters split evenly into two groups of three cells, you set the passcode pattern to `\"###-###\"`\n\n```\n.---. .---. .---.   .---. .---. .---.\n|   | |   | |   |   |   | |   | |   |\n|   | |   | |   |   |   | |   | |   |\n`---' `---' `---'   `---' `---' `---'\n```\n\nThis control can be used in both autolayout and manual layout apps (internally the control does not use auto-layout)\n\nNote this control uses [@VIViewInvalidating](https://github.com/dagronf/VIViewInvalidating) providing automatic NSView invalidation when properties value change. (automatically added as a dependency)\n\n## Features\n\n* Configurable allowable character support\n* Character Viewer support (eg. hit Command-Ctrl-Space when a passcode cell is active)\n* Different fonts\n* Different spacing (intra-cell, edge insets, group and cell spacing)\n* Light and dark modes\n* High contrast support\n* Accessibility and VoiceOver support\n\n## Installation\n\nUsing Swift Package Manager, add `https://github.com/dagronf/DSFPasscodeView` to your project.\n\n## Settings\n\n### pattern (`String`)\n\nThe cell pattern to use when displaying the passcode. A `#` represents a cell and a `-` represents a group space. \n\nThe only valid characters are # (a cell) and - (group spacing). Attempting to set a pattern with any other character will result in a `fatalError()`\n\nExamples :-\n\n```\n\"###-###\"\n.---. .---. .---.   .---. .---. .---.\n|   | |   | |   |   |   | |   | |   |\n|   | |   | |   |   |   | |   | |   |\n`---' `---' `---'   `---' `---' `---'\n\n\"####-##-###\"\n.---. .---. .---. .---.   .---. .---.   .---. .---. .---.\n|   | |   | |   | |   |   |   | |   |   |   | |   | |   |\n|   | |   | |   | |   |   |   | |   |   |   | |   | |   |\n`---' `---' `---' `---'   `---' `---'   `---' `---' `---'\n\n\"##-##-#\"\n.---. .---.   .---. .---.   .---.\n|   | |   |   |   | |   |   |   |\n|   | |   |   |   | |   |   |   |\n`---' `---'   `---' `---'   `---'\n```\n\n### cellSpacing (`CGFloat`)\n\nThe spacing to use between adjacent cells\n\n### groupSpacing (`CGFloat`)\n\nThe spacing to use between cell groups\n\n### font (`NSFont`)\n\nThe font to use when displaying the character in a cell\n\n### padding (`CGSize`)\n\nThe padding to use between the character and the edge of its cell\n\n### edgeInsets (`NSEdgeInsets`)\n\nThe padding to use between the cells and the bounds of the control\n\n### isEnabled (`Bool`)\n\nEnable or disable the control (observable)\n\n## Validations\n\nThere are two methods of validation\n\n### allowableCharacters (String)\n\nThis settings on the control allows you to specify a string containing the characters that are allowed within the control. By default, this is `0123456789`.\n\n### characterValidatorBlock \n\nFor more complex validations, you can specify a callback block which can be used to validate each character\n\nIt takes a string element and returns either a value transformed string element (for example, uppercased), or nil if the presented character isn't valid for the control.\n \n```swift\n// A validator block which allows numbers and case-insensitive A-F characters\nself.passcode.characterValidatorBlock = { element in\n   let validChars = \"0123456789ABCDEF\"\n   let s = element.uppercased()         // Always check against uppercase\n   if validChars.contains(s) {          // If the validChars contains the uppercased char...\n       return s.first                   //  ... return the uppercased version\n   }\n   return nil                           // Unsupported char, ignore by returning nil\n}\n```\n\n## Values\n\nYou can bind to these member variables to receive updates as the control content changes.\n\n### isValidPasscode (`Bool`)\n\nIs the passcode entered a valid passcode (ie. all the values are specified)\n\n### isEmpty (`Bool`)\n\nAre there no values specified yet\n\n### passcodeValue (`String`)\n\nIf the passcode is valid, the passcode value as a string, otherwise nil.\n\n## Delegate (DSFPasscodeViewHandling)\n\nYou can attach a delegate to receive messages back from the view if binding is not your thing.\n\n```swift\nfunc passcodeViewDidChange(\n   _ view: DSFPasscodeView)\n```\n\nCalled when the content of the passcode view changes.\n\n```swift\nfunc passcodeView(\n   _ view: DSFPasscodeView,                        // The passcode view\n   updatedPasscodeValue passcode: String)          // The valid passcode as a string of characters\n```\n\nCalled ONLY when the passcode is valid and complete.\n\n```swift\nfunc passcodeView(\n   _ view: DSFPasscodeView,                        // The passcode view \n   didTryInvalidCharacter invalidChar: String?,    // The invalid character, or nil for a special key\n   atIndex index: Int)                             // The passcode cell index where the attempt failed\n```\n\nCalled if the user presses an unsupported character or key in a passcode cell.\n\n## Known issues\n\n* Xcode has been broken for many years regarding support for `@IBDesignable`/`@IBInspectable`. Whilst this control provides support, Xcode's support for @IBDesignable for a control provided from a package is completely broken.  \n\nIf you copy the DSFPasscodeView source files directly into your project the Designables work as expected (FB8358478).\n\n## License\n\nMIT. Use it and abuse it for anything you want, just attribute my work. Let me know if you do use it somewhere, I'd love to hear about it!\n\n```\nMIT License\n\nCopyright (c) 2021 Darren Ford\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdagronf%2Fdsfpasscodeview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdagronf%2Fdsfpasscodeview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdagronf%2Fdsfpasscodeview/lists"}