Skip to content

Commit b1a8186

Browse files
committed
Add support for controlSize modifier
A new property for controls like Button or Picker: "controlSize": "regular", // Optional: "mini", "small", "regular", "large", "extraLarge"; defaults to none (system default)
1 parent 630bb9e commit b1a8186

5 files changed

Lines changed: 158 additions & 0 deletions

File tree

ActionUI/Views/View.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"key": "a", // Required: String for KeyEquivalent (single character like "a" or special key like "return", "space", "upArrow")
4040
"modifiers": ["command", "shift"] // Optional: Array of strings for modifiers (e.g., ["command", "shift"]), defaults to ["command"], must contain unique elements
4141
},
42+
"controlSize": "regular", // Optional: "mini", "small", "regular", "large", "extraLarge"; defaults to none (system default)
4243
"disabled": false, // Optional: Boolean to disable user interaction
4344
"accessibilityLabel": "View", // Optional: Accessibility label for VoiceOver
4445
"accessibilityHint": "Base view", // Optional: Accessibility hint for VoiceOver
@@ -506,6 +507,20 @@ struct View: ActionUIViewConstruction {
506507
}
507508
}
508509

510+
// Validate controlSize
511+
if let controlSize = properties["controlSize"] {
512+
if let sizeStr = controlSize as? String {
513+
let validSizes = ["mini", "small", "regular", "large", "extraLarge"]
514+
if !validSizes.contains(sizeStr) {
515+
logger.log("Invalid controlSize '\(sizeStr)'; expected one of \(validSizes), ignoring", .warning)
516+
validatedProperties["controlSize"] = nil
517+
}
518+
} else {
519+
logger.log("Invalid type for controlSize: expected String, got \(type(of: controlSize)), ignoring", .warning)
520+
validatedProperties["controlSize"] = nil
521+
}
522+
}
523+
509524
if let columnWidthAny = properties["navigationSplitViewColumnWidth"] {
510525
var validatedValue: Any? = nil
511526

@@ -665,6 +680,23 @@ struct View: ActionUIViewConstruction {
665680
modifiedView = modifiedView.border(color, width: width)
666681
}
667682

683+
if let controlSize = properties["controlSize"] as? String {
684+
switch controlSize {
685+
case "mini":
686+
modifiedView = modifiedView.controlSize(.mini)
687+
case "small":
688+
modifiedView = modifiedView.controlSize(.small)
689+
case "regular":
690+
modifiedView = modifiedView.controlSize(.regular)
691+
case "large":
692+
modifiedView = modifiedView.controlSize(.large)
693+
case "extraLarge":
694+
modifiedView = modifiedView.controlSize(.extraLarge)
695+
default:
696+
break
697+
}
698+
}
699+
668700
if let shadow = properties["shadow"] as? [String: Any] {
669701
let color = ColorHelper.resolveColor(shadow["color"] as? String) ?? .black
670702
let radius = shadow.cgFloat(forKey: "radius") ?? 0.0

ActionUISwiftTestApp/Resources/Button.json

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,56 @@
9898
}
9999
},
100100

101+
{
102+
"type": "Text",
103+
"properties": {
104+
"text": "controlSize variants",
105+
"font": "headline",
106+
"padding": { "top": 16, "bottom": 4 }
107+
}
108+
},
109+
{
110+
"type": "HStack",
111+
"properties": {
112+
"spacing": 12,
113+
"alignment": "center"
114+
},
115+
"children": [
116+
{
117+
"type": "Button",
118+
"properties": {
119+
"title": "Mini",
120+
"buttonStyle": "bordered",
121+
"controlSize": "mini"
122+
}
123+
},
124+
{
125+
"type": "Button",
126+
"properties": {
127+
"title": "Small",
128+
"buttonStyle": "bordered",
129+
"controlSize": "small"
130+
}
131+
},
132+
{
133+
"type": "Button",
134+
"properties": {
135+
"title": "Regular",
136+
"buttonStyle": "bordered",
137+
"controlSize": "regular"
138+
}
139+
},
140+
{
141+
"type": "Button",
142+
"properties": {
143+
"title": "Large",
144+
"buttonStyle": "bordered",
145+
"controlSize": "large"
146+
}
147+
}
148+
]
149+
},
150+
101151
{
102152
"type": "Text",
103153
"properties": {

ActionUISwiftTestApp/Resources/Picker.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,59 @@
6060
"pickerStyle": "radioGroup",
6161
"horizontalRadioGroupLayout": true
6262
}
63+
},
64+
{
65+
"type": "Text",
66+
"properties": {
67+
"text": "Menu Picker — controlSize variants",
68+
"font": "headline",
69+
"padding": { "top": 16, "bottom": 4 }
70+
}
71+
},
72+
{
73+
"type": "Picker",
74+
"properties": {
75+
"title": "Mini",
76+
"options": ["One", "Two", "Three"],
77+
"pickerStyle": "menu",
78+
"controlSize": "mini"
79+
}
80+
},
81+
{
82+
"type": "Picker",
83+
"properties": {
84+
"title": "Small",
85+
"options": ["One", "Two", "Three"],
86+
"pickerStyle": "menu",
87+
"controlSize": "small"
88+
}
89+
},
90+
{
91+
"type": "Picker",
92+
"properties": {
93+
"title": "Regular",
94+
"options": ["One", "Two", "Three"],
95+
"pickerStyle": "menu",
96+
"controlSize": "regular"
97+
}
98+
},
99+
{
100+
"type": "Picker",
101+
"properties": {
102+
"title": "Large",
103+
"options": ["One", "Two", "Three"],
104+
"pickerStyle": "menu",
105+
"controlSize": "large"
106+
}
107+
},
108+
{
109+
"type": "Picker",
110+
"properties": {
111+
"title": "Extra Large",
112+
"options": ["One", "Two", "Three"],
113+
"pickerStyle": "menu",
114+
"controlSize": "extraLarge"
115+
}
63116
}
64117
]
65118
}

ActionUITests/Views/ViewTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,4 +970,26 @@ final class ViewTests: XCTestCase {
970970
XCTAssertTrue(view is SwiftUI.EmptyView, "buildView should return EmptyView")
971971
XCTAssertNil(validatedProperties["keyboardShortcut"], "keyboardShortcut should be nil for invalid key")
972972
}
973+
974+
// MARK: - controlSize validation
975+
976+
func testValidatePropertiesControlSizeValid() throws {
977+
for size in ["mini", "small", "regular", "large", "extraLarge"] {
978+
let properties: [String: Any] = ["controlSize": size]
979+
let validated = View.validateProperties(properties, logger)
980+
XCTAssertEqual(validated["controlSize"] as? String, size, "controlSize '\(size)' should be valid")
981+
}
982+
}
983+
984+
func testValidatePropertiesControlSizeInvalidValue() throws {
985+
let properties: [String: Any] = ["controlSize": "huge"]
986+
let validated = View.validateProperties(properties, logger)
987+
XCTAssertNil(validated["controlSize"], "Invalid controlSize should be nil")
988+
}
989+
990+
func testValidatePropertiesControlSizeInvalidType() throws {
991+
let properties: [String: Any] = ["controlSize": 42]
992+
let validated = View.validateProperties(properties, logger)
993+
XCTAssertNil(validated["controlSize"], "Non-string controlSize should be nil")
994+
}
973995
}

Documentation/ActionUI-JSON-Specifications.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,7 @@
11381138
"key": "a", // Required: String for KeyEquivalent (single character like "a" or special key like "return", "space", "upArrow")
11391139
"modifiers": ["command", "shift"] // Optional: Array of strings for modifiers (e.g., ["command", "shift"]), defaults to ["command"], must contain unique elements
11401140
},
1141+
"controlSize": "regular", // Optional: "mini", "small", "regular", "large", "extraLarge"; no default (system default)
11411142
"disabled": false, // Optional: Boolean to disable user interaction
11421143
"accessibilityLabel": "View", // Optional: Accessibility label for VoiceOver
11431144
"accessibilityHint": "Base view", // Optional: Accessibility hint for VoiceOver

0 commit comments

Comments
 (0)