@momo-kits/native-kits 0.163.1-beta.15-debug → 0.163.1-beta.16-debug
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +2 -1
- package/compose/build.gradle.kts +1 -1
- package/compose/compose.podspec +1 -1
- package/gradle.properties +1 -1
- package/ios/Button/Button.swift +14 -20
- package/ios/native-kits.podspec +1 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +211 -66
- package/package.json +1 -1
|
@@ -78,7 +78,8 @@
|
|
|
78
78
|
"Bash(xcodebuild -workspace MoMoPlatform.xcworkspace -list)",
|
|
79
79
|
"Bash(git --no-pager diff --stat ios/Application/Localize.swift ios/Application/Navigation/NavigationContainer.swift ios/Popup/PopupDisplay.swift ios/Popup/PopupNotify.swift ios/Template/TrustBanner/TrustBanner.swift)",
|
|
80
80
|
"Bash(git rm *)",
|
|
81
|
-
"Bash(echo \"EXIT=$?\")"
|
|
81
|
+
"Bash(echo \"EXIT=$?\")",
|
|
82
|
+
"Bash(git -C /Users/sophia/Workspace/momo/momo-native-kits diff sample/iosApp/iosApp/Demo/ButtonDemo.swift)"
|
|
82
83
|
]
|
|
83
84
|
}
|
|
84
85
|
}
|
package/compose/build.gradle.kts
CHANGED
package/compose/compose.podspec
CHANGED
package/gradle.properties
CHANGED
package/ios/Button/Button.swift
CHANGED
|
@@ -281,25 +281,19 @@ private struct ButtonPressFeedbackStyle: ButtonStyle {
|
|
|
281
281
|
func makeBody(configuration: Configuration) -> some View {
|
|
282
282
|
let pressed = configuration.isPressed && isEnabled
|
|
283
283
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
// unconstrained in a ZStack inside a non-height-constraining container
|
|
299
|
-
// (e.g. a footer VStack) it can report an oversized ideal height and
|
|
300
|
-
// stretch the button — and its container — far taller than intended.
|
|
301
|
-
.frame(height: height)
|
|
302
|
-
.clipShape(RoundedRectangle(cornerRadius: radius))
|
|
303
|
-
.animation(.easeInOut(duration: 0.1), value: pressed)
|
|
284
|
+
configuration.label
|
|
285
|
+
.opacity(pressed ? 0.5 : 1)
|
|
286
|
+
.background(
|
|
287
|
+
RoundedRectangle(cornerRadius: radius)
|
|
288
|
+
.fill(background)
|
|
289
|
+
.overlay(
|
|
290
|
+
RoundedRectangle(cornerRadius: radius)
|
|
291
|
+
.strokeBorder(border ?? .clear, lineWidth: border != nil ? borderWidth : 0)
|
|
292
|
+
)
|
|
293
|
+
.padding(.horizontal, pressed ? 2 : 0)
|
|
294
|
+
)
|
|
295
|
+
.frame(height: height)
|
|
296
|
+
.clipShape(RoundedRectangle(cornerRadius: radius))
|
|
297
|
+
.animation(.easeInOut(duration: 0.1), value: pressed)
|
|
304
298
|
}
|
|
305
299
|
}
|
package/ios/native-kits.podspec
CHANGED
|
@@ -1,100 +1,245 @@
|
|
|
1
1
|
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
2
|
+
// ButtonDemo.swift
|
|
3
|
+
// MoMoUIKitsDemo
|
|
4
4
|
//
|
|
5
|
-
//
|
|
5
|
+
// SwiftUI port of the Compose demo `sample/shared/.../screens/ButtonUsage.kt`:
|
|
6
|
+
// Preview tab mirrors `PreviewButton`, Playground tab mirrors `PlaygroundButton`.
|
|
6
7
|
//
|
|
7
8
|
|
|
8
9
|
import Foundation
|
|
9
|
-
import Lottie
|
|
10
10
|
import MoMoUIKits
|
|
11
11
|
import SwiftUI
|
|
12
12
|
|
|
13
|
+
// Mirror the option lists in Compose `DemoScreen.kt`.
|
|
14
|
+
private let buttonTypeList: [(key: String, value: ButtonType)] = [
|
|
15
|
+
("primary", .primary),
|
|
16
|
+
("secondary", .secondary),
|
|
17
|
+
("tonal", .tonal),
|
|
18
|
+
("outline", .outline),
|
|
19
|
+
("danger", .danger),
|
|
20
|
+
("text", .text),
|
|
21
|
+
("disabled", .disabled),
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
private let sizeList: [(key: String, value: ButtonSize)] = [
|
|
25
|
+
("large", .large),
|
|
26
|
+
("medium", .medium),
|
|
27
|
+
("small", .small),
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
// Subset of the Compose `Icons` map — names resolved via `Icon(source:)` / icon.json.
|
|
31
|
+
private let iconOptionList: [String] = [
|
|
32
|
+
"none",
|
|
33
|
+
"arrow_arrow-back",
|
|
34
|
+
"arrow_arrow-next",
|
|
35
|
+
"Phonebook",
|
|
36
|
+
]
|
|
37
|
+
|
|
13
38
|
// MARK: - ButtonDemo
|
|
14
39
|
|
|
15
40
|
struct ButtonDemo: View {
|
|
16
|
-
|
|
41
|
+
@State private var tab = 0
|
|
17
42
|
|
|
18
43
|
var body: some View {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
VStack(spacing: 0) {
|
|
45
|
+
// Stand-in for Compose `DemoScreen`'s Preview/Playground bottom tabs.
|
|
46
|
+
Picker("", selection: $tab) {
|
|
47
|
+
Text("Preview").tag(0)
|
|
48
|
+
Text("Playground").tag(1)
|
|
49
|
+
}
|
|
50
|
+
.pickerStyle(.segmented)
|
|
51
|
+
.padding(.horizontal, 12)
|
|
52
|
+
.padding(.top, 8)
|
|
53
|
+
|
|
54
|
+
if tab == 0 {
|
|
55
|
+
PreviewButton()
|
|
56
|
+
} else {
|
|
57
|
+
PlaygroundButton()
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
28
62
|
|
|
29
|
-
|
|
30
|
-
Button(title: "Button", action: onPress, type: .danger,
|
|
31
|
-
iconLeft: AnyView(Image(systemName: "checkmark.circle")))
|
|
32
|
-
Button(title: "Button", action: onPress, type: .danger, size: .medium)
|
|
33
|
-
Button(title: "Button", action: onPress, type: .danger, size: .small)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
Group {
|
|
37
|
-
Button(title: "Button", action: onPress, type: .danger, iconLeft: AnyView(Image(systemName: "checkmark.circle")), isFull: false)
|
|
38
|
-
Button(title: "Button", action: onPress, type: .danger, size: .medium, isFull: false)
|
|
39
|
-
Button(title: "Button", action: onPress, type: .danger, size: .small, isFull: false)
|
|
40
|
-
}
|
|
63
|
+
// MARK: - PreviewButton
|
|
41
64
|
|
|
65
|
+
private struct PreviewButton: View {
|
|
66
|
+
private let url = "https://static-00.iconduck.com/assets.00/external-link-icon-512x512-h2zzryfc.png"
|
|
42
67
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
var body: some View {
|
|
69
|
+
ScrollView {
|
|
70
|
+
VStack(spacing: 0) {
|
|
71
|
+
ButtonSectionBox(title: "Title") {
|
|
72
|
+
Button(title: "Open", action: {})
|
|
47
73
|
}
|
|
48
74
|
|
|
49
|
-
|
|
50
|
-
Button(title: "
|
|
51
|
-
|
|
52
|
-
Button(title: "
|
|
53
|
-
|
|
75
|
+
ButtonSectionBox(title: "Type") {
|
|
76
|
+
Button(title: "PRIMARY", action: {}, type: .primary)
|
|
77
|
+
Button(title: "DANGER", action: {}, type: .danger)
|
|
78
|
+
Button(title: "SECONDARY", action: {}, type: .secondary)
|
|
79
|
+
Button(title: "TONAL", action: {}, type: .tonal)
|
|
80
|
+
Button(title: "OUTLINE", action: {}, type: .outline)
|
|
81
|
+
Button(title: "TEXT", action: {}, type: .text)
|
|
82
|
+
Button(title: "DISABLED", action: {}, type: .disabled)
|
|
54
83
|
}
|
|
55
84
|
|
|
56
|
-
|
|
57
|
-
Button(title: "
|
|
58
|
-
Button(title: "
|
|
59
|
-
Button(title: "
|
|
85
|
+
ButtonSectionBox(title: "Size") {
|
|
86
|
+
Button(title: "LARGE", action: {}, size: .large)
|
|
87
|
+
Button(title: "MEDIUM", action: {}, size: .medium)
|
|
88
|
+
Button(title: "SMALL", action: {}, size: .small)
|
|
60
89
|
}
|
|
61
90
|
|
|
62
|
-
|
|
63
|
-
Button(title: "
|
|
64
|
-
Button(title: "
|
|
65
|
-
Button(title: "
|
|
91
|
+
ButtonSectionBox(title: "Loading") {
|
|
92
|
+
Button(title: "PRIMARY", action: {}, type: .primary, loading: true)
|
|
93
|
+
Button(title: "DANGER", action: {}, type: .danger, loading: true)
|
|
94
|
+
Button(title: "SECONDARY", action: {}, type: .secondary, loading: true)
|
|
95
|
+
Button(title: "TONAL", action: {}, type: .tonal, loading: true)
|
|
96
|
+
Button(title: "OUTLINE", action: {}, type: .outline, loading: true)
|
|
97
|
+
Button(title: "TEXT", action: {}, type: .text, loading: true)
|
|
98
|
+
Button(title: "DISABLED", action: {}, type: .disabled, loading: true)
|
|
66
99
|
}
|
|
67
100
|
|
|
68
|
-
|
|
69
|
-
Button(title: "
|
|
70
|
-
Button(title: "Button", action: onPress, type: .outline, size: .medium)
|
|
71
|
-
Button(title: "Button", action: onPress, type: .outline, size: .small)
|
|
101
|
+
ButtonSectionBox(title: "Icon Right") {
|
|
102
|
+
Button(title: "Icon", action: {}, iconRight: AnyView(ImageView(url, loading: false)))
|
|
72
103
|
}
|
|
73
104
|
|
|
74
|
-
|
|
75
|
-
Button(title: "
|
|
76
|
-
Button(title: "Button", action: onPress, type: .disabled, size: .medium)
|
|
77
|
-
Button(title: "Button", action: onPress, type: .disabled, size: .small)
|
|
105
|
+
ButtonSectionBox(title: "Icon Left") {
|
|
106
|
+
Button(title: "Icon", action: {}, iconLeft: AnyView(ImageView(url, loading: false)))
|
|
78
107
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// MARK: - PlaygroundButton
|
|
114
|
+
|
|
115
|
+
private struct PlaygroundButton: View {
|
|
116
|
+
@State private var title: String = "Button"
|
|
117
|
+
@State private var type: AnyHashable = "primary"
|
|
118
|
+
@State private var size: AnyHashable = "large"
|
|
119
|
+
@State private var iconRight: AnyHashable = "none"
|
|
120
|
+
@State private var iconLeft: AnyHashable = "none"
|
|
121
|
+
@State private var full = true
|
|
122
|
+
@State private var loading = false
|
|
123
|
+
@State private var useTintColor = true
|
|
124
|
+
|
|
125
|
+
var body: some View {
|
|
126
|
+
VStack(spacing: 0) {
|
|
127
|
+
ButtonSectionBox(title: "Component", alignment: .leading) {
|
|
128
|
+
Button(
|
|
129
|
+
title: title,
|
|
130
|
+
action: {},
|
|
131
|
+
type: buttonTypeList.first { $0.key == type }?.value ?? .primary,
|
|
132
|
+
size: sizeList.first { $0.key == size }?.value ?? .large,
|
|
133
|
+
iconLeft: iconView(iconLeft),
|
|
134
|
+
iconRight: iconView(iconRight),
|
|
135
|
+
isFull: full,
|
|
136
|
+
loading: loading,
|
|
137
|
+
useTintColor: useTintColor
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
ScrollView {
|
|
142
|
+
ButtonSectionBox(title: "Props", alignment: .leading) {
|
|
143
|
+
PropTitle("Children")
|
|
144
|
+
Input(text: $title)
|
|
145
|
+
PropGap()
|
|
146
|
+
|
|
147
|
+
PropTitle("Type")
|
|
148
|
+
RadioGroup(options: buttonTypeList.map(\.key), selection: $type)
|
|
149
|
+
PropGap()
|
|
150
|
+
|
|
151
|
+
PropTitle("Size")
|
|
152
|
+
RadioGroup(options: sizeList.map(\.key), selection: $size)
|
|
153
|
+
PropGap()
|
|
154
|
+
|
|
155
|
+
PropTitle("Full")
|
|
156
|
+
Checkbox($full, title: "\(full)")
|
|
157
|
+
PropGap()
|
|
158
|
+
|
|
159
|
+
PropTitle("Iconright")
|
|
160
|
+
RadioGroup(options: iconOptionList, selection: $iconRight)
|
|
161
|
+
PropGap()
|
|
162
|
+
|
|
163
|
+
PropTitle("Iconleft")
|
|
164
|
+
RadioGroup(options: iconOptionList, selection: $iconLeft)
|
|
165
|
+
PropGap()
|
|
166
|
+
|
|
167
|
+
PropTitle("Loading")
|
|
168
|
+
Checkbox($loading, title: "\(loading)")
|
|
169
|
+
PropGap()
|
|
170
|
+
|
|
171
|
+
PropTitle("Usetinecolor")
|
|
172
|
+
Checkbox($useTintColor, title: "\(useTintColor)")
|
|
87
173
|
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
90
176
|
}
|
|
91
177
|
|
|
92
|
-
func
|
|
93
|
-
|
|
178
|
+
private func iconView(_ selection: AnyHashable) -> AnyView? {
|
|
179
|
+
guard let name = selection as? String, name != "none" else { return nil }
|
|
180
|
+
return AnyView(Icon(source: name))
|
|
94
181
|
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// MARK: - Playground helpers
|
|
185
|
+
|
|
186
|
+
private struct PropTitle: View {
|
|
187
|
+
let title: String
|
|
188
|
+
|
|
189
|
+
init(_ title: String) { self.title = title }
|
|
190
|
+
|
|
191
|
+
var body: some View {
|
|
192
|
+
MomoText(title, typography: .headerDefaultBold)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private struct PropGap: View {
|
|
197
|
+
var body: some View {
|
|
198
|
+
Spacer().frame(height: Spacing.L)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private struct RadioGroup: View {
|
|
203
|
+
let options: [String]
|
|
204
|
+
@Binding var selection: AnyHashable
|
|
205
|
+
|
|
206
|
+
var body: some View {
|
|
207
|
+
ForEach(options, id: \.self) { key in
|
|
208
|
+
Radio(value: key, groupValue: $selection, label: key)
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// MARK: - ButtonSectionBox
|
|
214
|
+
|
|
215
|
+
/// Titled rounded-card section container, mirroring Compose's `BasicColumnBox`.
|
|
216
|
+
private struct ButtonSectionBox<Content: View>: View {
|
|
217
|
+
@Environment(\.appTheme) private var theme
|
|
218
|
+
let title: String
|
|
219
|
+
var alignment: HorizontalAlignment = .center
|
|
220
|
+
@ViewBuilder let content: () -> Content
|
|
221
|
+
|
|
222
|
+
var body: some View {
|
|
223
|
+
VStack(alignment: .leading, spacing: 8) {
|
|
224
|
+
if !title.isEmpty {
|
|
225
|
+
MomoText(title, typography: .headerMBold)
|
|
226
|
+
.padding(.top, 8)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
VStack(alignment: alignment, spacing: 8) {
|
|
230
|
+
content()
|
|
231
|
+
}
|
|
232
|
+
.frame(maxWidth: .infinity, alignment: alignment == .leading ? .leading : .center)
|
|
233
|
+
.padding(12)
|
|
234
|
+
.background(theme.colors.background.surface)
|
|
235
|
+
.clipShape(RoundedRectangle(cornerRadius: Radius.M))
|
|
236
|
+
}
|
|
237
|
+
.padding(12)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
95
240
|
|
|
96
|
-
|
|
241
|
+
// MARK: - Preview
|
|
97
242
|
|
|
98
|
-
|
|
99
|
-
|
|
243
|
+
#Preview {
|
|
244
|
+
ButtonDemo()
|
|
100
245
|
}
|