Repository navigation
feat(button): implement button styles and interactions #1138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
c630740
feat(button): update button style API and configuration
Kyle-Ye b4948dc
feat(button): update button role API
Kyle-Ye bd5384b
feat(button): update primitive button style API
Kyle-Ye 0cbc7eb
feat(button): add wrapped style and body resolution
Kyle-Ye cea7f50
feat(button): implement button border shapes
Kyle-Ye ec9a94f
feat(app-intent): implement action execution
Kyle-Ye 5579d21
feat(button): implement plain button style
Kyle-Ye 6264e02
feat(button): implement default rendering mode
Kyle-Ye 5d4710c
feat(button): implement borderless button style
Kyle-Ye aa7e266
feat(button): add bordered button specs
Kyle-Ye f85fae1
feat(button): implement AppKit button style
Kyle-Ye f86b4c0
feat(toggle): implement button toggle style
Kyle-Ye 537707d
feat(button): implement widget bordered styles
Kyle-Ye f3c3ded
feat(button): implement bordered prominent style
Kyle-Ye 006c18f
feat(button): implement bordered button style
Kyle-Ye fcc5889
feat(button): implement default button style
Kyle-Ye 211fed8
feat(button): update platform bordered button style
Kyle-Ye c9a88d5
feat(button): implement button repeat behavior
Kyle-Ye 71951a6
feat(button): implement button APIs
Kyle-Ye 2a6df4c
feat(gesture): add StaticIf gesture support
Kyle-Ye 59f9421
build(deps): use Compute 0.6.0-bugfix.1
Kyle-Ye b815669
fix(accessibility): build large content view preferences
Kyle-Ye ba75c7f
feat(button): add platform item selection support
Kyle-Ye 89f74e6
feat(button): implement wrapped style interactions
Kyle-Ye 0207857
feat(gesture): implement button gestures
Kyle-Ye ef3a414
feat(gesture): add pressable gesture callbacks
Kyle-Ye b6fe750
build(deps): update DarwinPrivateFrameworks and OpenRenderBox
Kyle-Ye f1fa904
build(deps): update DarwinPrivateFrameworks and OpenRenderBox
Kyle-Ye 5b5e46d
feat(text): implement keyed text rendering
Kyle-Ye 28915da
test(button): add shared example and interaction tests
Kyle-Ye 33e93ed
fix(button): guard native styles with canImport(Darwin)
Kyle-Ye 686fee0
fix(button): read content style through the AppKit host
Kyle-Ye 648dbf6
fix(button): install action environments and preserve fonts
Kyle-Ye File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // | ||
| // ButtonExample.swift | ||
| // Shared | ||
|
|
||
| #if OPENSWIFTUI | ||
| import OpenSwiftUI | ||
| #else | ||
| import SwiftUI | ||
| #endif | ||
|
|
||
| struct ButtonExample: View { | ||
| var onPress: (Int) -> Void = { _ in } | ||
|
|
||
| @State private var count = 0 | ||
|
|
||
| var body: some View { | ||
| Button { | ||
| count += 1 | ||
| onPress(count) | ||
| } label: { | ||
| Text("Count: \(count)") | ||
| .frame(minWidth: 120, minHeight: 44) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #Preview { | ||
| ButtonExample() | ||
| } |
54 changes: 54 additions & 0 deletions
54
Example/Tests/OpenSwiftUIInteractionTests/View/ButtonInteractionTests.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| // | ||
| // ButtonInteractionTests.swift | ||
| // OpenSwiftUIInteractionTests | ||
|
|
||
| #if OPENSWIFTUI | ||
| import OpenSwiftUI | ||
| #else | ||
| import SwiftUI | ||
| #endif | ||
| import SnapshotTesting | ||
| import Testing | ||
| @testable import TestingHost | ||
|
|
||
| @MainActor | ||
| @Suite(.serialized, .tags(.interaction), .snapshots(record: .never, diffTool: diffTool)) | ||
| struct ButtonInteractionTests { | ||
| @Test | ||
| func actionUpdatesCount() async throws { | ||
| var counts: [Int] = [] | ||
| let content = ButtonExample { counts.append($0) } | ||
|
|
||
| try await withInteractionTestHost(of: content) { host in | ||
| #expect(counts.isEmpty) | ||
| try await host.assertSnapshot(named: "initial") | ||
|
|
||
| for count in 1...2 { | ||
| try await host.tap() | ||
| try await host.waitUntil(counts.count >= count) | ||
| // Capture the idle appearance after the button's release animation. | ||
| try await Task.sleep(for: .milliseconds(600)) | ||
| try await host.assertSnapshot(named: "tap-\(count)") | ||
| #expect(counts == Array(1...count)) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| func disabledButtonDoesNotRunAction() async throws { | ||
| var counts: [Int] = [] | ||
| let content = ButtonExample { counts.append($0) } | ||
| .disabled(true) | ||
|
|
||
| try await withInteractionTestHost(of: content) { host in | ||
| try await host.assertSnapshot(named: "initial") | ||
|
|
||
| for count in 1...2 { | ||
| try await host.tap() | ||
| try await Task.sleep(for: .milliseconds(600)) | ||
| try await host.assertSnapshot(named: "tap-\(count)") | ||
| #expect(counts.isEmpty) | ||
| } | ||
| } | ||
| } | ||
| } |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| // | ||
| // NSButton_Private.h | ||
| // OpenSwiftUI_SPI | ||
| // | ||
| // Audited for macOS 15.5 | ||
|
|
||
| #ifndef NSButton_Private_h | ||
| #define NSButton_Private_h | ||
|
|
||
| #include "OpenSwiftUIBase.h" | ||
|
|
||
| #if __has_include(<AppKit/AppKit.h>) | ||
| #include <AppKit/AppKit.h> | ||
|
|
||
| OPENSWIFTUI_ASSUME_NONNULL_BEGIN | ||
|
|
||
| @interface NSControl (OpenSwiftUI_SPI) | ||
| - (void)addTarget:(id)target action:(SEL)action forControlEvents:(unsigned long long)events; | ||
| - (void)removeTarget:(id)target action:(SEL)action forControlEvents:(unsigned long long)events; | ||
| @end | ||
|
|
||
| @interface NSButton (OpenSwiftUI_SPI) | ||
| @property (nullable, strong) NSView *contentView; | ||
| @property NSInteger toolbarAppearance; | ||
| - (int)effectiveVibrancyBlendModeForAppearance:(NSAppearance *)appearance; | ||
| - (void)_setUsesCautionaryAppearanceWhenActionIsDestructive:(BOOL)destructive; | ||
| - (BOOL)_getIntrinsicArtworkSize:(CGSize *)size | ||
| alignmentRectInsets:(NSEdgeInsets *)alignmentInsets | ||
| idealContentInsets:(NSEdgeInsets *)contentInsets | ||
| maxContentInsets:(nullable NSEdgeInsets *)maxContentInsets; | ||
| @end | ||
|
|
||
| OPENSWIFTUI_ASSUME_NONNULL_END | ||
| #endif | ||
|
|
||
| #endif /* NSButton_Private_h */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.