react-native-platform-components 1.2.0 → 1.4.0
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/README.md +33 -31
- package/android/src/main/java/com/platformcomponents/PCButtonGroupView.kt +498 -0
- package/android/src/main/java/com/platformcomponents/PCButtonGroupViewManager.kt +191 -0
- package/android/src/main/java/com/platformcomponents/PCButtonSupport.kt +127 -0
- package/android/src/main/java/com/platformcomponents/PCButtonView.kt +345 -0
- package/android/src/main/java/com/platformcomponents/PCButtonViewManager.kt +126 -0
- package/android/src/main/java/com/platformcomponents/PCExpressive.kt +107 -0
- package/android/src/main/java/com/platformcomponents/PCFloatingToolbarView.kt +115 -0
- package/android/src/main/java/com/platformcomponents/PCFloatingToolbarViewManager.kt +65 -0
- package/android/src/main/java/com/platformcomponents/PCNativeThemeModule.kt +3 -0
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +13 -5
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +6 -1
- package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +1018 -0
- package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +248 -0
- package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +13 -6
- package/android/src/main/jni/CMakeLists.txt +13 -1
- package/android/src/main/res/values/attrs.xml +13 -0
- package/android/src/main/res/values/styles.xml +183 -0
- package/ios/PCButton.h +10 -0
- package/ios/PCButton.mm +196 -0
- package/ios/PCButtonGroup.h +10 -0
- package/ios/PCButtonGroup.mm +256 -0
- package/ios/PCButtonGroupView.swift +254 -0
- package/ios/PCButtonSupport.swift +141 -0
- package/ios/PCButtonView.swift +155 -0
- package/ios/PCFloatingToolbar.h +10 -0
- package/ios/PCFloatingToolbar.mm +76 -0
- package/ios/PCFloatingToolbarView.swift +95 -0
- package/ios/PCNativeThemeModule.mm +13 -0
- package/ios/PCSelectionMenu.swift +9 -1
- package/ios/PCTextField.h +10 -0
- package/ios/PCTextField.mm +391 -0
- package/ios/PCTextFieldView.swift +1012 -0
- package/lib/commonjs/Button.js +77 -0
- package/lib/commonjs/Button.js.map +1 -0
- package/lib/commonjs/ButtonGroup.js +99 -0
- package/lib/commonjs/ButtonGroup.js.map +1 -0
- package/lib/commonjs/ButtonGroupNativeComponent.ts +121 -0
- package/lib/commonjs/ButtonNativeComponent.ts +76 -0
- package/lib/commonjs/ContextMenuNativeComponent.ts +5 -4
- package/lib/commonjs/DatePickerNativeComponent.ts +17 -11
- package/lib/commonjs/FloatingToolbar.js +69 -0
- package/lib/commonjs/FloatingToolbar.js.map +1 -0
- package/lib/commonjs/FloatingToolbarNativeComponent.ts +31 -0
- package/lib/commonjs/LiquidGlass.js +24 -4
- package/lib/commonjs/LiquidGlass.js.map +1 -1
- package/lib/commonjs/LiquidGlassNativeComponent.ts +6 -5
- package/lib/commonjs/NativePlatformComponentsTheme.js.map +1 -1
- package/lib/commonjs/SegmentedControl.js +11 -85
- package/lib/commonjs/SegmentedControl.js.map +1 -1
- package/lib/commonjs/SegmentedControlNativeComponent.ts +15 -11
- package/lib/commonjs/SelectionMenuNativeComponent.ts +6 -5
- package/lib/commonjs/TextField.js +195 -0
- package/lib/commonjs/TextField.js.map +1 -0
- package/lib/commonjs/TextFieldNativeComponent.ts +218 -0
- package/lib/commonjs/codegenTypes.js +6 -0
- package/lib/commonjs/codegenTypes.js.map +1 -0
- package/lib/commonjs/focusRegistry.js +78 -0
- package/lib/commonjs/focusRegistry.js.map +1 -0
- package/lib/commonjs/icons.js +92 -0
- package/lib/commonjs/icons.js.map +1 -0
- package/lib/commonjs/index.js +66 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +32 -2
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/labelStyle.js +27 -0
- package/lib/commonjs/labelStyle.js.map +1 -0
- package/lib/commonjs/reactNativeInternals.d.js +2 -0
- package/lib/commonjs/reactNativeInternals.d.js.map +1 -0
- package/lib/module/Button.js +70 -0
- package/lib/module/Button.js.map +1 -0
- package/lib/module/ButtonGroup.js +92 -0
- package/lib/module/ButtonGroup.js.map +1 -0
- package/lib/module/ButtonGroupNativeComponent.ts +121 -0
- package/lib/module/ButtonNativeComponent.ts +76 -0
- package/lib/module/ContextMenuNativeComponent.ts +5 -4
- package/lib/module/DatePickerNativeComponent.ts +17 -11
- package/lib/module/FloatingToolbar.js +62 -0
- package/lib/module/FloatingToolbar.js.map +1 -0
- package/lib/module/FloatingToolbarNativeComponent.ts +31 -0
- package/lib/module/LiquidGlass.js +24 -4
- package/lib/module/LiquidGlass.js.map +1 -1
- package/lib/module/LiquidGlassNativeComponent.ts +6 -5
- package/lib/module/NativePlatformComponentsTheme.js.map +1 -1
- package/lib/module/SegmentedControl.js +12 -87
- package/lib/module/SegmentedControl.js.map +1 -1
- package/lib/module/SegmentedControlNativeComponent.ts +15 -11
- package/lib/module/SelectionMenuNativeComponent.ts +6 -5
- package/lib/module/TextField.js +189 -0
- package/lib/module/TextField.js.map +1 -0
- package/lib/module/TextFieldNativeComponent.ts +218 -0
- package/lib/module/codegenTypes.js +4 -0
- package/lib/module/codegenTypes.js.map +1 -0
- package/lib/module/focusRegistry.js +74 -0
- package/lib/module/focusRegistry.js.map +1 -0
- package/lib/module/icons.js +87 -0
- package/lib/module/icons.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +28 -0
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/labelStyle.js +23 -0
- package/lib/module/labelStyle.js.map +1 -0
- package/lib/module/reactNativeInternals.d.js +2 -0
- package/lib/module/reactNativeInternals.d.js.map +1 -0
- package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/Button.d.ts +76 -0
- package/lib/typescript/commonjs/src/Button.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/ButtonGroup.d.ts +102 -0
- package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +93 -0
- package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +57 -0
- package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts +5 -4
- package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts +12 -11
- package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +45 -0
- package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +24 -0
- package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts +4 -3
- package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +6 -5
- package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts +10 -2
- package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts +17 -46
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +9 -6
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts +6 -5
- package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/TextField.d.ts +174 -0
- package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +162 -0
- package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/codegenTypes.d.ts +12 -0
- package/lib/typescript/commonjs/src/codegenTypes.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/focusRegistry.d.ts +13 -0
- package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/icons.d.ts +52 -0
- package/lib/typescript/commonjs/src/icons.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +6 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.web.d.ts +121 -0
- package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/labelStyle.d.ts +20 -0
- package/lib/typescript/commonjs/src/labelStyle.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/sharedTypes.d.ts +8 -3
- package/lib/typescript/commonjs/src/sharedTypes.d.ts.map +1 -1
- package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
- package/lib/typescript/module/src/Button.d.ts +76 -0
- package/lib/typescript/module/src/Button.d.ts.map +1 -0
- package/lib/typescript/module/src/ButtonGroup.d.ts +102 -0
- package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -0
- package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +93 -0
- package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/ButtonNativeComponent.d.ts +57 -0
- package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts +5 -4
- package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/DatePickerNativeComponent.d.ts +12 -11
- package/lib/typescript/module/src/DatePickerNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/FloatingToolbar.d.ts +45 -0
- package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -0
- package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +24 -0
- package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/LiquidGlass.d.ts +4 -3
- package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -1
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +6 -5
- package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts +10 -2
- package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts.map +1 -1
- package/lib/typescript/module/src/SegmentedControl.d.ts +17 -46
- package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +9 -6
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts +6 -5
- package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts.map +1 -1
- package/lib/typescript/module/src/TextField.d.ts +174 -0
- package/lib/typescript/module/src/TextField.d.ts.map +1 -0
- package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +162 -0
- package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/codegenTypes.d.ts +12 -0
- package/lib/typescript/module/src/codegenTypes.d.ts.map +1 -0
- package/lib/typescript/module/src/focusRegistry.d.ts +13 -0
- package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -0
- package/lib/typescript/module/src/icons.d.ts +52 -0
- package/lib/typescript/module/src/icons.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +6 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.web.d.ts +121 -0
- package/lib/typescript/module/src/index.web.d.ts.map +1 -1
- package/lib/typescript/module/src/labelStyle.d.ts +20 -0
- package/lib/typescript/module/src/labelStyle.d.ts.map +1 -0
- package/lib/typescript/module/src/sharedTypes.d.ts +8 -3
- package/lib/typescript/module/src/sharedTypes.d.ts.map +1 -1
- package/package.json +28 -6
- package/react-native.config.js +3 -0
- package/shared/PCButtonComponentDescriptors-custom.h +22 -0
- package/shared/PCButtonGroupComponentDescriptors-custom.h +22 -0
- package/shared/PCButtonGroupShadowNode-custom.cpp +48 -0
- package/shared/PCButtonGroupShadowNode-custom.h +55 -0
- package/shared/PCButtonGroupState-custom.h +61 -0
- package/shared/PCButtonShadowNode-custom.cpp +48 -0
- package/shared/PCButtonShadowNode-custom.h +55 -0
- package/shared/PCButtonState-custom.h +61 -0
- package/shared/PCDatePickerState-custom.h +2 -2
- package/shared/PCSegmentedControlState-custom.h +2 -2
- package/shared/PCSelectionMenuState-custom.h +2 -2
- package/shared/PCTextFieldComponentDescriptors-custom.h +22 -0
- package/shared/PCTextFieldShadowNode-custom.cpp +47 -0
- package/shared/PCTextFieldShadowNode-custom.h +55 -0
- package/shared/PCTextFieldState-custom.h +61 -0
- package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
- package/src/Button.tsx +144 -0
- package/src/ButtonGroup.tsx +233 -0
- package/src/ButtonGroupNativeComponent.ts +121 -0
- package/src/ButtonNativeComponent.ts +76 -0
- package/src/ContextMenuNativeComponent.ts +5 -4
- package/src/DatePickerNativeComponent.ts +17 -11
- package/src/FloatingToolbar.tsx +113 -0
- package/src/FloatingToolbarNativeComponent.ts +31 -0
- package/src/LiquidGlass.tsx +24 -5
- package/src/LiquidGlassNativeComponent.ts +6 -5
- package/src/NativePlatformComponentsTheme.ts +11 -2
- package/src/SegmentedControl.tsx +26 -118
- package/src/SegmentedControlNativeComponent.ts +15 -11
- package/src/SelectionMenuNativeComponent.ts +6 -5
- package/src/TextField.tsx +494 -0
- package/src/TextFieldNativeComponent.ts +218 -0
- package/src/codegenTypes.ts +40 -0
- package/src/focusRegistry.ts +89 -0
- package/src/icons.ts +116 -0
- package/src/index.tsx +6 -0
- package/src/index.web.tsx +194 -0
- package/src/labelStyle.ts +36 -0
- package/src/reactNativeInternals.d.ts +22 -0
- package/src/sharedTypes.ts +9 -3
- /package/{app.plugin.cjs → app.plugin.js} +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// A row of native buttons (`UIButton` with configurations), with optional
|
|
4
|
+
/// single / multiple selection shown through the buttons' selected state.
|
|
5
|
+
@objcMembers
|
|
6
|
+
public final class PCButtonGroupView: UIView {
|
|
7
|
+
private struct Item {
|
|
8
|
+
let label: String
|
|
9
|
+
let value: String
|
|
10
|
+
let disabled: Bool
|
|
11
|
+
let icon: PCButtonSupport.Icon
|
|
12
|
+
let accessibilityLabel: String
|
|
13
|
+
|
|
14
|
+
/// What VoiceOver announces for the button.
|
|
15
|
+
var spokenLabel: String { accessibilityLabel.isEmpty ? label : accessibilityLabel }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// MARK: - Props (set from ObjC++)
|
|
19
|
+
|
|
20
|
+
/// ObjC++ sets this as an array of dictionaries; see `rebuild` for keys.
|
|
21
|
+
public var buttons: [Any] = [] { didSet { rebuild() } }
|
|
22
|
+
|
|
23
|
+
/// "filled" | "tonal" | "outlined" | "text" | "elevated"
|
|
24
|
+
public var variant: String = "outlined" {
|
|
25
|
+
didSet { if oldValue != variant { applyConfigurations() } }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// "xsmall" | "small" | "medium" | "large" | "xlarge"
|
|
29
|
+
public var size: String = "small" {
|
|
30
|
+
didSet { if oldValue != size { applyConfigurations() } }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// "" (UIKit default) | "round" | "square"
|
|
34
|
+
public var shape: String = "" {
|
|
35
|
+
didSet { if oldValue != shape { applyConfigurations() } }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Connected groups sit closer together (a hairline gap)
|
|
39
|
+
public var connected: Bool = false {
|
|
40
|
+
didSet { if oldValue != connected { applyLayout() } }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Gap between buttons in points; negative means the default
|
|
44
|
+
public var spacing: CGFloat = -1 {
|
|
45
|
+
didSet { if oldValue != spacing { applyLayout() } }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// "none" | "single" | "multiple"
|
|
49
|
+
public var selection: String = "none" {
|
|
50
|
+
didSet { if oldValue != selection { applyConfigurations() } }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// Controlled selection by value
|
|
54
|
+
public var selectedValues: [String] = [] {
|
|
55
|
+
didSet { if oldValue != selectedValues { applyConfigurations() } }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Whether at least one button must stay selected
|
|
59
|
+
public var selectionRequired: Bool = false
|
|
60
|
+
|
|
61
|
+
/// "enabled" | "disabled"
|
|
62
|
+
public var interactivity: String = "enabled" {
|
|
63
|
+
didSet { updateEnabled() }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/// Container color; nil keeps the configuration's color
|
|
67
|
+
public var containerColor: UIColor? {
|
|
68
|
+
didSet { applyConfigurations() }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// Label and icon color; nil keeps the configuration's color
|
|
72
|
+
public var foregroundColor: UIColor? {
|
|
73
|
+
didSet { applyConfigurations() }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/// Label font; nil keeps the configuration's font
|
|
77
|
+
public var labelFont: UIFont? {
|
|
78
|
+
didSet { applyConfigurations() }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// MARK: - Events back to ObjC++
|
|
82
|
+
|
|
83
|
+
public var onPress: ((Int, String) -> Void)? // (index, value)
|
|
84
|
+
public var onSelectionChange: (([String]) -> Void)?
|
|
85
|
+
|
|
86
|
+
/// Called when content changed after layout (an icon finished loading),
|
|
87
|
+
/// so the Fabric measurement can be refreshed.
|
|
88
|
+
public var onNeedsRemeasure: (() -> Void)?
|
|
89
|
+
|
|
90
|
+
// MARK: - Internal
|
|
91
|
+
|
|
92
|
+
private let stack = UIStackView()
|
|
93
|
+
private var items: [Item] = []
|
|
94
|
+
private var uiButtons: [UIButton] = []
|
|
95
|
+
private var iconImages: [UIImage?] = []
|
|
96
|
+
|
|
97
|
+
/// Bumped on every rebuild so late image loads can't touch stale buttons.
|
|
98
|
+
private var rebuildGeneration = 0
|
|
99
|
+
|
|
100
|
+
// MARK: - Init
|
|
101
|
+
|
|
102
|
+
public override init(frame: CGRect) {
|
|
103
|
+
super.init(frame: frame)
|
|
104
|
+
setup()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public required init?(coder: NSCoder) {
|
|
108
|
+
super.init(coder: coder)
|
|
109
|
+
setup()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private func setup() {
|
|
113
|
+
stack.axis = .horizontal
|
|
114
|
+
stack.alignment = .fill
|
|
115
|
+
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
116
|
+
addSubview(stack)
|
|
117
|
+
|
|
118
|
+
NSLayoutConstraint.activate([
|
|
119
|
+
stack.topAnchor.constraint(equalTo: topAnchor),
|
|
120
|
+
stack.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
121
|
+
stack.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
122
|
+
stack.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
123
|
+
])
|
|
124
|
+
|
|
125
|
+
applyLayout()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// MARK: - Props handling
|
|
129
|
+
|
|
130
|
+
private func rebuild() {
|
|
131
|
+
items = buttons.compactMap { any in
|
|
132
|
+
guard let dict = any as? [String: Any] else { return nil }
|
|
133
|
+
return Item(
|
|
134
|
+
label: (dict["label"] as? String) ?? "",
|
|
135
|
+
value: (dict["value"] as? String) ?? "",
|
|
136
|
+
disabled: (dict["disabled"] as? String) == "disabled",
|
|
137
|
+
icon: PCButtonSupport.Icon(dictionary: dict),
|
|
138
|
+
accessibilityLabel: (dict["accessibilityLabel"] as? String) ?? ""
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
rebuildGeneration += 1
|
|
143
|
+
let generation = rebuildGeneration
|
|
144
|
+
|
|
145
|
+
uiButtons.forEach { $0.removeFromSuperview() }
|
|
146
|
+
uiButtons = []
|
|
147
|
+
iconImages = Array(repeating: nil, count: items.count)
|
|
148
|
+
|
|
149
|
+
for (index, item) in items.enumerated() {
|
|
150
|
+
let button = UIButton(type: .system)
|
|
151
|
+
button.tag = index
|
|
152
|
+
button.addTarget(self, action: #selector(tapped(_:)), for: .touchUpInside)
|
|
153
|
+
stack.addArrangedSubview(button)
|
|
154
|
+
uiButtons.append(button)
|
|
155
|
+
|
|
156
|
+
iconImages[index] = PCButtonSupport.image(for: item.icon) { [weak self] image in
|
|
157
|
+
guard let self, self.rebuildGeneration == generation, index < self.iconImages.count else { return }
|
|
158
|
+
self.iconImages[index] = image
|
|
159
|
+
self.applyConfigurations()
|
|
160
|
+
self.onNeedsRemeasure?()
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
applyConfigurations()
|
|
165
|
+
updateEnabled()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private func applyLayout() {
|
|
169
|
+
stack.spacing = spacing >= 0 ? spacing : (connected ? 2 : 8)
|
|
170
|
+
// Buttons size to their content; extra or missing width is shared in
|
|
171
|
+
// proportion when the group is stretched or squeezed.
|
|
172
|
+
stack.distribution = .fillProportionally
|
|
173
|
+
invalidateIntrinsicContentSize()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private func applyConfigurations() {
|
|
177
|
+
for (index, button) in uiButtons.enumerated() where index < items.count {
|
|
178
|
+
let item = items[index]
|
|
179
|
+
let selected = selection != "none" && selectedValues.contains(item.value)
|
|
180
|
+
button.isSelected = selected
|
|
181
|
+
button.configuration = PCButtonSupport.makeConfiguration(
|
|
182
|
+
variant: variant,
|
|
183
|
+
selected: selected,
|
|
184
|
+
size: size,
|
|
185
|
+
shape: shape,
|
|
186
|
+
label: item.label,
|
|
187
|
+
image: iconImages[index],
|
|
188
|
+
containerColor: containerColor,
|
|
189
|
+
foregroundColor: foregroundColor,
|
|
190
|
+
font: labelFont
|
|
191
|
+
)
|
|
192
|
+
button.accessibilityLabel = item.spokenLabel.isEmpty ? nil : item.spokenLabel
|
|
193
|
+
}
|
|
194
|
+
invalidateIntrinsicContentSize()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private func updateEnabled() {
|
|
198
|
+
let enabled = interactivity != "disabled"
|
|
199
|
+
alpha = enabled ? 1.0 : 0.5
|
|
200
|
+
for (index, button) in uiButtons.enumerated() where index < items.count {
|
|
201
|
+
button.isEnabled = enabled && !items[index].disabled
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// MARK: - Selection
|
|
206
|
+
|
|
207
|
+
@objc private func tapped(_ sender: UIButton) {
|
|
208
|
+
let index = sender.tag
|
|
209
|
+
guard index >= 0, index < items.count else { return }
|
|
210
|
+
let item = items[index]
|
|
211
|
+
onPress?(index, item.value)
|
|
212
|
+
|
|
213
|
+
guard selection != "none", let next = nextSelection(tapping: item.value) else { return }
|
|
214
|
+
selectedValues = next
|
|
215
|
+
onSelectionChange?(next)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/// The selection after a tap, or nil when the tap changes nothing.
|
|
219
|
+
private func nextSelection(tapping value: String) -> [String]? {
|
|
220
|
+
let isSelected = selectedValues.contains(value)
|
|
221
|
+
if selection == "single" {
|
|
222
|
+
if isSelected {
|
|
223
|
+
return selectionRequired ? nil : []
|
|
224
|
+
}
|
|
225
|
+
return [value]
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// multiple
|
|
229
|
+
if isSelected {
|
|
230
|
+
if selectionRequired && selectedValues.count == 1 { return nil }
|
|
231
|
+
return selectedValues.filter { $0 != value }
|
|
232
|
+
}
|
|
233
|
+
var chosen = Set(selectedValues)
|
|
234
|
+
chosen.insert(value)
|
|
235
|
+
// Report in button order
|
|
236
|
+
return items.map(\.value).filter { chosen.contains($0) }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// MARK: - Sizing
|
|
240
|
+
|
|
241
|
+
public override var intrinsicContentSize: CGSize {
|
|
242
|
+
stack.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
public override func sizeThatFits(_ size: CGSize) -> CGSize {
|
|
246
|
+
stack.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/// Called by the measuring pipeline to get the size for Yoga layout.
|
|
250
|
+
@objc public func sizeForLayout(withConstrainedTo constrainedSize: CGSize) -> CGSize {
|
|
251
|
+
let fitted = stack.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
|
|
252
|
+
return CGSize(width: ceil(fitted.width), height: ceil(fitted.height))
|
|
253
|
+
}
|
|
254
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// UIButton configuration and icon handling shared by PCButtonView and
|
|
4
|
+
/// PCButtonGroupView.
|
|
5
|
+
enum PCButtonSupport {
|
|
6
|
+
struct Icon: Equatable {
|
|
7
|
+
/// "", "sfSymbol", "drawable" (ignored on iOS) or "image"
|
|
8
|
+
var type: String = ""
|
|
9
|
+
var name: String = ""
|
|
10
|
+
var uri: String = ""
|
|
11
|
+
var scale: CGFloat = 1
|
|
12
|
+
var tinted: Bool = true
|
|
13
|
+
|
|
14
|
+
var isPresent: Bool { type == "sfSymbol" || type == "image" }
|
|
15
|
+
|
|
16
|
+
static let none = Icon()
|
|
17
|
+
|
|
18
|
+
init() {}
|
|
19
|
+
|
|
20
|
+
init(type: String, name: String, uri: String, scale: CGFloat, tinted: Bool) {
|
|
21
|
+
self.type = type
|
|
22
|
+
self.name = name
|
|
23
|
+
self.uri = uri
|
|
24
|
+
self.scale = scale > 0 ? scale : 1
|
|
25
|
+
self.tinted = tinted
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// Reads the flat icon fields (iconType, iconName, ...) bridged as a dictionary.
|
|
29
|
+
init(dictionary: [String: Any]) {
|
|
30
|
+
let scale = (dictionary["iconScale"] as? NSNumber).map { CGFloat(truncating: $0) } ?? 1
|
|
31
|
+
self.init(
|
|
32
|
+
type: (dictionary["iconType"] as? String) ?? "",
|
|
33
|
+
name: (dictionary["iconName"] as? String) ?? "",
|
|
34
|
+
uri: (dictionary["iconUri"] as? String) ?? "",
|
|
35
|
+
scale: scale,
|
|
36
|
+
tinted: (dictionary["iconTinted"] as? String) != "false"
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// The configuration for a variant. A selected button (single / multiple
|
|
42
|
+
/// selection in a group) uses the filled style, as UIKit's own toggle
|
|
43
|
+
/// buttons do.
|
|
44
|
+
///
|
|
45
|
+
/// | Variant | Configuration |
|
|
46
|
+
/// | filled | .filled() |
|
|
47
|
+
/// | tonal | .tinted() |
|
|
48
|
+
/// | outlined | .bordered() |
|
|
49
|
+
/// | text | .plain() |
|
|
50
|
+
/// | elevated | .gray() |
|
|
51
|
+
static func configuration(variant: String, selected: Bool) -> UIButton.Configuration {
|
|
52
|
+
if selected { return .filled() }
|
|
53
|
+
switch variant {
|
|
54
|
+
case "tonal": return .tinted()
|
|
55
|
+
case "outlined": return .bordered()
|
|
56
|
+
case "text": return .plain()
|
|
57
|
+
case "elevated": return .gray()
|
|
58
|
+
default: return .filled()
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// Material's five sizes onto UIKit's four.
|
|
63
|
+
static func buttonSize(_ size: String) -> UIButton.Configuration.Size {
|
|
64
|
+
switch size {
|
|
65
|
+
case "xsmall": return .mini
|
|
66
|
+
case "medium": return .medium
|
|
67
|
+
case "large", "xlarge": return .large
|
|
68
|
+
default: return .small
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// `nil` keeps UIKit's dynamic corner style.
|
|
73
|
+
static func cornerStyle(_ shape: String) -> UIButton.Configuration.CornerStyle? {
|
|
74
|
+
switch shape {
|
|
75
|
+
case "round": return .capsule
|
|
76
|
+
case "square": return .large
|
|
77
|
+
default: return nil
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static func makeConfiguration(
|
|
82
|
+
variant: String,
|
|
83
|
+
selected: Bool,
|
|
84
|
+
size: String,
|
|
85
|
+
shape: String,
|
|
86
|
+
label: String,
|
|
87
|
+
image: UIImage?,
|
|
88
|
+
containerColor: UIColor?,
|
|
89
|
+
foregroundColor: UIColor?,
|
|
90
|
+
font: UIFont?
|
|
91
|
+
) -> UIButton.Configuration {
|
|
92
|
+
var config = configuration(variant: variant, selected: selected)
|
|
93
|
+
config.title = label.isEmpty ? nil : label
|
|
94
|
+
config.image = image
|
|
95
|
+
config.imagePadding = (image != nil && !label.isEmpty) ? 8 : 0
|
|
96
|
+
config.buttonSize = buttonSize(size)
|
|
97
|
+
config.titleLineBreakMode = .byTruncatingTail
|
|
98
|
+
if let corner = cornerStyle(shape) {
|
|
99
|
+
config.cornerStyle = corner
|
|
100
|
+
}
|
|
101
|
+
if let containerColor {
|
|
102
|
+
config.baseBackgroundColor = containerColor
|
|
103
|
+
}
|
|
104
|
+
if let foregroundColor {
|
|
105
|
+
config.baseForegroundColor = foregroundColor
|
|
106
|
+
}
|
|
107
|
+
if let font {
|
|
108
|
+
config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in
|
|
109
|
+
var outgoing = incoming
|
|
110
|
+
outgoing.font = font
|
|
111
|
+
return outgoing
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return config
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Resolves the icon's image. SF Symbols resolve synchronously; images
|
|
118
|
+
/// that are still loading return nil and call `completion` on the main
|
|
119
|
+
/// thread once they arrive.
|
|
120
|
+
static func image(for icon: Icon, completion: @escaping (UIImage?) -> Void) -> UIImage? {
|
|
121
|
+
switch icon.type {
|
|
122
|
+
case "sfSymbol":
|
|
123
|
+
return UIImage(systemName: icon.name).map { decorate($0, tinted: icon.tinted) }
|
|
124
|
+
|
|
125
|
+
case "image":
|
|
126
|
+
let cached = PCImageLoader.shared.image(uri: icon.uri, scale: icon.scale) { image in
|
|
127
|
+
completion(image.map { decorate($0, tinted: icon.tinted) })
|
|
128
|
+
}
|
|
129
|
+
return cached.map { decorate($0, tinted: icon.tinted) }
|
|
130
|
+
|
|
131
|
+
default:
|
|
132
|
+
return nil
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/// Template images take the button's foreground color; untinted images
|
|
137
|
+
/// keep their own colors.
|
|
138
|
+
static func decorate(_ image: UIImage, tinted: Bool) -> UIImage {
|
|
139
|
+
image.withRenderingMode(tinted ? .alwaysTemplate : .alwaysOriginal)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// A native button: `UIButton` with a `UIButton.Configuration` chosen by the
|
|
4
|
+
/// variant, so it takes the system look of the iOS version it runs on.
|
|
5
|
+
@objcMembers
|
|
6
|
+
public final class PCButtonView: UIView {
|
|
7
|
+
// MARK: - Props (set from ObjC++)
|
|
8
|
+
|
|
9
|
+
public var label: String = "" {
|
|
10
|
+
didSet { if oldValue != label { applyConfiguration() } }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// "filled" | "tonal" | "outlined" | "text" | "elevated"
|
|
14
|
+
public var variant: String = "filled" {
|
|
15
|
+
didSet { if oldValue != variant { applyConfiguration() } }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// "xsmall" | "small" | "medium" | "large" | "xlarge"
|
|
19
|
+
public var size: String = "small" {
|
|
20
|
+
didSet { if oldValue != size { applyConfiguration() } }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// "" (UIKit default) | "round" | "square"
|
|
24
|
+
public var shape: String = "" {
|
|
25
|
+
didSet { if oldValue != shape { applyConfiguration() } }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// "enabled" | "disabled"
|
|
29
|
+
public var interactivity: String = "enabled" {
|
|
30
|
+
didSet { button.isEnabled = interactivity != "disabled" }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// Container color; nil keeps the configuration's color
|
|
34
|
+
public var containerColor: UIColor? {
|
|
35
|
+
didSet { applyConfiguration() }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Label and icon color; nil keeps the configuration's color
|
|
39
|
+
public var foregroundColor: UIColor? {
|
|
40
|
+
didSet { applyConfiguration() }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Label font; nil keeps the configuration's font
|
|
44
|
+
public var labelFont: UIFont? {
|
|
45
|
+
didSet { applyConfiguration() }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// Screen-reader label; empty uses the label
|
|
49
|
+
public var spokenLabel: String = "" {
|
|
50
|
+
didSet { button.accessibilityLabel = spokenLabel.isEmpty ? nil : spokenLabel }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// MARK: - Events back to ObjC++
|
|
54
|
+
|
|
55
|
+
public var onPress: (() -> Void)?
|
|
56
|
+
|
|
57
|
+
/// Called when content changed after layout (an icon finished loading),
|
|
58
|
+
/// so the Fabric measurement can be refreshed.
|
|
59
|
+
public var onNeedsRemeasure: (() -> Void)?
|
|
60
|
+
|
|
61
|
+
// MARK: - Internal
|
|
62
|
+
|
|
63
|
+
private let button = UIButton(type: .system)
|
|
64
|
+
private var icon = PCButtonSupport.Icon.none
|
|
65
|
+
private var iconImage: UIImage?
|
|
66
|
+
|
|
67
|
+
/// Bumped on every icon change so late image loads can't apply a stale icon.
|
|
68
|
+
private var iconGeneration = 0
|
|
69
|
+
|
|
70
|
+
// MARK: - Init
|
|
71
|
+
|
|
72
|
+
public override init(frame: CGRect) {
|
|
73
|
+
super.init(frame: frame)
|
|
74
|
+
setup()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public required init?(coder: NSCoder) {
|
|
78
|
+
super.init(coder: coder)
|
|
79
|
+
setup()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private func setup() {
|
|
83
|
+
button.translatesAutoresizingMaskIntoConstraints = false
|
|
84
|
+
addSubview(button)
|
|
85
|
+
|
|
86
|
+
NSLayoutConstraint.activate([
|
|
87
|
+
button.topAnchor.constraint(equalTo: topAnchor),
|
|
88
|
+
button.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
89
|
+
button.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
90
|
+
button.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
91
|
+
])
|
|
92
|
+
|
|
93
|
+
button.addTarget(self, action: #selector(pressed), for: .touchUpInside)
|
|
94
|
+
applyConfiguration()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@objc private func pressed() {
|
|
98
|
+
onPress?()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// MARK: - Props handling
|
|
102
|
+
|
|
103
|
+
/// Sets the icon from the flat spec fields. Images that are still loading
|
|
104
|
+
/// apply once they arrive.
|
|
105
|
+
public func setIcon(type: String, name: String, uri: String, scale: CGFloat, tinted: Bool) {
|
|
106
|
+
let next = PCButtonSupport.Icon(type: type, name: name, uri: uri, scale: scale, tinted: tinted)
|
|
107
|
+
guard next != icon else { return }
|
|
108
|
+
icon = next
|
|
109
|
+
iconGeneration += 1
|
|
110
|
+
let generation = iconGeneration
|
|
111
|
+
|
|
112
|
+
iconImage = PCButtonSupport.image(for: next) { [weak self] image in
|
|
113
|
+
guard let self, self.iconGeneration == generation else { return }
|
|
114
|
+
self.iconImage = image
|
|
115
|
+
self.applyConfiguration()
|
|
116
|
+
self.onNeedsRemeasure?()
|
|
117
|
+
}
|
|
118
|
+
applyConfiguration()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private func applyConfiguration() {
|
|
122
|
+
button.configuration = PCButtonSupport.makeConfiguration(
|
|
123
|
+
variant: variant,
|
|
124
|
+
selected: false,
|
|
125
|
+
size: size,
|
|
126
|
+
shape: shape,
|
|
127
|
+
label: label,
|
|
128
|
+
image: iconImage,
|
|
129
|
+
containerColor: containerColor,
|
|
130
|
+
foregroundColor: foregroundColor,
|
|
131
|
+
font: labelFont
|
|
132
|
+
)
|
|
133
|
+
invalidateIntrinsicContentSize()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// MARK: - Sizing
|
|
137
|
+
|
|
138
|
+
public override var intrinsicContentSize: CGSize {
|
|
139
|
+
button.intrinsicContentSize
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public override func sizeThatFits(_ size: CGSize) -> CGSize {
|
|
143
|
+
button.sizeThatFits(size)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/// Called by the measuring pipeline to get the size for Yoga layout: the
|
|
147
|
+
/// button's natural size, or its height at the given width.
|
|
148
|
+
@objc public func sizeForLayout(withConstrainedTo constrainedSize: CGSize) -> CGSize {
|
|
149
|
+
let fitted = button.sizeThatFits(
|
|
150
|
+
CGSize(width: constrainedSize.width > 0 ? constrainedSize.width : .greatestFiniteMagnitude,
|
|
151
|
+
height: .greatestFiniteMagnitude)
|
|
152
|
+
)
|
|
153
|
+
return CGSize(width: ceil(fitted.width), height: ceil(fitted.height))
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// PCFloatingToolbar.mm
|
|
2
|
+
//
|
|
3
|
+
// A floating toolbar: a capsule of Liquid Glass on iOS 26 (a blur material
|
|
4
|
+
// with a soft shadow on earlier versions) hosting the React children.
|
|
5
|
+
|
|
6
|
+
#import "PCFloatingToolbar.h"
|
|
7
|
+
|
|
8
|
+
#import <React/RCTComponentViewFactory.h>
|
|
9
|
+
#import <React/RCTConversions.h>
|
|
10
|
+
#import <React/RCTFabricComponentsPlugins.h>
|
|
11
|
+
|
|
12
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
|
|
13
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
|
|
14
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/Props.h>
|
|
15
|
+
|
|
16
|
+
#if __has_include(<PlatformComponents/PlatformComponents-Swift.h>)
|
|
17
|
+
#import <PlatformComponents/PlatformComponents-Swift.h>
|
|
18
|
+
#else
|
|
19
|
+
#import "PlatformComponents-Swift.h"
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
using namespace facebook::react;
|
|
23
|
+
|
|
24
|
+
@implementation PCFloatingToolbar {
|
|
25
|
+
PCFloatingToolbarView *_view;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
29
|
+
return concreteComponentDescriptorProvider<PCFloatingToolbarComponentDescriptor>();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
33
|
+
if (self = [super initWithFrame:frame]) {
|
|
34
|
+
_view = [[PCFloatingToolbarView alloc] initWithFrame:self.bounds];
|
|
35
|
+
_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
|
36
|
+
[self addSubview:_view];
|
|
37
|
+
}
|
|
38
|
+
return self;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Mount children into the material's contentView
|
|
42
|
+
- (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
43
|
+
[_view.contentView insertSubview:childComponentView atIndex:index];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
|
|
47
|
+
[childComponentView removeFromSuperview];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (void)updateProps:(Props::Shared const &)props
|
|
51
|
+
oldProps:(Props::Shared const &)oldProps {
|
|
52
|
+
const auto &newProps = *std::static_pointer_cast<const PCFloatingToolbarProps>(props);
|
|
53
|
+
const auto prevProps = std::static_pointer_cast<const PCFloatingToolbarProps>(oldProps);
|
|
54
|
+
|
|
55
|
+
// color -> material tint (SharedColor, already processed by React Native)
|
|
56
|
+
if (!prevProps || newProps.color != prevProps->color) {
|
|
57
|
+
_view.tintUIColor = RCTUIColorFromSharedColor(newProps.color);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ios.effect: "regular" | "clear"
|
|
61
|
+
const auto &newIos = newProps.ios;
|
|
62
|
+
const auto &oldIos = prevProps ? prevProps->ios : PCFloatingToolbarIosStruct{};
|
|
63
|
+
if (!prevProps || newIos.effect != oldIos.effect) {
|
|
64
|
+
_view.effectStyle = newIos.effect == "clear" ? @"clear" : @"regular";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// android.variant: Android only
|
|
68
|
+
|
|
69
|
+
[super updateProps:props oldProps:oldProps];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@end
|
|
73
|
+
|
|
74
|
+
Class<RCTComponentViewProtocol> PCFloatingToolbarCls(void) {
|
|
75
|
+
return PCFloatingToolbar.class;
|
|
76
|
+
}
|