diff --git a/.gitignore b/.gitignore
index a8ee677..527afa6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
DSFFloatLabelledTextControls.xcodeproj/xcuserdata
xcschememanagement.plist
.swiftpm
+Demos/DSFFloatLabelledTextControls.xcodeproj/xcuserdata
diff --git a/DSFFloatLabelledTextControl.podspec b/DSFFloatLabelledTextControl.podspec
index 8db189e..15a428c 100644
--- a/DSFFloatLabelledTextControl.podspec
+++ b/DSFFloatLabelledTextControl.podspec
@@ -1,9 +1,9 @@
Pod::Spec.new do |s|
s.name = "DSFFloatLabelledTextControl"
s.version = "1.8.0"
- s.summary = "A macOS Cocoa single-line NSTextField that implements the Float Label Pattern"
+ s.summary = "A macOS Cocoa single-line NSTextField/NSSecureTextField that implements the Float Label Pattern"
s.description = <<-DESC
- A macOS Cocoa single-line NSTextField that implements the Float Label Pattern. Supports secure edit fields.
+ A macOS Cocoa single-line NSTextField/NSSecureTextField that implements the Float Label Pattern.
DESC
s.homepage = "https://github.com/dagronf/DSFFloatLabelledTextControl"
s.license = { :type => "MIT", :file => "LICENSE" }
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
s.social_media_url = ""
s.osx.deployment_target = "10.11"
s.source = { :git => ".git", :tag => s.version.to_s }
- s.source_files = "DSFFloatLabelledTextControl/DSFFloatLabelledTextField.swift"
+ s.source_files = "Sources/DSFFloatLabelledTextControl/*.swift"
s.frameworks = "Cocoa"
- s.swift_version = "5.0"
+ s.swift_version = "5.4"
end
diff --git a/DSFFloatLabelledTextControls.xcodeproj/xcuserdata/dford.xcuserdatad/xcschemes/xcschememanagement.plist b/DSFFloatLabelledTextControls.xcodeproj/xcuserdata/dford.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index d0a84d9..0000000
--- a/DSFFloatLabelledTextControls.xcodeproj/xcuserdata/dford.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
- SchemeUserState
-
- All.xcscheme_^#shared#^_
-
- orderHint
- 4
-
- DSFFloatLabelledTextControl.xcscheme_^#shared#^_
-
- orderHint
- 1
-
- DSFFloatLabelledTextControls Demo objc.xcscheme_^#shared#^_
-
- orderHint
- 3
-
- DSFFloatLabelledTextControls RTL.xcscheme_^#shared#^_
-
- orderHint
- 1
-
- DSFFloatLabelledTextControls.xcscheme_^#shared#^_
-
- orderHint
- 0
-
- DSFFloatLabelledTextField.xcscheme_^#shared#^_
-
- orderHint
- 2
-
-
- SuppressBuildableAutocreation
-
- 2351F84A2207D15C00EFA4F7
-
- primary
-
-
- 23A2B7E8220792FE00B2FC77
-
- primary
-
-
- 23C3AB9923FBCFA30079D9C3
-
- primary
-
-
-
-
-
diff --git a/DSFFloatLabelledTextControls.xcodeproj/project.pbxproj b/Demos/DSFFloatLabelledTextControls.xcodeproj/project.pbxproj
similarity index 69%
rename from DSFFloatLabelledTextControls.xcodeproj/project.pbxproj
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/project.pbxproj
index 6001a19..adff5ef 100644
--- a/DSFFloatLabelledTextControls.xcodeproj/project.pbxproj
+++ b/Demos/DSFFloatLabelledTextControls.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 50;
+ objectVersion = 52;
objects = {
/* Begin PBXAggregateTarget section */
@@ -22,38 +22,18 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
- 2351F84F2207D15C00EFA4F7 /* DSFFloatLabelledTextControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 2351F84D2207D15C00EFA4F7 /* DSFFloatLabelledTextControl.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 2351F8522207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */; };
- 2351F8532207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- 2351F8582207D16100EFA4F7 /* DSFFloatLabelledTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A2B7FA2207931500B2FC77 /* DSFFloatLabelledTextField.swift */; };
- 2351F85B22082AD800EFA4F7 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 2351F85922082AD800EFA4F7 /* LICENSE */; };
- 2351F85C22082AD800EFA4F7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 2351F85A22082AD800EFA4F7 /* README.md */; };
23A2B7ED220792FE00B2FC77 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A2B7EC220792FE00B2FC77 /* AppDelegate.swift */; };
23A2B7EF220792FF00B2FC77 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 23A2B7EE220792FF00B2FC77 /* Assets.xcassets */; };
23A2B7F2220792FF00B2FC77 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 23A2B7F0220792FF00B2FC77 /* MainMenu.xib */; };
+ 23A3061C29C12CB200BEC98A /* DSFFloatLabelledTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 23A3061B29C12CB200BEC98A /* DSFFloatLabelledTextField */; };
+ 23A3061E29C12CB800BEC98A /* DSFFloatLabelledTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 23A3061D29C12CB800BEC98A /* DSFFloatLabelledTextField */; };
23C3AB9E23FBCFA30079D9C3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 23C3AB9D23FBCFA30079D9C3 /* AppDelegate.m */; };
23C3ABA023FBCFA40079D9C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 23C3AB9F23FBCFA40079D9C3 /* Assets.xcassets */; };
23C3ABA323FBCFA40079D9C3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 23C3ABA123FBCFA40079D9C3 /* MainMenu.xib */; };
23C3ABA623FBCFA40079D9C3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 23C3ABA523FBCFA40079D9C3 /* main.m */; };
- 23C3ABAC23FBCFDE0079D9C3 /* DSFFloatLabelledTextField.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */; };
- 23C3ABB023FBD0F80079D9C3 /* DSFFloatLabelledTextField.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 2351F8502207D15C00EFA4F7 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 23A2B7E1220792FE00B2FC77 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2351F84A2207D15C00EFA4F7;
- remoteInfo = DSFFloatLabelledTextControl;
- };
- 23C3ABAD23FBCFE40079D9C3 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 23A2B7E1220792FE00B2FC77 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 2351F84A2207D15C00EFA4F7;
- remoteInfo = DSFFloatLabelledTextField;
- };
23E825672575D17E0023A3C7 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 23A2B7E1220792FE00B2FC77 /* Project object */;
@@ -77,7 +57,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
- 2351F8532207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -88,26 +67,19 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
- 23C3ABB023FBD0F80079D9C3 /* DSFFloatLabelledTextField.framework in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DSFFloatLabelledTextField.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 2351F84D2207D15C00EFA4F7 /* DSFFloatLabelledTextControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSFFloatLabelledTextControl.h; sourceTree = ""; };
- 2351F84E2207D15C00EFA4F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- 2351F85922082AD800EFA4F7 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; };
- 2351F85A22082AD800EFA4F7 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
23A2B7E9220792FE00B2FC77 /* DSFFloatLabelledTextControls.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DSFFloatLabelledTextControls.app; sourceTree = BUILT_PRODUCTS_DIR; };
23A2B7EC220792FE00B2FC77 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
23A2B7EE220792FF00B2FC77 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23A2B7F1220792FF00B2FC77 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
23A2B7F3220792FF00B2FC77 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
23A2B7F4220792FF00B2FC77 /* DSFFloatLabelledTextControls.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DSFFloatLabelledTextControls.entitlements; sourceTree = ""; };
- 23A2B7FA2207931500B2FC77 /* DSFFloatLabelledTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DSFFloatLabelledTextField.swift; sourceTree = ""; };
- 23ACF96D228A3F6600FF6594 /* DSFFloatLabelledTextControl.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = DSFFloatLabelledTextControl.podspec; sourceTree = ""; };
+ 23A3061A29C12C9C00BEC98A /* DSFFloatLabelledTextControls */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DSFFloatLabelledTextControls; path = ..; sourceTree = ""; };
23C3AB9A23FBCFA30079D9C3 /* DSFFloatLabelledTextControls Demo objc.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DSFFloatLabelledTextControls Demo objc.app"; sourceTree = BUILT_PRODUCTS_DIR; };
23C3AB9C23FBCFA30079D9C3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
23C3AB9D23FBCFA30079D9C3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
@@ -117,22 +89,14 @@
23C3ABA523FBCFA40079D9C3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
23C3ABA723FBCFA40079D9C3 /* DSFFloatLabelledTextControls_Demo_objc.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DSFFloatLabelledTextControls_Demo_objc.entitlements; sourceTree = ""; };
23E8256D2575D28A0023A3C7 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/MainMenu.strings; sourceTree = ""; };
- 23FFF1CD23BD490F008FA55A /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
- 2351F8482207D15C00EFA4F7 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
23A2B7E6220792FE00B2FC77 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 2351F8522207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework in Frameworks */,
+ 23A3061C29C12CB200BEC98A /* DSFFloatLabelledTextField in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -140,32 +104,18 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 23C3ABAC23FBCFDE0079D9C3 /* DSFFloatLabelledTextField.framework in Frameworks */,
+ 23A3061E29C12CB800BEC98A /* DSFFloatLabelledTextField in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- 2351F84C2207D15C00EFA4F7 /* DSFFloatLabelledTextField */ = {
- isa = PBXGroup;
- children = (
- 23A2B7FA2207931500B2FC77 /* DSFFloatLabelledTextField.swift */,
- 2351F84D2207D15C00EFA4F7 /* DSFFloatLabelledTextControl.h */,
- 2351F84E2207D15C00EFA4F7 /* Info.plist */,
- );
- path = DSFFloatLabelledTextField;
- sourceTree = "";
- };
23A2B7E0220792FE00B2FC77 = {
isa = PBXGroup;
children = (
+ 23A3061A29C12C9C00BEC98A /* DSFFloatLabelledTextControls */,
23FFF1CF23BD4982008FA55A /* Demos */,
- 23FFF1CE23BD496A008FA55A /* Sources */,
- 23ACF96D228A3F6600FF6594 /* DSFFloatLabelledTextControl.podspec */,
- 2351F85922082AD800EFA4F7 /* LICENSE */,
- 2351F85A22082AD800EFA4F7 /* README.md */,
- 23FFF1CD23BD490F008FA55A /* Package.swift */,
23A2B7EA220792FE00B2FC77 /* Products */,
23C3ABAB23FBCFDE0079D9C3 /* Frameworks */,
);
@@ -175,7 +125,6 @@
isa = PBXGroup;
children = (
23A2B7E9220792FE00B2FC77 /* DSFFloatLabelledTextControls.app */,
- 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */,
23C3AB9A23FBCFA30079D9C3 /* DSFFloatLabelledTextControls Demo objc.app */,
);
name = Products;
@@ -214,14 +163,6 @@
name = Frameworks;
sourceTree = "";
};
- 23FFF1CE23BD496A008FA55A /* Sources */ = {
- isa = PBXGroup;
- children = (
- 2351F84C2207D15C00EFA4F7 /* DSFFloatLabelledTextField */,
- );
- path = Sources;
- sourceTree = "";
- };
23FFF1CF23BD4982008FA55A /* Demos */ = {
isa = PBXGroup;
children = (
@@ -233,36 +174,7 @@
};
/* End PBXGroup section */
-/* Begin PBXHeadersBuildPhase section */
- 2351F8462207D15C00EFA4F7 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2351F84F2207D15C00EFA4F7 /* DSFFloatLabelledTextControl.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXHeadersBuildPhase section */
-
/* Begin PBXNativeTarget section */
- 2351F84A2207D15C00EFA4F7 /* DSFFloatLabelledTextField */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 2351F8542207D15C00EFA4F7 /* Build configuration list for PBXNativeTarget "DSFFloatLabelledTextField" */;
- buildPhases = (
- 2351F8462207D15C00EFA4F7 /* Headers */,
- 2351F8472207D15C00EFA4F7 /* Sources */,
- 2351F8482207D15C00EFA4F7 /* Frameworks */,
- 2351F8492207D15C00EFA4F7 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = DSFFloatLabelledTextField;
- productName = DSFFloatLabelledTextControl;
- productReference = 2351F84B2207D15C00EFA4F7 /* DSFFloatLabelledTextField.framework */;
- productType = "com.apple.product-type.framework";
- };
23A2B7E8220792FE00B2FC77 /* DSFFloatLabelledTextControls */ = {
isa = PBXNativeTarget;
buildConfigurationList = 23A2B7F7220792FF00B2FC77 /* Build configuration list for PBXNativeTarget "DSFFloatLabelledTextControls" */;
@@ -275,9 +187,11 @@
buildRules = (
);
dependencies = (
- 2351F8512207D15C00EFA4F7 /* PBXTargetDependency */,
);
name = DSFFloatLabelledTextControls;
+ packageProductDependencies = (
+ 23A3061B29C12CB200BEC98A /* DSFFloatLabelledTextField */,
+ );
productName = DSFFloatLabelledTextControls;
productReference = 23A2B7E9220792FE00B2FC77 /* DSFFloatLabelledTextControls.app */;
productType = "com.apple.product-type.application";
@@ -294,9 +208,11 @@
buildRules = (
);
dependencies = (
- 23C3ABAE23FBCFE40079D9C3 /* PBXTargetDependency */,
);
name = "DSFFloatLabelledTextControls Demo objc";
+ packageProductDependencies = (
+ 23A3061D29C12CB800BEC98A /* DSFFloatLabelledTextField */,
+ );
productName = "DSFFloatLabelledTextControls Demo objc";
productReference = 23C3AB9A23FBCFA30079D9C3 /* DSFFloatLabelledTextControls Demo objc.app */;
productType = "com.apple.product-type.application";
@@ -311,9 +227,6 @@
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Darren Ford";
TargetAttributes = {
- 2351F84A2207D15C00EFA4F7 = {
- CreatedOnToolsVersion = 10.1;
- };
23A2B7E8220792FE00B2FC77 = {
CreatedOnToolsVersion = 10.1;
};
@@ -339,7 +252,6 @@
projectDirPath = "";
projectRoot = "";
targets = (
- 2351F84A2207D15C00EFA4F7 /* DSFFloatLabelledTextField */,
23A2B7E8220792FE00B2FC77 /* DSFFloatLabelledTextControls */,
23C3AB9923FBCFA30079D9C3 /* DSFFloatLabelledTextControls Demo objc */,
23E825612575D1760023A3C7 /* All */,
@@ -348,20 +260,11 @@
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
- 2351F8492207D15C00EFA4F7 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
23A2B7E7220792FE00B2FC77 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 2351F85B22082AD800EFA4F7 /* LICENSE in Resources */,
23A2B7EF220792FF00B2FC77 /* Assets.xcassets in Resources */,
- 2351F85C22082AD800EFA4F7 /* README.md in Resources */,
23A2B7F2220792FF00B2FC77 /* MainMenu.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -378,14 +281,6 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
- 2351F8472207D15C00EFA4F7 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2351F8582207D16100EFA4F7 /* DSFFloatLabelledTextField.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
23A2B7E5220792FE00B2FC77 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -406,16 +301,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 2351F8512207D15C00EFA4F7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2351F84A2207D15C00EFA4F7 /* DSFFloatLabelledTextField */;
- targetProxy = 2351F8502207D15C00EFA4F7 /* PBXContainerItemProxy */;
- };
- 23C3ABAE23FBCFE40079D9C3 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 2351F84A2207D15C00EFA4F7 /* DSFFloatLabelledTextField */;
- targetProxy = 23C3ABAD23FBCFE40079D9C3 /* PBXContainerItemProxy */;
- };
23E825682575D17E0023A3C7 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 23A2B7E8220792FE00B2FC77 /* DSFFloatLabelledTextControls */;
@@ -449,66 +334,6 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
- 2351F8552207D15C00EFA4F7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CODE_SIGN_IDENTITY = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DEVELOPMENT_TEAM = "";
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- FRAMEWORK_VERSION = A;
- INFOPLIST_FILE = Sources/DSFFloatLabelledTextField/Info.plist;
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.5;
- PRODUCT_BUNDLE_IDENTIFIER = com.darrenford.DSFFloatLabelledTextControl;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
- SKIP_INSTALL = YES;
- SWIFT_VERSION = 4.2;
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Debug;
- };
- 2351F8562207D15C00EFA4F7 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CODE_SIGN_IDENTITY = "Apple Development";
- CODE_SIGN_STYLE = Automatic;
- COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DEVELOPMENT_TEAM = "";
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- FRAMEWORK_VERSION = A;
- INFOPLIST_FILE = Sources/DSFFloatLabelledTextField/Info.plist;
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.5;
- PRODUCT_BUNDLE_IDENTIFIER = com.darrenford.DSFFloatLabelledTextControl;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
- SKIP_INSTALL = YES;
- SWIFT_VERSION = 4.2;
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Release;
- };
23A2B7F5220792FF00B2FC77 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -629,7 +454,6 @@
23A2B7F8220792FF00B2FC77 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "";
CODE_SIGN_ENTITLEMENTS = Demos/DSFFloatLabelledTextControls/DSFFloatLabelledTextControls.entitlements;
@@ -642,6 +466,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.darrenford.DSFFloatLabelledTextControls;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -653,7 +478,6 @@
23A2B7F9220792FF00B2FC77 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = "";
CODE_SIGN_ENTITLEMENTS = Demos/DSFFloatLabelledTextControls/DSFFloatLabelledTextControls.entitlements;
@@ -666,6 +490,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.darrenford.DSFFloatLabelledTextControls;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -680,17 +505,17 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "Demos/DSFFloatLabelledTextControls Demo objc/DSFFloatLabelledTextControls_Demo_objc.entitlements";
- CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- DEVELOPMENT_TEAM = 3L6RK3LGGW;
+ DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Demos/DSFFloatLabelledTextControls Demo objc/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFFloatLabelledTextControls-Demo-objc";
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -702,17 +527,17 @@
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "Demos/DSFFloatLabelledTextControls Demo objc/DSFFloatLabelledTextControls_Demo_objc.entitlements";
- CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- DEVELOPMENT_TEAM = 3L6RK3LGGW;
+ DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "Demos/DSFFloatLabelledTextControls Demo objc/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFFloatLabelledTextControls-Demo-objc";
PRODUCT_NAME = "$(TARGET_NAME)";
};
@@ -739,15 +564,6 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 2351F8542207D15C00EFA4F7 /* Build configuration list for PBXNativeTarget "DSFFloatLabelledTextField" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 2351F8552207D15C00EFA4F7 /* Debug */,
- 2351F8562207D15C00EFA4F7 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
23A2B7E4220792FE00B2FC77 /* Build configuration list for PBXProject "DSFFloatLabelledTextControls" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -785,6 +601,17 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 23A3061B29C12CB200BEC98A /* DSFFloatLabelledTextField */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DSFFloatLabelledTextField;
+ };
+ 23A3061D29C12CB800BEC98A /* DSFFloatLabelledTextField */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DSFFloatLabelledTextField;
+ };
+/* End XCSwiftPackageProductDependency section */
};
rootObject = 23A2B7E1220792FE00B2FC77 /* Project object */;
}
diff --git a/DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Demos/DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Demos/DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls Demo objc.xcscheme b/Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls Demo objc.xcscheme
similarity index 100%
rename from DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls Demo objc.xcscheme
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls Demo objc.xcscheme
diff --git a/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls RTL.xcscheme b/Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls RTL.xcscheme
similarity index 100%
rename from DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls RTL.xcscheme
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls RTL.xcscheme
diff --git a/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls.xcscheme b/Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls.xcscheme
similarity index 100%
rename from DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls.xcscheme
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextControls.xcscheme
diff --git a/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextField.xcscheme b/Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextField.xcscheme
similarity index 100%
rename from DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextField.xcscheme
rename to Demos/DSFFloatLabelledTextControls.xcodeproj/xcshareddata/xcschemes/DSFFloatLabelledTextField.xcscheme
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.h b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.h
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.h
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.h
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.m b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.m
similarity index 87%
rename from Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.m
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.m
index 720bb9f..443f28f 100644
--- a/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.m
+++ b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/AppDelegate.m
@@ -24,7 +24,7 @@
// Insert code here to tear down your application
}
-- (void)floatLabelledTextFieldContentChanged:(DSFFloatLabelledTextField *)field {
+- (void)floatLabelledTextFieldContentChanged:(DSFFloatLabelledSecureTextField *)field {
NSLog(@"Password is now `%@`", field.stringValue);
}
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/AppIcon.appiconset/Contents.json b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/Contents.json b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/Contents.json
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/Contents.json
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/Assets.xcassets/Contents.json
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/Base.lproj/MainMenu.xib b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/Base.lproj/MainMenu.xib
similarity index 98%
rename from Demos/DSFFloatLabelledTextControls Demo objc/Base.lproj/MainMenu.xib
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/Base.lproj/MainMenu.xib
index d5d659b..9b06dba 100644
--- a/Demos/DSFFloatLabelledTextControls Demo objc/Base.lproj/MainMenu.xib
+++ b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/Base.lproj/MainMenu.xib
@@ -1,8 +1,8 @@
-
+
-
+
@@ -692,7 +692,7 @@
-
+
@@ -705,7 +705,7 @@
-
+
@@ -718,7 +718,7 @@
-
+
@@ -729,7 +729,6 @@
-
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/DSFFloatLabelledTextControls_Demo_objc.entitlements b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/DSFFloatLabelledTextControls_Demo_objc.entitlements
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls Demo objc/DSFFloatLabelledTextControls_Demo_objc.entitlements
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/DSFFloatLabelledTextControls_Demo_objc.entitlements
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/Info.plist b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/Info.plist
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls Demo objc/Info.plist
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/Info.plist
diff --git a/Demos/DSFFloatLabelledTextControls Demo objc/main.m b/Demos/Demos/DSFFloatLabelledTextControls Demo objc/main.m
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls Demo objc/main.m
rename to Demos/Demos/DSFFloatLabelledTextControls Demo objc/main.m
diff --git a/Demos/DSFFloatLabelledTextControls/AppDelegate.swift b/Demos/Demos/DSFFloatLabelledTextControls/AppDelegate.swift
similarity index 84%
rename from Demos/DSFFloatLabelledTextControls/AppDelegate.swift
rename to Demos/Demos/DSFFloatLabelledTextControls/AppDelegate.swift
index 802aefa..e89b7fe 100644
--- a/Demos/DSFFloatLabelledTextControls/AppDelegate.swift
+++ b/Demos/Demos/DSFFloatLabelledTextControls/AppDelegate.swift
@@ -35,6 +35,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
@IBOutlet weak var topFloatingLabel: DSFFloatLabelledTextField!
+ @IBOutlet weak var secureTextField: DSFFloatLabelledSecureTextField!
@IBOutlet weak var passwordFloatingLabel: DSFFloatLabelledTextField!
func applicationDidFinishLaunching(_ aNotification: Notification) {
@@ -47,26 +48,34 @@ class AppDelegate: NSObject, NSApplicationDelegate {
let cv = self.window.contentView!
- let x = NSLayoutConstraint(item: ft, attribute: .width,
- relatedBy: .equal,
- toItem: nil, attribute: .notAnAttribute,
- multiplier: 1, constant: 300)
+ let x = NSLayoutConstraint(
+ item: ft, attribute: .width,
+ relatedBy: .equal,
+ toItem: nil, attribute: .notAnAttribute,
+ multiplier: 1, constant: 300
+ )
ft.addConstraint(x)
cv.addSubview(ft)
- let x1 = NSLayoutConstraint(item: ft, attribute: .left,
- relatedBy: .equal,
- toItem: cv, attribute: .left,
- multiplier: 1, constant: 20)
+ let x1 = NSLayoutConstraint(
+ item: ft, attribute: .leading,
+ relatedBy: .equal,
+ toItem: cv, attribute: .leading,
+ multiplier: 1, constant: 20
+ )
cv.addConstraint(x1)
- let x2 = NSLayoutConstraint(item: ft, attribute: .bottom,
- relatedBy: .equal,
- toItem: cv, attribute: .bottom,
- multiplier: 1, constant: -20)
+ let x2 = NSLayoutConstraint(
+ item: ft, attribute: .bottom,
+ relatedBy: .equal,
+ toItem: cv, attribute: .bottom,
+ multiplier: 1, constant: -20
+ )
cv.addConstraint(x2)
+
+ self.secureTextField.stringValue = "caterpillar"
}
@IBAction func resetPressed(_ sender: Any) {
diff --git a/Demos/DSFFloatLabelledTextControls/Assets.xcassets/AppIcon.appiconset/Contents.json b/Demos/Demos/DSFFloatLabelledTextControls/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to Demos/Demos/DSFFloatLabelledTextControls/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/Demos/DSFFloatLabelledTextControls/Assets.xcassets/Contents.json b/Demos/Demos/DSFFloatLabelledTextControls/Assets.xcassets/Contents.json
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls/Assets.xcassets/Contents.json
rename to Demos/Demos/DSFFloatLabelledTextControls/Assets.xcassets/Contents.json
diff --git a/Demos/DSFFloatLabelledTextControls/Base.lproj/MainMenu.xib b/Demos/Demos/DSFFloatLabelledTextControls/Base.lproj/MainMenu.xib
similarity index 97%
rename from Demos/DSFFloatLabelledTextControls/Base.lproj/MainMenu.xib
rename to Demos/Demos/DSFFloatLabelledTextControls/Base.lproj/MainMenu.xib
index 0021f6f..c802433 100644
--- a/Demos/DSFFloatLabelledTextControls/Base.lproj/MainMenu.xib
+++ b/Demos/Demos/DSFFloatLabelledTextControls/Base.lproj/MainMenu.xib
@@ -1,8 +1,8 @@
-
+
-
+
@@ -16,6 +16,7 @@
+
@@ -686,19 +687,19 @@
-
+
-
+
-
-
-
+
+
+
-
+
@@ -714,7 +715,7 @@
-
diff --git a/Demos/DSFFloatLabelledTextControls/DSFFloatLabelledTextControls.entitlements b/Demos/Demos/DSFFloatLabelledTextControls/DSFFloatLabelledTextControls.entitlements
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls/DSFFloatLabelledTextControls.entitlements
rename to Demos/Demos/DSFFloatLabelledTextControls/DSFFloatLabelledTextControls.entitlements
diff --git a/Demos/DSFFloatLabelledTextControls/Info.plist b/Demos/Demos/DSFFloatLabelledTextControls/Info.plist
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls/Info.plist
rename to Demos/Demos/DSFFloatLabelledTextControls/Info.plist
diff --git a/Demos/DSFFloatLabelledTextControls/ar.lproj/MainMenu.strings b/Demos/Demos/DSFFloatLabelledTextControls/ar.lproj/MainMenu.strings
similarity index 100%
rename from Demos/DSFFloatLabelledTextControls/ar.lproj/MainMenu.strings
rename to Demos/Demos/DSFFloatLabelledTextControls/ar.lproj/MainMenu.strings
diff --git a/Package.swift b/Package.swift
index a16c6ee..d95c09c 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1,29 +1,23 @@
-// swift-tools-version:5.1
-// The swift-tools-version declares the minimum version of Swift required to build this package.
+// swift-tools-version: 5.4
import PackageDescription
let package = Package(
- name: "DSFFloatLabelledTextField",
- platforms: [
- .macOS(.v10_11)
- ],
- products: [
- // Products define the executables and libraries produced by a package, and make them visible to other packages.
- .library(
- name: "DSFFloatLabelledTextField",
- targets: ["DSFFloatLabelledTextField"]),
- ],
- dependencies: [
- // Dependencies declare other packages that this package depends on.
- // .package(url: /* package url */, from: "1.0.0"),
- ],
- targets: [
- // Targets are the basic building blocks of a package. A target can define a module or a test suite.
- // Targets can depend on other targets in this package, and on products in packages which this package depends on.
- .target(
- name: "DSFFloatLabelledTextField",
- dependencies: [])
- ],
- swiftLanguageVersions: [.v5]
+ name: "DSFFloatLabelledTextField",
+ platforms: [
+ .macOS(.v10_11)
+ ],
+ products: [
+ .library(
+ name: "DSFFloatLabelledTextField",
+ targets: ["DSFFloatLabelledTextField"]
+ ),
+ ],
+ targets: [
+ .target(
+ name: "DSFFloatLabelledTextField",
+ dependencies: []
+ )
+ ],
+ swiftLanguageVersions: [.v5]
)
diff --git a/README.md b/README.md
index 626851f..2a6a5ea 100644
--- a/README.md
+++ b/README.md
@@ -30,10 +30,10 @@ Copy the `DSFFloatLabelledTextField.swift` into your project. This class inheri
### Interface builder
-* Drop in a new Text Field into your canvas and set its class to `DSFFloatLabelledTextField`
+* Drop in a new Text Field into your canvas and set its class to `DSFFloatLabelledTextField` or
+ `DSFFloatLabelledSecureTextControl` depending on whether you need a secure field
* Set the size and style of your primary font as you would a regular text field
* Set the size of the secondary font via the attributes inspector for the control
-* If you want a secure field, set the `isSecure` property on the control
### Dynamically
@@ -89,7 +89,7 @@ You can specify a delegate (`floatLabelDelegate`), either programatically or via
```
MIT License
-Copyright (c) 2020 Darren Ford
+Copyright (c) 2023 Darren Ford
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Sources/DSFFloatLabelledTextField/DSFFloatLabelledSecureTextField.swift b/Sources/DSFFloatLabelledTextField/DSFFloatLabelledSecureTextField.swift
new file mode 100644
index 0000000..b2aa182
--- /dev/null
+++ b/Sources/DSFFloatLabelledTextField/DSFFloatLabelledSecureTextField.swift
@@ -0,0 +1,451 @@
+//
+// DSFFloatLabelledSecureTextField.swift
+//
+// Copyright © 2023 Darren Ford. All rights reserved.
+//
+// MIT license
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+import AppKit
+
+/// DSFFloatLabelledTextField delegate protocol
+@objc public protocol DSFFloatLabelledSecureTextFieldDelegate: NSObjectProtocol {
+ /// Called when the label is shown or hidden
+ @objc optional func floatLabelledTextField(_ field: DSFFloatLabelledSecureTextField, didShowFloatingLabel didShow: Bool)
+ /// Called when the field becomes or loses first responder status
+ @objc optional func floatLabelledTextField(_ field: DSFFloatLabelledSecureTextField, didFocus: Bool)
+ /// Called when the content of the field changes
+ @objc optional func floatLabelledTextFieldContentChanged(_ field: DSFFloatLabelledSecureTextField)
+}
+
+/// An NSSecureTextField that implements the Float Label Pattern
+@IBDesignable open class DSFFloatLabelledSecureTextField: NSSecureTextField {
+
+ /// Optional delegate to provide callbacks for the floating label state.
+ ///
+ /// This delegate can be set via Interface Builder or programatically
+ @IBOutlet @objc public weak var floatLabelDelegate: DSFFloatLabelledSecureTextFieldDelegate?
+
+ /// The size (in pt) of the floating label text
+ @IBInspectable public var placeholderTextSize: CGFloat = NSFont.smallSystemFontSize {
+ didSet {
+ self.floatingLabel.font = NSFont.systemFont(ofSize: self.placeholderTextSize)
+ self.reconfigureControl()
+ }
+ }
+
+ /// Spacing between the floating label and the text field text
+ @IBInspectable public var placeholderSpacing: CGFloat = 0.0 {
+ didSet {
+ self.floatingLabel.font = NSFont.systemFont(ofSize: self.placeholderTextSize)
+ self.reconfigureControl()
+ }
+ }
+
+ // Override so that we can notify when the developer changes the text programatically too
+ open override var stringValue: String {
+ get {
+ return super.stringValue
+ }
+ set {
+ super.stringValue = newValue
+ NotificationCenter.default.post(name: NSControl.textDidChangeNotification, object: self)
+ }
+ }
+
+ // Override so that we can update when the developer changes the placeholder string
+ open override var placeholderString: String? {
+ get {
+ return super.placeholderString
+ }
+ set {
+ super.placeholderString = newValue
+ self.floatingLabel.stringValue = newValue ?? ""
+ }
+ }
+
+ /// Floating label
+ private let floatingLabel = NSTextField()
+
+ /// Is the label currently showing
+ private var isShowing: Bool = false {
+ didSet {
+ self.floatLabelDelegate?.floatLabelledTextField?(self, didShowFloatingLabel: self.isShowing)
+ }
+ }
+
+ /// Constraint to tie the label to the top of the control
+ private var floatingTop: NSLayoutConstraint?
+
+ /// Height of the control
+ private var heightConstraint: NSLayoutConstraint?
+
+ /// Observers for the font and placeholder text
+ private var fontObserver: NSKeyValueObservation?
+ private var placeholderObserver: NSKeyValueObservation?
+
+ /// Returns the height of the placeholder text
+ var placeholderHeight: CGFloat {
+ let layoutManager = NSLayoutManager()
+ return layoutManager.defaultLineHeight(for: self.floatingLabel.font!) + 1
+ }
+
+ /// Returns the height of the primary (editable) text
+ private var textHeight: CGFloat {
+ let layoutManager = NSLayoutManager()
+ return layoutManager.defaultLineHeight(for: self.font!) + 1
+ }
+
+ /// Returns the total height of the control given the font settings
+ private var controlHeight: CGFloat {
+ return self.textHeight + self.placeholderSpacing + self.placeholderHeight
+ }
+
+ open override var intrinsicContentSize: NSSize {
+ var sz = super.intrinsicContentSize
+ sz.height = self.controlHeight
+ return sz
+ }
+
+ func configureCell() {
+ let customCell = DSFFloatLabelledSecureTextFieldCell()
+ customCell.isEditable = true
+ customCell.wraps = false
+ customCell.usesSingleLineMode = true
+ customCell.placeholderString = self.placeholderString
+ customCell.title = self.stringValue
+ customCell.font = self.font
+ customCell.isBordered = self.isBordered
+ customCell.isBezeled = self.isBezeled
+ customCell.bezelStyle = self.bezelStyle
+ customCell.isScrollable = true
+ customCell.isContinuous = self.isContinuous
+ customCell.alignment = self.alignment
+ customCell.formatter = self.formatter
+ customCell.topOffset = self.placeholderHeight
+ self.cell = customCell
+ }
+
+ func setTopOffset(_ value: CGFloat) {
+ guard var f = self.cell as? DSFFloatLabelledTextFieldCellProtocol else {
+ return
+ }
+ f.topOffset = value
+ }
+
+ /// Set the fonts to be used in the control
+ open func setFonts(primary: NSFont, secondary: NSFont) {
+ self.floatingLabel.font = secondary
+ self.font = primary
+ }
+
+ public override init(frame frameRect: NSRect) {
+ super.init(frame: frameRect)
+ self.setup()
+ }
+
+ required public init?(coder: NSCoder) {
+ super.init(coder: coder)
+ self.setup()
+ }
+
+ open override func awakeFromNib() {
+ super.awakeFromNib()
+
+ }
+
+ open override func viewDidMoveToWindow() {
+ super.viewDidMoveToWindow()
+
+ // When we're added to the view, make sure that the floating label alignment matches us
+ // (as the user might have changed the alignment BEFORE adding to the superview
+ self.floatingLabel.alignment = self.alignment
+ }
+
+ private func setup() {
+ // Setup the common elements of the control
+ self.commonSetup()
+
+ // Configure a default text cell
+ self.configureCell()
+
+ // Listen to changes in the primary font so we can reconfigure to match
+ self.fontObserver = self.observe(\.font, options: [.new]) { [weak self] _, _ in
+ self?.reconfigureControl()
+ }
+
+ // Listen to changes in the placeholder text so we can reflect it in the floater
+ self.placeholderObserver = self.observe(\.placeholderString, options: [.new]) { [weak self] _, _ in
+ guard let `self` = self else { return }
+ self.floatingLabel.stringValue = self.placeholderString!
+ self.reconfigureControl()
+ }
+ }
+
+ /// Build the floating label
+ private func createFloatingLabel() {
+ if self.floatingLabel.superview == nil {
+ self.addSubview(self.floatingLabel)
+ }
+
+ self.floatingLabel.wantsLayer = true
+ self.floatingLabel.isEditable = false
+ self.floatingLabel.isSelectable = false
+ self.floatingLabel.isEnabled = true
+ self.floatingLabel.isBezeled = false
+ self.floatingLabel.isBordered = false
+ self.floatingLabel.translatesAutoresizingMaskIntoConstraints = false
+ self.floatingLabel.font = NSFont.systemFont(ofSize: self.placeholderTextSize)
+ self.floatingLabel.textColor = NSColor.placeholderTextColor
+ self.floatingLabel.stringValue = self.placeholderString ?? ""
+ self.floatingLabel.alphaValue = 0.0
+ self.floatingLabel.alignment = self.alignment
+ self.floatingLabel.drawsBackground = false
+
+ self.floatingTop = NSLayoutConstraint(
+ item: self.floatingLabel, attribute: .top,
+ relatedBy: .equal,
+ toItem: self, attribute: .top,
+ multiplier: 1.0, constant: 10
+ )
+ self.addConstraint(self.floatingTop!)
+
+ var x = NSLayoutConstraint(
+ item: self.floatingLabel, attribute: .leading,
+ relatedBy: .equal,
+ toItem: self, attribute: .leading,
+ multiplier: 1.0, constant: self.isBezeled ? 4 : 0
+ )
+ self.addConstraint(x)
+
+ x = NSLayoutConstraint(
+ item: self.floatingLabel, attribute: .trailing,
+ relatedBy: .equal,
+ toItem: self, attribute: .trailing,
+ multiplier: 1.0, constant: self.isBezeled ? -4 : 0
+ )
+ self.addConstraint(x)
+
+ self.floatingLabel.setContentHuggingPriority(NSLayoutConstraint.Priority(10), for: .horizontal)
+ self.floatingLabel.setContentCompressionResistancePriority(NSLayoutConstraint.Priority(10), for: .horizontal)
+ }
+
+ private func commonSetup() {
+ self.wantsLayer = true
+ self.translatesAutoresizingMaskIntoConstraints = false
+ self.usesSingleLineMode = true
+ self.delegate = self
+
+ // Default to natural layout
+ self.alignment = .natural
+
+ self.createFloatingLabel()
+
+ self.heightConstraint = NSLayoutConstraint(
+ item: self, attribute: .height,
+ relatedBy: .equal,
+ toItem: nil, attribute: .notAnAttribute,
+ multiplier: 1.0, constant: self.controlHeight
+ )
+ self.addConstraint(self.heightConstraint!)
+
+ // If the field already has text, make sure the placeholder is shown
+ if self.stringValue.count > 0 {
+ self.showPlaceholder(animated: false)
+ }
+ }
+
+ /// Change the layout if any changes occur
+ private func reconfigureControl() {
+ if self.isCurrentFocus() {
+ /// If we are currently editing, then finish before changing.
+ self.window?.endEditing(for: nil)
+ }
+ self.expandFrame()
+ }
+
+ /// Rebuild the frame of the text field to match the new settings
+ private func expandFrame() {
+ self.heightConstraint?.constant = self.controlHeight
+ self.setTopOffset(self.placeholderHeight + self.placeholderSpacing)
+ self.needsLayout = true
+ }
+
+ open override func layout() {
+ super.layout()
+
+ self.setTopOffset(self.placeholderHeight + self.placeholderSpacing)
+ self.needsLayout = true
+ }
+
+}
+
+// MARK: - Focus and editing
+
+extension DSFFloatLabelledSecureTextField: NSTextFieldDelegate {
+
+ // Change the floating label color to represent active state
+ private func setFloatingLabelActive(_ active: Bool) {
+ if active {
+ self.floatingLabel.textColor = NSColor.simulatedAccentColor
+ }
+ else {
+ self.floatingLabel.textColor = NSColor.placeholderTextColor
+ }
+
+ self.floatLabelDelegate?.floatLabelledTextField?(self, didFocus: active)
+ }
+
+ public func controlTextDidChange(_ obj: Notification) {
+ guard let field = obj.object as? NSTextField else {
+ return
+ }
+
+ if field.stringValue.count > 0, !self.isShowing {
+ self.showPlaceholder(animated: true)
+ }
+ else if field.stringValue.count == 0, self.isShowing {
+ self.hidePlaceholder()
+ }
+
+ self.floatLabelDelegate?.floatLabelledTextFieldContentChanged?(self)
+ }
+
+ open override func becomeFirstResponder() -> Bool {
+ let becomeResult = super.becomeFirstResponder()
+ if becomeResult, self.isCurrentFocus() {
+ // Set the color of the 'label' to match the current focus color.
+ // We need to perform this on the main thread after the current set of notifications are processed
+ // Why? We (occasionally) receive a 'controlTextDidEndEditing' message AFTER we receive a
+ // 'becomeFirstResponder'. I've read that this is related to the text field automatically selecting
+ // text when taking focus, but I haven't been able to verify this in any useful manner.
+ DispatchQueue.main.async { [weak self] in
+ if let `self` = self {
+ self.setFloatingLabelActive(true)
+ }
+ }
+ }
+ return becomeResult
+ }
+
+ open func controlTextDidEndEditing(_: Notification) {
+ // When we lose focus, set the label color back to the placeholder color
+ self.setFloatingLabelActive(false)
+ }
+
+ /// Does our text field currently have input focus?
+ private func isCurrentFocus() -> Bool {
+ // 1. Get the window's first responder
+ // 2. Check is has an active field editor
+ // 3. Is the delegate of the field editor us?
+ if let fr = self.window?.firstResponder as? NSTextView,
+ self.window?.fieldEditor(false, for: nil) != nil,
+ fr.delegate === self {
+ return true
+ }
+ return false
+ }
+}
+
+// MARK: - Animations
+
+extension DSFFloatLabelledSecureTextField {
+
+ /// Duration of the fade in/out of the secondary label
+ private var animationDuration: TimeInterval {
+ return shouldAnimate() ? 0.4 : 0.0
+ }
+
+ /// Returns true if the system is NOT set to reduce motion (accessibility settings)
+ private func shouldAnimate() -> Bool {
+ if #available(OSX 10.12, *) {
+ return !NSWorkspace.shared.accessibilityDisplayShouldReduceMotion
+ } else {
+ // Fallback on earlier versions. Just animate
+ return true
+ }
+ }
+
+ private func showPlaceholder(animated: Bool) {
+ self.isShowing = true
+ if animated {
+ NSAnimationContext.runAnimationGroup({ [weak self] context in
+ guard let `self` = self else { return }
+ context.allowsImplicitAnimation = true
+ context.duration = self.animationDuration
+ self.floatingTop?.constant = 0
+ self.floatingLabel.alphaValue = 1.0
+ self.layoutSubtreeIfNeeded()
+ }, completionHandler: {
+ //
+ })
+ }
+ else {
+ self.setFloatingLabelActive(false)
+ self.floatingTop?.constant = 0
+ self.floatingLabel.alphaValue = 1.0
+ }
+ }
+
+ private func hidePlaceholder() {
+ self.isShowing = false
+ let duration = self.animationDuration
+ NSAnimationContext.runAnimationGroup({ [weak self] context in
+ guard let `self` = self else { return }
+ context.allowsImplicitAnimation = true
+ context.duration = duration
+ self.floatingTop?.constant = self.textHeight / 1.5
+ self.floatingLabel.alphaValue = 0.0
+ self.layoutSubtreeIfNeeded()
+ }, completionHandler: {
+ //
+ })
+ }
+}
+
+// MARK: - Cell definition
+
+private class DSFFloatLabelledSecureTextFieldCell: NSSecureTextFieldCell, DSFFloatLabelledTextFieldCellProtocol {
+ var topOffset: CGFloat = 0
+
+ private func offset() -> CGFloat {
+ return self.topOffset - (self.isBezeled ? 5 : 1)
+ }
+
+ override func titleRect(forBounds rect: NSRect) -> NSRect {
+ return NSRect(x: rect.origin.x, y: rect.origin.y + self.offset(), width: rect.width, height: rect.height)
+ }
+
+ override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
+ let insetRect = NSRect(x: rect.origin.x, y: rect.origin.y + self.offset(), width: rect.width, height: rect.height)
+ super.edit(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, event: event)
+ }
+
+ override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
+ let insetRect = NSRect(x: rect.origin.x, y: rect.origin.y + self.offset(), width: rect.width, height: rect.height)
+ super.select(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
+ }
+
+ override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
+ let insetRect = NSRect(x: cellFrame.origin.x, y: cellFrame.origin.y + self.offset(), width: cellFrame.width, height: cellFrame.height)
+ super.drawInterior(withFrame: insetRect, in: controlView)
+ }
+}
diff --git a/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextControl.h b/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextControl.h
deleted file mode 100644
index 953be89..0000000
--- a/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextControl.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// DSFFloatLabelledTextControl.h
-// DSFFloatLabelledTextControl
-//
-// Created by Darren Ford on 4/2/19.
-// Copyright © 2020 Darren Ford. All rights reserved.
-//
-// MIT License
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-#import
-
-//! Project version number for DSFFloatLabelledTextControl.
-FOUNDATION_EXPORT double DSFFloatLabelledTextControlVersionNumber;
-
-//! Project version string for DSFFloatLabelledTextControl.
-FOUNDATION_EXPORT const unsigned char DSFFloatLabelledTextControlVersionString[];
-
-// In this header, you should import all the public headers of your framework using statements like #import
-
-
diff --git a/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextField.swift b/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextField.swift
index 19cd85d..f7369ed 100644
--- a/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextField.swift
+++ b/Sources/DSFFloatLabelledTextField/DSFFloatLabelledTextField.swift
@@ -1,31 +1,30 @@
//
// DSFFloatLabelledTextField.swift
-// DSFFloatLabelledTextControls
//
-// Created by Darren Ford on 4/2/19.
-// Copyright © 2020 Darren Ford. All rights reserved.
+// Copyright © 2023 Darren Ford. All rights reserved.
//
-// MIT License
+// MIT license
//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-import Cocoa
+import AppKit
/// DSFFloatLabelledTextField delegate protocol
@objc public protocol DSFFloatLabelledTextFieldDelegate: NSObjectProtocol {
@@ -61,13 +60,6 @@ import Cocoa
}
}
- /// Spacing between the floating label and the text field text
- @IBInspectable public var isSecure: Bool = false {
- didSet {
- self.configureCell(isSecure: self.isSecure)
- }
- }
-
// Override so that we can notify when the developer changes the text programatically too
open override var stringValue: String {
get {
@@ -133,8 +125,8 @@ import Cocoa
return sz
}
- func configureCell(isSecure: Bool = false) {
- let customCell: NSTextFieldCell = isSecure ? DSFFloatLabelledSecureTextFieldCell() : DSFFloatLabelledTextFieldCell()
+ func configureCell() {
+ let customCell = DSFFloatLabelledTextFieldCell()
customCell.isEditable = true
customCell.wraps = false
customCell.usesSingleLineMode = true
@@ -148,10 +140,7 @@ import Cocoa
customCell.isContinuous = self.isContinuous
customCell.alignment = self.alignment
customCell.formatter = self.formatter
-
- if var s = customCell as? DSFFloatLabelledTextFieldCellProtocol {
- s.topOffset = self.placeholderHeight
- }
+ customCell.topOffset = self.placeholderHeight
self.cell = customCell
}
@@ -192,7 +181,7 @@ import Cocoa
self.commonSetup()
// Configure a default text cell
- self.configureCell(isSecure: false)
+ self.configureCell()
// Listen to changes in the primary font so we can reconfigure to match
self.fontObserver = self.observe(\.font, options: [.new]) { [weak self] _, _ in
@@ -312,7 +301,7 @@ extension DSFFloatLabelledTextField: NSTextFieldDelegate {
// Change the floating label color to represent active state
private func setFloatingLabelActive(_ active: Bool) {
if active {
- self.floatingLabel.textColor = NSColor.systemAccentColor
+ self.floatingLabel.textColor = NSColor.simulatedAccentColor
}
else {
self.floatingLabel.textColor = NSColor.placeholderTextColor
@@ -430,10 +419,6 @@ extension DSFFloatLabelledTextField {
// MARK: - Cell definition
-protocol DSFFloatLabelledTextFieldCellProtocol {
- var topOffset: CGFloat { get set }
-}
-
private class DSFFloatLabelledTextFieldCell: NSTextFieldCell, DSFFloatLabelledTextFieldCellProtocol {
var topOffset: CGFloat = 0
@@ -460,76 +445,3 @@ private class DSFFloatLabelledTextFieldCell: NSTextFieldCell, DSFFloatLabelledTe
super.drawInterior(withFrame: insetRect, in: controlView)
}
}
-
-private class DSFFloatLabelledSecureTextFieldCell: NSSecureTextFieldCell, DSFFloatLabelledTextFieldCellProtocol {
- var topOffset: CGFloat = 0
-
- private func offset() -> CGFloat {
- return self.topOffset - (self.isBezeled ? 5 : 1)
- }
-
- override func titleRect(forBounds rect: NSRect) -> NSRect {
- return NSRect(x: rect.origin.x, y: rect.origin.y + self.offset(), width: rect.width, height: rect.height)
- }
-
- override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
- let insetRect = NSRect(x: rect.origin.x, y: rect.origin.y + self.offset(), width: rect.width, height: rect.height)
- super.edit(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, event: event)
- }
-
- override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
- let insetRect = NSRect(x: rect.origin.x, y: rect.origin.y + self.offset(), width: rect.width, height: rect.height)
- super.select(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
- }
-
- override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
- let insetRect = NSRect(x: cellFrame.origin.x, y: cellFrame.origin.y + self.offset(), width: cellFrame.width, height: cellFrame.height)
- super.drawInterior(withFrame: insetRect, in: controlView)
- }
-}
-
-/// MARK: - Utilities
-
-fileprivate let kAccentColor: String = "AppleAccentColor"
-fileprivate extension NSColor {
-
- /// The system accent color, with fallbacks for older macOS versions
- static var systemAccentColor: NSColor {
- if #available(OSX 10.14, *) {
- // macOS 10.14 and above have a dedicated static NSColor
- return NSColor.controlAccentColor
- }
-
- // Use standard user defaults for anything lower than 10.14
- let userDefaults = UserDefaults.standard
- guard userDefaults.object(forKey: kAccentColor) != nil else {
- return DefaultColor()
- }
-
- return ColorForSystemColorOffset(userDefaults.integer(forKey: kAccentColor))
- }
-
- /// Map an integer value to a system color
- static func ColorForSystemColorOffset(_ value: Int) -> NSColor {
- switch value {
- case -1: return NSColor.systemGray
- case 0: return NSColor.systemRed
- case 1: return NSColor.systemOrange
- case 2: return NSColor.systemYellow
- case 3: return NSColor.systemGreen
- case 4: return NSColor.systemBlue
- case 5: return NSColor.systemPurple
- case 6: return NSColor.systemPink
- default: return DefaultColor()
- }
- }
-
- static func DefaultColor() -> NSColor {
- if #available(OSX 11.0, *) {
- return NSColor.systemGray
- }
- else {
- return NSColor.systemBlue
- }
- }
-}
diff --git a/Sources/DSFFloatLabelledTextField/Info.plist b/Sources/DSFFloatLabelledTextField/Info.plist
deleted file mode 100644
index f49eb3e..0000000
--- a/Sources/DSFFloatLabelledTextField/Info.plist
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- FMWK
- CFBundleShortVersionString
- $(MARKETING_VERSION)
- CFBundleVersion
- $(CURRENT_PROJECT_VERSION)
- NSHumanReadableCopyright
- Copyright © 2020 Darren Ford. All rights reserved.
-
-
diff --git a/Sources/DSFFloatLabelledTextField/private/utils.swift b/Sources/DSFFloatLabelledTextField/private/utils.swift
new file mode 100644
index 0000000..5f15d40
--- /dev/null
+++ b/Sources/DSFFloatLabelledTextField/private/utils.swift
@@ -0,0 +1,46 @@
+//
+// utils.swift
+//
+// Copyright © 2023 Darren Ford. All rights reserved.
+//
+// MIT license
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+
+import Foundation
+import AppKit
+
+protocol DSFFloatLabelledTextFieldCellProtocol {
+ var topOffset: CGFloat { get set }
+}
+
+extension NSColor {
+ /// A backwards compatible `controlAccentColor`
+ @inlinable static var simulatedAccentColor: NSColor {
+ if #available(macOS 10.14, *) {
+ // macOS 10.14 and above have a dedicated static NSColor
+ return NSColor.controlAccentColor
+ }
+ else {
+ // Just use the menu highlight color - there's no concept of 'accent' color pre 10.14
+ return NSColor.selectedMenuItemColor
+ }
+ }
+}