@momo-kits/native-kits 0.162.30-debug → 0.162.31-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.md +19 -0
- package/compose/build.gradle.kts +1 -1
- package/compose/compose.podspec +1 -1
- package/gradle.properties +1 -1
- package/ios/Application/ApplicationEnvironment.swift +14 -6
- package/ios/Application/LanguageSource.swift +93 -0
- package/ios/Application/Localize.swift +73 -4
- package/ios/Application/LocalizeModifier.swift +30 -0
- package/ios/Application/Navigation/NavigationContainer.swift +28 -18
- package/ios/Application/Navigation/Navigator.swift +121 -53
- package/ios/Application/Navigation/NavigatorManager.swift +49 -0
- package/ios/Application/Navigation/component/NavigationFooter.swift +90 -0
- package/ios/Application/StackScreen.swift +19 -28
- package/ios/Badge/Badge.swift +2 -1
- package/ios/Badge/BadgeRibbon.swift +6 -2
- package/ios/Button/Button.swift +41 -61
- package/ios/Chip/Chip.swift +6 -5
- package/ios/Icon/Icon.swift +13 -4
- package/ios/Input/ErrorView.swift +2 -1
- package/ios/Input/Input.swift +9 -2
- package/ios/Input/InputPhoneNumber.swift +2 -1
- package/ios/Input/InputSearch.swift +3 -2
- package/ios/Input/InputTextArea.swift +6 -1
- package/ios/InputMoney/InputMoney.swift +5 -2
- package/ios/InputOTP/InputOTP.swift +2 -1
- package/ios/Layout/GridContext.swift +30 -0
- package/ios/Layout/Item.swift +42 -0
- package/ios/Layout/Section.swift +134 -0
- package/ios/Popup/PopupNotify.swift +2 -1
- package/ios/ProgressInfo/ProgressInfo.swift +4 -3
- package/ios/Rating/Rating.swift +2 -1
- package/ios/Stepper/Stepper.swift +2 -1
- package/ios/SuggestAction/SuggestAction.swift +3 -2
- package/ios/Tag/Tag.swift +2 -1
- package/ios/Template/TrustBanner/TrustBanner.swift +4 -2
- package/ios/Title/Title.swift +3 -2
- package/ios/Tooltip/Tooltip.swift +2 -1
- package/ios/Typography/FontScale.swift +103 -0
- package/ios/Typography/FontScaleStore.swift +52 -13
- package/ios/Typography/Text.swift +12 -29
- package/ios/Typography/Typography.swift +66 -86
- package/ios/native-kits.podspec +2 -1
- package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/AvatarDemo.swift +87 -73
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/BadgeDemo.swift +55 -249
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ButtonDemo.swift +90 -82
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CarouselDemo.swift +74 -104
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CheckboxDemo.swift +47 -50
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ChipDemo.swift +63 -7
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/CollapseDemo.swift +90 -81
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DateTimePickerDemo.swift +73 -97
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DemoScreen.swift +420 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DividerDemo.swift +46 -4
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +54 -57
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconButtonDemo.swift +80 -45
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IconDemo.swift +81 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ImageDemo.swift +49 -62
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InformationDemo.swift +66 -116
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDemo.swift +104 -98
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputDropDownDemo.swift +76 -118
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputMoneyDemo.swift +73 -86
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputOTPDemo.swift +69 -54
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputPhoneNumberDemo.swift +74 -54
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputSearchDemo.swift +73 -20
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/InputTextAreaDemo.swift +68 -38
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LoaderDemo.swift +55 -52
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/LocalizeDemo.swift +51 -4
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +14 -2
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PaginationDemo.swift +47 -51
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PlaygroundData.swift +76 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupNotifyDemo.swift +67 -93
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/PopupPromotionDemo.swift +34 -43
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ProgressInfoDemo.swift +83 -71
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RadioDemo.swift +55 -23
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/RatingDemo.swift +58 -46
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SectionDemo.swift +83 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SkeletonDemo.swift +41 -12
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SliderDemo.swift +67 -127
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SnackBarDemo.swift +54 -110
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepperDemo.swift +69 -79
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/StepsDemo.swift +78 -58
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SuggestActionDemo.swift +76 -65
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwipeDemo.swift +82 -127
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/SwitchDemo.swift +44 -19
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TabViewDemo.swift +92 -168
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TagDemo.swift +79 -27
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ThemeDemo.swift +0 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TitleDemo.swift +87 -92
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TooltipDemo.swift +94 -163
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/TypographyDemo.swift +70 -70
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/UploaderDemo.swift +68 -114
- package/ios-demo/Sources/MoMoUIKitsDemo/SwiftUIDemoBrowserView.swift +3 -1
- package/package.json +2 -2
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
//
|
|
2
|
+
// DemoScreen.swift
|
|
3
|
+
// Example
|
|
4
|
+
//
|
|
5
|
+
// SwiftUI port of Compose's `sample/shared/.../screens/DemoScreen.kt`: the demo
|
|
6
|
+
// shell every component uses. `DemoScreen(preview:playground:)` renders a two-tab
|
|
7
|
+
// `BottomTab` — a static "Preview" showcase and an interactive, data-driven
|
|
8
|
+
// "Playground" props editor (BasicColumnBox / PlaygroundParams / PlaygroundView /
|
|
9
|
+
// PlaygroundTab). Must be pushed inside the `NavigationContainer` (BottomTab reads
|
|
10
|
+
// the Navigator) with `headerType: .none, scrollable: false`.
|
|
11
|
+
//
|
|
12
|
+
|
|
13
|
+
import MoMoUIKits
|
|
14
|
+
import SwiftUI
|
|
15
|
+
|
|
16
|
+
// MARK: - DemoScreen shell
|
|
17
|
+
|
|
18
|
+
@available(iOS 16.0, *)
|
|
19
|
+
struct DemoScreen<Preview: View, Playground: View>: View {
|
|
20
|
+
@ViewBuilder let preview: () -> Preview
|
|
21
|
+
@ViewBuilder let playground: () -> Playground
|
|
22
|
+
|
|
23
|
+
var body: some View {
|
|
24
|
+
BottomTab(items: [
|
|
25
|
+
BottomTabItem(
|
|
26
|
+
name: "Preview",
|
|
27
|
+
label: "Preview",
|
|
28
|
+
icon: "security_eye_open",
|
|
29
|
+
options: NavigationOptions(headerTitle: .default("Preview"), scrollable: true),
|
|
30
|
+
// StackScreen provides the scroll when scrollable == true.
|
|
31
|
+
screen: {
|
|
32
|
+
VStack(alignment: .leading, spacing: 0) { preview() }
|
|
33
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
34
|
+
}
|
|
35
|
+
),
|
|
36
|
+
BottomTabItem(
|
|
37
|
+
name: "Playground",
|
|
38
|
+
label: "Playground",
|
|
39
|
+
icon: "24_basic_chart",
|
|
40
|
+
// Playground owns its own scroll (Props list), so disable the outer one.
|
|
41
|
+
options: NavigationOptions(headerTitle: .default("Playground"), scrollable: false),
|
|
42
|
+
screen: { playground() }
|
|
43
|
+
),
|
|
44
|
+
])
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// MARK: - BasicColumnBox (titled surface card)
|
|
49
|
+
|
|
50
|
+
struct BasicColumnBox<Content: View>: View {
|
|
51
|
+
let title: String
|
|
52
|
+
let alignment: HorizontalAlignment
|
|
53
|
+
let background: Color?
|
|
54
|
+
@ViewBuilder let content: () -> Content
|
|
55
|
+
|
|
56
|
+
init(
|
|
57
|
+
_ title: String = "",
|
|
58
|
+
alignment: HorizontalAlignment = .center,
|
|
59
|
+
background: Color? = nil,
|
|
60
|
+
@ViewBuilder content: @escaping () -> Content
|
|
61
|
+
) {
|
|
62
|
+
self.title = title
|
|
63
|
+
self.alignment = alignment
|
|
64
|
+
self.background = background
|
|
65
|
+
self.content = content
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var body: some View {
|
|
69
|
+
VStack(alignment: .leading, spacing: Spacing.S) {
|
|
70
|
+
if !title.isEmpty {
|
|
71
|
+
MomoText(title, typography: .headerMBold)
|
|
72
|
+
.padding(.top, Spacing.S)
|
|
73
|
+
}
|
|
74
|
+
VStack(alignment: alignment, spacing: Spacing.S) {
|
|
75
|
+
content()
|
|
76
|
+
}
|
|
77
|
+
.frame(maxWidth: .infinity, alignment: alignmentFrame)
|
|
78
|
+
.padding(Spacing.M)
|
|
79
|
+
.background(
|
|
80
|
+
RoundedRectangle(cornerRadius: Radius.M)
|
|
81
|
+
.fill(background ?? defaultTheme.colors.background.surface)
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
.padding(Spacing.M)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private var alignmentFrame: Alignment {
|
|
88
|
+
switch alignment {
|
|
89
|
+
case .leading: return .leading
|
|
90
|
+
case .trailing: return .trailing
|
|
91
|
+
default: return .center
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// MARK: - Playground model (mirrors PlaygroundParams / PlaygroundDataType)
|
|
97
|
+
|
|
98
|
+
enum PlaygroundDataType {
|
|
99
|
+
case string, number, option, color, radio, checkbox, slider
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// One selectable entry for OPTION / COLOR / RADIO params. Replaces Compose's
|
|
103
|
+
/// `Map<String, Any>` + `Map.Entry`. Equality is by `key`.
|
|
104
|
+
struct PlaygroundOption: Identifiable, Hashable {
|
|
105
|
+
var id: String { key }
|
|
106
|
+
let key: String
|
|
107
|
+
let value: AnyHashable
|
|
108
|
+
|
|
109
|
+
init(_ key: String, _ value: AnyHashable) {
|
|
110
|
+
self.key = key
|
|
111
|
+
self.value = value
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static func == (lhs: PlaygroundOption, rhs: PlaygroundOption) -> Bool { lhs.key == rhs.key }
|
|
115
|
+
func hash(into hasher: inout Hasher) { hasher.combine(key) }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// A single editable prop row. Build with the per-type factory methods so the
|
|
119
|
+
/// call site stays type-safe (`.radio("Type", buttonTypeList, $type)`).
|
|
120
|
+
struct PlaygroundParams: Identifiable {
|
|
121
|
+
// Identity is the title, never a fresh UUID: the array is rebuilt on every body
|
|
122
|
+
// pass, so a per-instance id would re-key the ForEach on each keystroke — tearing
|
|
123
|
+
// down the row (an editing TextField loses first responder) and wiping its @State.
|
|
124
|
+
var id: String { title }
|
|
125
|
+
let title: String
|
|
126
|
+
let type: PlaygroundDataType
|
|
127
|
+
let list: [PlaygroundOption]
|
|
128
|
+
let enable: Binding<Bool>
|
|
129
|
+
let required: Bool
|
|
130
|
+
let sliderMin: Double
|
|
131
|
+
let sliderMax: Double
|
|
132
|
+
let sliderStep: Double
|
|
133
|
+
|
|
134
|
+
// Only the binding matching `type` is non-nil.
|
|
135
|
+
let text: Binding<String>?
|
|
136
|
+
let selection: Binding<PlaygroundOption?>?
|
|
137
|
+
let flag: Binding<Bool>?
|
|
138
|
+
let number: Binding<Double>?
|
|
139
|
+
|
|
140
|
+
private init(
|
|
141
|
+
title: String,
|
|
142
|
+
type: PlaygroundDataType,
|
|
143
|
+
list: [PlaygroundOption] = [],
|
|
144
|
+
enable: Binding<Bool> = .constant(true),
|
|
145
|
+
required: Bool = false,
|
|
146
|
+
sliderMin: Double = 0,
|
|
147
|
+
sliderMax: Double = 100,
|
|
148
|
+
sliderStep: Double = 1,
|
|
149
|
+
text: Binding<String>? = nil,
|
|
150
|
+
selection: Binding<PlaygroundOption?>? = nil,
|
|
151
|
+
flag: Binding<Bool>? = nil,
|
|
152
|
+
number: Binding<Double>? = nil
|
|
153
|
+
) {
|
|
154
|
+
self.title = title
|
|
155
|
+
self.type = type
|
|
156
|
+
self.list = list
|
|
157
|
+
self.enable = enable
|
|
158
|
+
self.required = required
|
|
159
|
+
self.sliderMin = sliderMin
|
|
160
|
+
self.sliderMax = sliderMax
|
|
161
|
+
self.sliderStep = sliderStep
|
|
162
|
+
self.text = text
|
|
163
|
+
self.selection = selection
|
|
164
|
+
self.flag = flag
|
|
165
|
+
self.number = number
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static func string(_ title: String, _ text: Binding<String>, required: Bool = false, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
169
|
+
PlaygroundParams(title: title, type: .string, enable: enable, required: required, text: text)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static func number(_ title: String, _ text: Binding<String>, required: Bool = false, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
173
|
+
PlaygroundParams(title: title, type: .number, enable: enable, required: required, text: text)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static func option(_ title: String, _ list: [PlaygroundOption], _ selection: Binding<PlaygroundOption?>, required: Bool = false, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
177
|
+
PlaygroundParams(title: title, type: .option, list: list, enable: enable, required: required, selection: selection)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static func color(_ title: String, _ list: [PlaygroundOption], _ selection: Binding<PlaygroundOption?>, required: Bool = false, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
181
|
+
PlaygroundParams(title: title, type: .color, list: list, enable: enable, required: required, selection: selection)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static func radio(_ title: String, _ list: [PlaygroundOption], _ selection: Binding<PlaygroundOption?>, required: Bool = false, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
185
|
+
PlaygroundParams(title: title, type: .radio, list: list, enable: enable, required: required, selection: selection)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static func checkbox(_ title: String, _ flag: Binding<Bool>, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
189
|
+
PlaygroundParams(title: title, type: .checkbox, enable: enable, flag: flag)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
static func slider(_ title: String, _ number: Binding<Double>, min: Double = 0, max: Double = 100, step: Double = 1, enable: Binding<Bool> = .constant(true)) -> PlaygroundParams {
|
|
193
|
+
PlaygroundParams(title: title, type: .slider, enable: enable, sliderMin: min, sliderMax: max, sliderStep: step, number: number)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// MARK: - PlaygroundTab (live component + scrollable props list)
|
|
198
|
+
|
|
199
|
+
@available(iOS 16.0, *)
|
|
200
|
+
struct PlaygroundTab<Component: View>: View {
|
|
201
|
+
@ViewBuilder let component: () -> Component
|
|
202
|
+
let params: [PlaygroundParams]
|
|
203
|
+
var isHideComponent: Bool = false
|
|
204
|
+
|
|
205
|
+
var body: some View {
|
|
206
|
+
VStack(spacing: 0) {
|
|
207
|
+
if !isHideComponent {
|
|
208
|
+
BasicColumnBox("Component", alignment: .leading) { component() }
|
|
209
|
+
}
|
|
210
|
+
ScrollView {
|
|
211
|
+
BasicColumnBox("Props", alignment: .leading) {
|
|
212
|
+
ForEach(params) { param in
|
|
213
|
+
MomoText(param.title, typography: .headerDefaultBold)
|
|
214
|
+
.opacity(param.enable.wrappedValue ? 1 : 0.4)
|
|
215
|
+
PlaygroundView(param: param)
|
|
216
|
+
Spacer().frame(height: Spacing.L)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// MARK: - PlaygroundView (per-type editor, mirrors PlayGroundView.kt)
|
|
225
|
+
|
|
226
|
+
@available(iOS 16.0, *)
|
|
227
|
+
struct PlaygroundView: View {
|
|
228
|
+
let param: PlaygroundParams
|
|
229
|
+
@EnvironmentObject private var navigator: Navigator
|
|
230
|
+
@State private var isUndefined = false
|
|
231
|
+
@State private var initialSelection: PlaygroundOption?
|
|
232
|
+
@State private var didCapture = false
|
|
233
|
+
|
|
234
|
+
var body: some View {
|
|
235
|
+
editor
|
|
236
|
+
.opacity(param.enable.wrappedValue ? 1 : 0.4)
|
|
237
|
+
.disabled(!param.enable.wrappedValue)
|
|
238
|
+
.allowsHitTesting(param.enable.wrappedValue)
|
|
239
|
+
.onAppear {
|
|
240
|
+
if !didCapture {
|
|
241
|
+
initialSelection = param.selection?.wrappedValue
|
|
242
|
+
didCapture = true
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@ViewBuilder
|
|
248
|
+
private var editor: some View {
|
|
249
|
+
switch param.type {
|
|
250
|
+
case .string, .number: stringEditor
|
|
251
|
+
case .option, .color: optionEditor
|
|
252
|
+
case .radio: radioEditor
|
|
253
|
+
case .checkbox: checkboxEditor
|
|
254
|
+
case .slider: sliderEditor
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// STRING / NUMBER
|
|
259
|
+
@ViewBuilder
|
|
260
|
+
private var stringEditor: some View {
|
|
261
|
+
if let text = param.text {
|
|
262
|
+
Input(
|
|
263
|
+
text: text,
|
|
264
|
+
keyboardType: param.type == .number ? .numberPad : .default,
|
|
265
|
+
onChangeText: { _ in isUndefined = false }
|
|
266
|
+
)
|
|
267
|
+
if !param.required {
|
|
268
|
+
undefinedCheckbox { text.wrappedValue = "" }
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// OPTION / COLOR
|
|
274
|
+
@ViewBuilder
|
|
275
|
+
private var optionEditor: some View {
|
|
276
|
+
if let selection = param.selection {
|
|
277
|
+
HStack {
|
|
278
|
+
Spacer().frame(width: 30)
|
|
279
|
+
MomoText(selection.wrappedValue?.key ?? "", typography: .bodyDefaultRegular)
|
|
280
|
+
Spacer()
|
|
281
|
+
Icon(source: "arrow_chevron_down", size: 20)
|
|
282
|
+
.padding(.trailing, Spacing.XS)
|
|
283
|
+
}
|
|
284
|
+
.frame(height: 40)
|
|
285
|
+
.overlay(
|
|
286
|
+
RoundedRectangle(cornerRadius: Radius.XS)
|
|
287
|
+
.stroke(defaultTheme.colors.border.default, lineWidth: 1)
|
|
288
|
+
)
|
|
289
|
+
.contentShape(Rectangle())
|
|
290
|
+
.onTapGesture { openPicker(selection: selection) }
|
|
291
|
+
|
|
292
|
+
if !param.required {
|
|
293
|
+
// An OPTION/COLOR prop is genuinely nullable, so "undefined" clears it
|
|
294
|
+
// outright rather than restoring the seeded default.
|
|
295
|
+
undefinedCheckbox { selection.wrappedValue = nil }
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// RADIO
|
|
301
|
+
@ViewBuilder
|
|
302
|
+
private var radioEditor: some View {
|
|
303
|
+
if let selection = param.selection {
|
|
304
|
+
ForEach(param.list) { option in
|
|
305
|
+
Radio(
|
|
306
|
+
value: option.key,
|
|
307
|
+
groupValue: Binding(
|
|
308
|
+
get: { AnyHashable(selection.wrappedValue?.key ?? "") },
|
|
309
|
+
set: { _ in }
|
|
310
|
+
),
|
|
311
|
+
onChange: { isUndefined = false; selection.wrappedValue = option },
|
|
312
|
+
label: option.key
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
if !param.required {
|
|
316
|
+
undefinedCheckbox { selection.wrappedValue = initialSelection }
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// CHECKBOX
|
|
322
|
+
@ViewBuilder
|
|
323
|
+
private var checkboxEditor: some View {
|
|
324
|
+
if let flag = param.flag {
|
|
325
|
+
Checkbox(flag, title: flag.wrappedValue.description)
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// SLIDER
|
|
330
|
+
@ViewBuilder
|
|
331
|
+
private var sliderEditor: some View {
|
|
332
|
+
if let number = param.number {
|
|
333
|
+
MomoText(formatSlider(number.wrappedValue), typography: .headerDefaultBold)
|
|
334
|
+
MomoSlider(
|
|
335
|
+
min: param.sliderMin,
|
|
336
|
+
max: param.sliderMax,
|
|
337
|
+
step: param.sliderStep,
|
|
338
|
+
low: number.wrappedValue,
|
|
339
|
+
disableRange: true,
|
|
340
|
+
onValueChanged: { low, _, _ in number.wrappedValue = low }
|
|
341
|
+
)
|
|
342
|
+
.frame(maxWidth: .infinity)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// "is undefined" toggle for optional params. RADIO restores the value captured on
|
|
347
|
+
// first render (Compose's `remember { data.value }`) since its prop is never null.
|
|
348
|
+
@ViewBuilder
|
|
349
|
+
private func undefinedCheckbox(_ onUndefined: @escaping () -> Void) -> some View {
|
|
350
|
+
Checkbox($isUndefined, onChange: { if $0 { onUndefined() } }, title: "is undefined")
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private func openPicker(selection: Binding<PlaygroundOption?>) {
|
|
354
|
+
let isColor = param.type == .color
|
|
355
|
+
navigator.showBottomSheet({
|
|
356
|
+
PlaygroundOptionPicker(list: param.list, isColor: isColor) { picked in
|
|
357
|
+
isUndefined = false
|
|
358
|
+
selection.wrappedValue = picked
|
|
359
|
+
navigator.hideOverplay()
|
|
360
|
+
}
|
|
361
|
+
}, header: .title("Choose option"))
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private func formatSlider(_ v: Double) -> String {
|
|
365
|
+
v == v.rounded() ? String(Int(v)) : String(format: "%.1f", v)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// MARK: - Option picker (searchable bottom-sheet list)
|
|
370
|
+
|
|
371
|
+
@available(iOS 16.0, *)
|
|
372
|
+
private struct PlaygroundOptionPicker: View {
|
|
373
|
+
let list: [PlaygroundOption]
|
|
374
|
+
let isColor: Bool
|
|
375
|
+
let onSelect: (PlaygroundOption) -> Void
|
|
376
|
+
|
|
377
|
+
@State private var query = ""
|
|
378
|
+
|
|
379
|
+
private var filtered: [PlaygroundOption] {
|
|
380
|
+
query.isEmpty ? list : list.filter { $0.key.localizedCaseInsensitiveContains(query) }
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
var body: some View {
|
|
384
|
+
VStack(spacing: 0) {
|
|
385
|
+
InputSearch(props: InputSearchProps(
|
|
386
|
+
text: $query,
|
|
387
|
+
placeholder: "Search input",
|
|
388
|
+
onChangeText: { query = $0.replacingOccurrences(of: "\n", with: " ") }
|
|
389
|
+
))
|
|
390
|
+
.padding(.horizontal, Spacing.L)
|
|
391
|
+
|
|
392
|
+
ScrollView {
|
|
393
|
+
LazyVStack(alignment: .leading, spacing: 0) {
|
|
394
|
+
ForEach(filtered) { item in
|
|
395
|
+
HStack(spacing: Spacing.S) {
|
|
396
|
+
if isColor, let color = item.value.base as? Color {
|
|
397
|
+
RoundedRectangle(cornerRadius: Radius.S)
|
|
398
|
+
.fill(color)
|
|
399
|
+
.frame(width: 36, height: 36)
|
|
400
|
+
.overlay(
|
|
401
|
+
RoundedRectangle(cornerRadius: Radius.S)
|
|
402
|
+
.stroke(defaultTheme.colors.border.default, lineWidth: 1)
|
|
403
|
+
)
|
|
404
|
+
} else if let iconName = item.value.base as? String {
|
|
405
|
+
Icon(source: iconName, size: 24)
|
|
406
|
+
}
|
|
407
|
+
MomoText(item.key, typography: .bodyDefaultRegular)
|
|
408
|
+
}
|
|
409
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
410
|
+
.padding(.vertical, Spacing.XS)
|
|
411
|
+
.contentShape(Rectangle())
|
|
412
|
+
.onTapGesture { onSelect(item) }
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
.padding(Spacing.L)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
.frame(height: 600)
|
|
419
|
+
}
|
|
420
|
+
}
|
|
@@ -1,14 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
//
|
|
2
|
+
// DividerDemo.swift
|
|
3
|
+
// Example
|
|
4
|
+
//
|
|
5
|
+
// Preview + Playground demo for MomoDivider.
|
|
6
|
+
//
|
|
7
|
+
|
|
2
8
|
import MoMoUIKits
|
|
9
|
+
import SwiftUI
|
|
3
10
|
|
|
4
11
|
struct DividerDemo: View {
|
|
5
12
|
var body: some View {
|
|
6
|
-
|
|
13
|
+
if #available(iOS 16.0, *) {
|
|
14
|
+
DemoScreen(preview: { DividerPreview() }, playground: { DividerPlayground() })
|
|
15
|
+
} else {
|
|
16
|
+
Text("Requires iOS 16+").padding()
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// MARK: - Preview
|
|
22
|
+
|
|
23
|
+
private struct DividerPreview: View {
|
|
24
|
+
var body: some View {
|
|
25
|
+
BasicColumnBox("Between items", alignment: .leading) {
|
|
7
26
|
ForEach(0..<5, id: \.self) { index in
|
|
8
|
-
|
|
27
|
+
MomoText("Item \(index)", typography: .bodyDefaultRegular)
|
|
9
28
|
MomoDivider()
|
|
10
29
|
}
|
|
11
30
|
}
|
|
12
|
-
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// MARK: - Playground
|
|
35
|
+
|
|
36
|
+
// MomoDivider takes no props; the playground varies how many are rendered.
|
|
37
|
+
@available(iOS 16.0, *)
|
|
38
|
+
private struct DividerPlayground: View {
|
|
39
|
+
@State private var count: Double = 3
|
|
40
|
+
|
|
41
|
+
var body: some View {
|
|
42
|
+
PlaygroundTab(
|
|
43
|
+
component: {
|
|
44
|
+
VStack(alignment: .leading, spacing: Spacing.S) {
|
|
45
|
+
ForEach(0..<Int(count), id: \.self) { index in
|
|
46
|
+
MomoText("Item \(index)", typography: .bodyDefaultRegular)
|
|
47
|
+
MomoDivider()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
params: [
|
|
52
|
+
.slider("Count", $count, min: 1, max: 6, step: 1),
|
|
53
|
+
]
|
|
54
|
+
)
|
|
13
55
|
}
|
|
14
56
|
}
|
|
@@ -13,11 +13,16 @@ public struct ScreenUsage: Hashable, Identifiable {
|
|
|
13
13
|
public let title: String
|
|
14
14
|
public let destination: AnyView
|
|
15
15
|
public let icon: String
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/// True when the destination hosts its own chrome (e.g. a `BottomTab` — the
|
|
17
|
+
/// Preview/Playground `DemoScreen` or `BottomTabDemo`); such screens are pushed
|
|
18
|
+
/// with `headerType: .none, scrollable: false`.
|
|
19
|
+
public let hostsOwnChrome: Bool
|
|
20
|
+
|
|
21
|
+
public init(title: String, destination: AnyView, icon: String, hostsOwnChrome: Bool = false) {
|
|
18
22
|
self.title = title
|
|
19
23
|
self.destination = destination
|
|
20
24
|
self.icon = icon
|
|
25
|
+
self.hostsOwnChrome = hostsOwnChrome
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
public static func == (lhs: ScreenUsage, rhs: ScreenUsage) -> Bool {
|
|
@@ -34,59 +39,51 @@ public func getIcon(icon: String) -> String {
|
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
public let ScreenUsages: [ScreenUsage] = [
|
|
37
|
-
|
|
38
|
-
ScreenUsage(title: "
|
|
39
|
-
ScreenUsage(title: "
|
|
40
|
-
ScreenUsage(title: "
|
|
41
|
-
ScreenUsage(title: "
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ScreenUsage(title: "
|
|
45
|
-
ScreenUsage(title: "
|
|
46
|
-
|
|
47
|
-
ScreenUsage(title: "
|
|
48
|
-
ScreenUsage(title: "
|
|
49
|
-
ScreenUsage(title: "
|
|
50
|
-
ScreenUsage(title: "
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
ScreenUsage(title: "PopupNotify", destination: AnyView(PopupNotifyDemo()), icon: getIcon(icon: "Popup")),
|
|
54
|
-
ScreenUsage(title: "PopupPromotion", destination: AnyView(PopupPromotionDemo()), icon: getIcon(icon: "Popup")),
|
|
55
|
-
ScreenUsage(title: "SnackBar", destination: AnyView(SnackBarDemo()), icon: getIcon(icon: "Popup")),
|
|
56
|
-
// ScreenUsage(title: "Radio", destination: AnyView(ContentView()), icon: getIcon(icon: "Radio")),
|
|
57
|
-
// ScreenUsage(title: "Skeleton", destination: AnyView(ContentView()), icon: getIcon(icon: "Skeleton")),
|
|
58
|
-
ScreenUsage(title: "Switch", destination: AnyView(SwitchDemo()), icon: getIcon(icon: "Toggle")),
|
|
59
|
-
// ScreenUsage(title: "Tag", destination: AnyView(ContentView()), icon: getIcon(icon: "Skeleton")),
|
|
60
|
-
ScreenUsage(title: "Text", destination: AnyView(TypographyDemo()), icon: getIcon(icon: "Typography")),
|
|
42
|
+
ScreenUsage(title: "Badge", destination: AnyView(BadgeDemo()), icon: getIcon(icon: "Badge"), hostsOwnChrome: true),
|
|
43
|
+
ScreenUsage(title: "Button", destination: AnyView(ButtonDemo()), icon: getIcon(icon: "Button"), hostsOwnChrome: true),
|
|
44
|
+
ScreenUsage(title: "CheckBox", destination: AnyView(CheckboxDemo()), icon: getIcon(icon: "Checkbox"), hostsOwnChrome: true),
|
|
45
|
+
ScreenUsage(title: "Chip", destination: AnyView(ChipDemo()), icon: getIcon(icon: "Chip"), hostsOwnChrome: true),
|
|
46
|
+
ScreenUsage(title: "Icon", destination: AnyView(IconDemo()), icon: getIcon(icon: "Icon"), hostsOwnChrome: true),
|
|
47
|
+
ScreenUsage(title: "Image", destination: AnyView(ImageDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
48
|
+
ScreenUsage(title: "Section", destination: AnyView(SectionDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
49
|
+
ScreenUsage(title: "Input", destination: AnyView(InputDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
50
|
+
ScreenUsage(title: "Input Phone Number", destination: AnyView(InputPhoneNumberDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
51
|
+
ScreenUsage(title: "InputTextArea", destination: AnyView(InputTextAreaDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
52
|
+
ScreenUsage(title: "InputSearch", destination: AnyView(InputSearchDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
53
|
+
ScreenUsage(title: "PopupNotify", destination: AnyView(PopupNotifyDemo()), icon: getIcon(icon: "Popup"), hostsOwnChrome: true),
|
|
54
|
+
ScreenUsage(title: "PopupPromotion", destination: AnyView(PopupPromotionDemo()), icon: getIcon(icon: "Popup"), hostsOwnChrome: true),
|
|
55
|
+
ScreenUsage(title: "SnackBar", destination: AnyView(SnackBarDemo()), icon: getIcon(icon: "Popup"), hostsOwnChrome: true),
|
|
56
|
+
ScreenUsage(title: "Switch", destination: AnyView(SwitchDemo()), icon: getIcon(icon: "Toggle"), hostsOwnChrome: true),
|
|
57
|
+
ScreenUsage(title: "Text", destination: AnyView(TypographyDemo()), icon: getIcon(icon: "Typography"), hostsOwnChrome: true),
|
|
61
58
|
// ScreenUsage(title: "TrustBanner", destination: AnyView(TrustBanner(onPress: {_ in })), icon: getIcon(icon: "Typography")),
|
|
62
|
-
ScreenUsage(title: "Information", destination: AnyView(InformationDemo()), icon: getIcon(icon: "Typography")),
|
|
63
|
-
ScreenUsage(title: "Avatar", destination: AnyView(AvatarDemo()), icon: getIcon(icon: "Avatar")),
|
|
64
|
-
ScreenUsage(title: "Carousel", destination: AnyView(CarouselDemo()), icon: getIcon(icon: "Carousel")),
|
|
65
|
-
ScreenUsage(title: "Divider", destination: AnyView(DividerDemo()), icon: getIcon(icon: "Divider")),
|
|
66
|
-
ScreenUsage(title: "IconButton", destination: AnyView(IconButtonDemo()), icon: getIcon(icon: "Button")),
|
|
67
|
-
ScreenUsage(title: "Loader", destination: AnyView(LoaderDemo()), icon: getIcon(icon: "Loader")),
|
|
68
|
-
ScreenUsage(title: "Pagination", destination: AnyView(PaginationDemo()), icon: getIcon(icon: "Badge")),
|
|
69
|
-
ScreenUsage(title: "Radio", destination: AnyView(RadioDemo()), icon: getIcon(icon: "Radio")),
|
|
70
|
-
ScreenUsage(title: "Rating", destination: AnyView(RatingDemo()), icon: getIcon(icon: "Rating")),
|
|
71
|
-
ScreenUsage(title: "Skeleton", destination: AnyView(SkeletonDemo()), icon: getIcon(icon: "Skeleton")),
|
|
72
|
-
ScreenUsage(title: "SuggestAction", destination: AnyView(SuggestActionDemo()), icon: getIcon(icon: "Information")),
|
|
73
|
-
ScreenUsage(title: "Tag", destination: AnyView(TagDemo()), icon: getIcon(icon: "Tag")),
|
|
74
|
-
ScreenUsage(title: "Title", destination: AnyView(TitleDemo()), icon: getIcon(icon: "Typography")),
|
|
75
|
-
ScreenUsage(title: "Collapse", destination: AnyView(CollapseDemo()), icon: getIcon(icon: "Layout")),
|
|
76
|
-
ScreenUsage(title: "Stepper", destination: AnyView(StepperDemo()), icon: getIcon(icon: "Layout")),
|
|
77
|
-
ScreenUsage(title: "Uploader", destination: AnyView(UploaderDemo()), icon: getIcon(icon: "FormInput")),
|
|
78
|
-
ScreenUsage(title: "Swipe", destination: AnyView(SwipeDemo()), icon: getIcon(icon: "Layout")),
|
|
79
|
-
ScreenUsage(title: "InputDropDown", destination: AnyView(InputDropDownDemo()), icon: getIcon(icon: "FormInput")),
|
|
80
|
-
ScreenUsage(title: "InputMoney", destination: AnyView(InputMoneyDemo()), icon: getIcon(icon: "FormInput")),
|
|
81
|
-
ScreenUsage(title: "InputOTP", destination: AnyView(InputOTPDemo()), icon: getIcon(icon: "FormInput")),
|
|
82
|
-
ScreenUsage(title: "ProgressInfo", destination: AnyView(ProgressInfoDemo()), icon: getIcon(icon: "Layout")),
|
|
83
|
-
ScreenUsage(title: "Steps", destination: AnyView(StepsDemo()), icon: getIcon(icon: "Layout")),
|
|
84
|
-
ScreenUsage(title: "Slider", destination: AnyView(SliderDemo()), icon: getIcon(icon: "Layout")),
|
|
85
|
-
ScreenUsage(title: "TabView", destination: AnyView(TabViewDemo()), icon: getIcon(icon: "Layout")),
|
|
86
|
-
ScreenUsage(title: "Tooltip", destination: AnyView(TooltipDemo()), icon: getIcon(icon: "Layout")),
|
|
87
|
-
ScreenUsage(title: "DateTimePicker", destination: AnyView(DateTimePickerDemo()), icon: getIcon(icon: "Layout")),
|
|
59
|
+
ScreenUsage(title: "Information", destination: AnyView(InformationDemo()), icon: getIcon(icon: "Typography"), hostsOwnChrome: true),
|
|
60
|
+
ScreenUsage(title: "Avatar", destination: AnyView(AvatarDemo()), icon: getIcon(icon: "Avatar"), hostsOwnChrome: true),
|
|
61
|
+
ScreenUsage(title: "Carousel", destination: AnyView(CarouselDemo()), icon: getIcon(icon: "Carousel"), hostsOwnChrome: true),
|
|
62
|
+
ScreenUsage(title: "Divider", destination: AnyView(DividerDemo()), icon: getIcon(icon: "Divider"), hostsOwnChrome: true),
|
|
63
|
+
ScreenUsage(title: "IconButton", destination: AnyView(IconButtonDemo()), icon: getIcon(icon: "Button"), hostsOwnChrome: true),
|
|
64
|
+
ScreenUsage(title: "Loader", destination: AnyView(LoaderDemo()), icon: getIcon(icon: "Loader"), hostsOwnChrome: true),
|
|
65
|
+
ScreenUsage(title: "Pagination", destination: AnyView(PaginationDemo()), icon: getIcon(icon: "Badge"), hostsOwnChrome: true),
|
|
66
|
+
ScreenUsage(title: "Radio", destination: AnyView(RadioDemo()), icon: getIcon(icon: "Radio"), hostsOwnChrome: true),
|
|
67
|
+
ScreenUsage(title: "Rating", destination: AnyView(RatingDemo()), icon: getIcon(icon: "Rating"), hostsOwnChrome: true),
|
|
68
|
+
ScreenUsage(title: "Skeleton", destination: AnyView(SkeletonDemo()), icon: getIcon(icon: "Skeleton"), hostsOwnChrome: true),
|
|
69
|
+
ScreenUsage(title: "SuggestAction", destination: AnyView(SuggestActionDemo()), icon: getIcon(icon: "Information"), hostsOwnChrome: true),
|
|
70
|
+
ScreenUsage(title: "Tag", destination: AnyView(TagDemo()), icon: getIcon(icon: "Tag"), hostsOwnChrome: true),
|
|
71
|
+
ScreenUsage(title: "Title", destination: AnyView(TitleDemo()), icon: getIcon(icon: "Typography"), hostsOwnChrome: true),
|
|
72
|
+
ScreenUsage(title: "Collapse", destination: AnyView(CollapseDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
73
|
+
ScreenUsage(title: "Stepper", destination: AnyView(StepperDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
74
|
+
ScreenUsage(title: "Uploader", destination: AnyView(UploaderDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
75
|
+
ScreenUsage(title: "Swipe", destination: AnyView(SwipeDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
76
|
+
ScreenUsage(title: "InputDropDown", destination: AnyView(InputDropDownDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
77
|
+
ScreenUsage(title: "InputMoney", destination: AnyView(InputMoneyDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
78
|
+
ScreenUsage(title: "InputOTP", destination: AnyView(InputOTPDemo()), icon: getIcon(icon: "FormInput"), hostsOwnChrome: true),
|
|
79
|
+
ScreenUsage(title: "ProgressInfo", destination: AnyView(ProgressInfoDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
80
|
+
ScreenUsage(title: "Steps", destination: AnyView(StepsDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
81
|
+
ScreenUsage(title: "Slider", destination: AnyView(SliderDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
82
|
+
ScreenUsage(title: "TabView", destination: AnyView(TabViewDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
83
|
+
ScreenUsage(title: "Tooltip", destination: AnyView(TooltipDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
84
|
+
ScreenUsage(title: "DateTimePicker", destination: AnyView(DateTimePickerDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
88
85
|
ScreenUsage(title: "Navigation", destination: AnyView(NavigationDemo()), icon: getIcon(icon: "Layout")),
|
|
89
|
-
ScreenUsage(title: "Bottom Tab", destination: AnyView(BottomTabDemo()), icon: getIcon(icon: "Layout")),
|
|
86
|
+
ScreenUsage(title: "Bottom Tab", destination: AnyView(BottomTabDemo()), icon: getIcon(icon: "Layout"), hostsOwnChrome: true),
|
|
90
87
|
ScreenUsage(title: "Animated Header", destination: AnyView(AnimatedHeaderDemo()), icon: getIcon(icon: "Layout")),
|
|
91
88
|
ScreenUsage(title: "Theme", destination: AnyView(ThemeDemo()), icon: getIcon(icon: "Typography")),
|
|
92
89
|
ScreenUsage(title: "Localize", destination: AnyView(LocalizeDemo()), icon: getIcon(icon: "Typography")),
|
|
@@ -134,11 +131,11 @@ public struct HomeView: View {
|
|
|
134
131
|
headerRight: {
|
|
135
132
|
HeaderRight(headerRight: HeaderRightData(useShortcut: true))
|
|
136
133
|
},
|
|
137
|
-
// footerComponent = { Button("
|
|
134
|
+
// footerComponent = { Button("Open SwiftUI (iOS only)") }
|
|
138
135
|
footer: {
|
|
139
136
|
AnyView(
|
|
140
137
|
MoMoUIKits.Button(
|
|
141
|
-
title: "
|
|
138
|
+
title: "Open Compose",
|
|
142
139
|
action: onOpenCompose,
|
|
143
140
|
type: .primary,
|
|
144
141
|
size: .large
|
|
@@ -240,7 +237,7 @@ public struct HomeItemView: View {
|
|
|
240
237
|
public var body: some View {
|
|
241
238
|
ForEach(screenUsages) { screenUsage in
|
|
242
239
|
SwiftUI.Button {
|
|
243
|
-
let options = screenUsage.
|
|
240
|
+
let options = screenUsage.hostsOwnChrome
|
|
244
241
|
? NavigationOptions(
|
|
245
242
|
title: screenUsage.title,
|
|
246
243
|
headerType: .none,
|
|
@@ -267,7 +264,7 @@ public struct HomeItemView: View {
|
|
|
267
264
|
Divider()
|
|
268
265
|
}
|
|
269
266
|
.padding(.horizontal, 16)
|
|
270
|
-
.padding(.vertical,
|
|
267
|
+
.padding(.vertical, 16)
|
|
271
268
|
}
|
|
272
269
|
}
|
|
273
270
|
|