react-native-platform-components 0.6.1 → 0.7.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 +153 -44
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +241 -0
- package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +105 -0
- package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +1 -0
- package/ios/PCDatePickerView.swift +16 -13
- package/ios/PCSegmentedControl.h +10 -0
- package/ios/PCSegmentedControl.mm +194 -0
- package/ios/PCSegmentedControl.swift +200 -0
- package/lib/commonjs/SegmentedControl.js +93 -0
- package/lib/commonjs/SegmentedControl.js.map +1 -0
- package/lib/commonjs/SegmentedControlNativeComponent.ts +79 -0
- package/lib/commonjs/index.js +11 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/SegmentedControl.js +87 -0
- package/lib/module/SegmentedControl.js.map +1 -0
- package/lib/module/SegmentedControlNativeComponent.ts +79 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts +62 -0
- package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +63 -0
- package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/SegmentedControl.d.ts +62 -0
- package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -0
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +63 -0
- package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +1 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +4 -3
- package/react-native.config.js +1 -0
- package/shared/PCSegmentedControlComponentDescriptors-custom.h +22 -0
- package/shared/PCSegmentedControlShadowNode-custom.cpp +54 -0
- package/shared/PCSegmentedControlShadowNode-custom.h +56 -0
- package/shared/PCSegmentedControlState-custom.h +62 -0
- package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +1 -0
- package/src/SegmentedControl.tsx +178 -0
- package/src/SegmentedControlNativeComponent.ts +79 -0
- package/src/index.tsx +1 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// PCSegmentedControl.mm
|
|
2
|
+
|
|
3
|
+
#import "PCSegmentedControl.h"
|
|
4
|
+
|
|
5
|
+
#import <React/RCTComponentViewFactory.h>
|
|
6
|
+
#import <React/RCTConversions.h>
|
|
7
|
+
#import <React/RCTFabricComponentsPlugins.h>
|
|
8
|
+
|
|
9
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
|
|
10
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
|
|
11
|
+
#import <react/renderer/components/PlatformComponentsViewSpec/Props.h>
|
|
12
|
+
#import <react/renderer/core/LayoutPrimitives.h>
|
|
13
|
+
|
|
14
|
+
#if __has_include(<PlatformComponents/PlatformComponents-Swift.h>)
|
|
15
|
+
#import <PlatformComponents/PlatformComponents-Swift.h>
|
|
16
|
+
#else
|
|
17
|
+
#import "PlatformComponents-Swift.h"
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
#import "PCSegmentedControlComponentDescriptors-custom.h"
|
|
21
|
+
#import "PCSegmentedControlShadowNode-custom.h"
|
|
22
|
+
#import "PCSegmentedControlState-custom.h"
|
|
23
|
+
|
|
24
|
+
using namespace facebook::react;
|
|
25
|
+
|
|
26
|
+
namespace {
|
|
27
|
+
static inline bool SegmentsEqual(
|
|
28
|
+
const std::vector<facebook::react::PCSegmentedControlSegmentsStruct> &a,
|
|
29
|
+
const std::vector<facebook::react::PCSegmentedControlSegmentsStruct> &b) {
|
|
30
|
+
if (a.size() != b.size()) return false;
|
|
31
|
+
for (size_t i = 0; i < a.size(); i++) {
|
|
32
|
+
if (a[i].label != b[i].label) return false;
|
|
33
|
+
if (a[i].value != b[i].value) return false;
|
|
34
|
+
if (a[i].disabled != b[i].disabled) return false;
|
|
35
|
+
if (a[i].icon != b[i].icon) return false;
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
} // namespace
|
|
40
|
+
|
|
41
|
+
@interface PCSegmentedControl ()
|
|
42
|
+
|
|
43
|
+
- (void)updateMeasurements;
|
|
44
|
+
|
|
45
|
+
@end
|
|
46
|
+
|
|
47
|
+
@implementation PCSegmentedControl {
|
|
48
|
+
PCSegmentedControlView *_view;
|
|
49
|
+
MeasuringPCSegmentedControlShadowNode::ConcreteState::Shared _state;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
53
|
+
return concreteComponentDescriptorProvider<
|
|
54
|
+
MeasuringPCSegmentedControlComponentDescriptor>();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
58
|
+
if (self = [super initWithFrame:frame]) {
|
|
59
|
+
_view = [PCSegmentedControlView new];
|
|
60
|
+
self.contentView = _view;
|
|
61
|
+
|
|
62
|
+
__weak __typeof(self) weakSelf = self;
|
|
63
|
+
|
|
64
|
+
_view.onSelect = ^(NSInteger index, NSString *value) {
|
|
65
|
+
__typeof(self) strongSelf = weakSelf;
|
|
66
|
+
if (!strongSelf) return;
|
|
67
|
+
|
|
68
|
+
auto eventEmitter =
|
|
69
|
+
std::static_pointer_cast<const PCSegmentedControlEventEmitter>(
|
|
70
|
+
strongSelf->_eventEmitter);
|
|
71
|
+
if (!eventEmitter) return;
|
|
72
|
+
|
|
73
|
+
PCSegmentedControlEventEmitter::OnSelect payload = {
|
|
74
|
+
.index = (int)index,
|
|
75
|
+
.value = value.UTF8String,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
eventEmitter->onSelect(payload);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return self;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
- (void)updateProps:(Props::Shared const &)props
|
|
85
|
+
oldProps:(Props::Shared const &)oldProps {
|
|
86
|
+
const auto &newProps =
|
|
87
|
+
*std::static_pointer_cast<const PCSegmentedControlProps>(props);
|
|
88
|
+
const auto prevProps =
|
|
89
|
+
std::static_pointer_cast<const PCSegmentedControlProps>(oldProps);
|
|
90
|
+
|
|
91
|
+
// segments: [{label, value, disabled, icon}]
|
|
92
|
+
if (!prevProps || !SegmentsEqual(newProps.segments, prevProps->segments)) {
|
|
93
|
+
NSMutableArray *arr = [NSMutableArray new];
|
|
94
|
+
for (const auto &seg : newProps.segments) {
|
|
95
|
+
NSString *label = seg.label.empty()
|
|
96
|
+
? @""
|
|
97
|
+
: [NSString stringWithUTF8String:seg.label.c_str()];
|
|
98
|
+
NSString *value = seg.value.empty()
|
|
99
|
+
? @""
|
|
100
|
+
: [NSString stringWithUTF8String:seg.value.c_str()];
|
|
101
|
+
NSString *disabled = seg.disabled.empty()
|
|
102
|
+
? @"enabled"
|
|
103
|
+
: [NSString stringWithUTF8String:seg.disabled.c_str()];
|
|
104
|
+
NSString *icon = seg.icon.empty()
|
|
105
|
+
? @""
|
|
106
|
+
: [NSString stringWithUTF8String:seg.icon.c_str()];
|
|
107
|
+
[arr addObject:@{
|
|
108
|
+
@"label": label,
|
|
109
|
+
@"value": value,
|
|
110
|
+
@"disabled": disabled,
|
|
111
|
+
@"icon": icon
|
|
112
|
+
}];
|
|
113
|
+
}
|
|
114
|
+
_view.segments = arr;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// selectedValue (default "")
|
|
118
|
+
if (!prevProps || newProps.selectedValue != prevProps->selectedValue) {
|
|
119
|
+
if (!newProps.selectedValue.empty()) {
|
|
120
|
+
_view.selectedValue =
|
|
121
|
+
[NSString stringWithUTF8String:newProps.selectedValue.c_str()];
|
|
122
|
+
} else {
|
|
123
|
+
_view.selectedValue = @""; // sentinel for no selection
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// interactivity: "enabled" | "disabled"
|
|
128
|
+
if (!prevProps || newProps.interactivity != prevProps->interactivity) {
|
|
129
|
+
if (!newProps.interactivity.empty()) {
|
|
130
|
+
_view.interactivity =
|
|
131
|
+
[NSString stringWithUTF8String:newProps.interactivity.c_str()];
|
|
132
|
+
} else {
|
|
133
|
+
_view.interactivity = @"enabled";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// iOS-specific props
|
|
138
|
+
const auto &newIos = newProps.ios;
|
|
139
|
+
const auto &oldIos =
|
|
140
|
+
prevProps ? prevProps->ios : PCSegmentedControlIosStruct{};
|
|
141
|
+
|
|
142
|
+
if (!prevProps || newIos.momentary != oldIos.momentary) {
|
|
143
|
+
_view.momentary = (newIos.momentary == "true");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!prevProps || newIos.apportionsSegmentWidthsByContent != oldIos.apportionsSegmentWidthsByContent) {
|
|
147
|
+
_view.apportionsSegmentWidthsByContent = (newIos.apportionsSegmentWidthsByContent == "true");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!prevProps || newIos.selectedSegmentTintColor != oldIos.selectedSegmentTintColor) {
|
|
151
|
+
if (!newIos.selectedSegmentTintColor.empty()) {
|
|
152
|
+
_view.selectedSegmentTintColor =
|
|
153
|
+
[NSString stringWithUTF8String:newIos.selectedSegmentTintColor.c_str()];
|
|
154
|
+
} else {
|
|
155
|
+
_view.selectedSegmentTintColor = nil;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
[super updateProps:props oldProps:oldProps];
|
|
160
|
+
|
|
161
|
+
// Update measurements when props change that affect layout
|
|
162
|
+
[self updateMeasurements];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
#pragma mark - State (Measuring)
|
|
166
|
+
|
|
167
|
+
- (void)updateState:(const State::Shared &)state
|
|
168
|
+
oldState:(const State::Shared &)oldState {
|
|
169
|
+
_state = std::static_pointer_cast<
|
|
170
|
+
const MeasuringPCSegmentedControlShadowNode::ConcreteState>(state);
|
|
171
|
+
|
|
172
|
+
if (oldState == nullptr) {
|
|
173
|
+
// First time: compute initial size.
|
|
174
|
+
[self updateMeasurements];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[super updateState:state oldState:oldState];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
- (void)updateMeasurements {
|
|
181
|
+
if (_state == nullptr)
|
|
182
|
+
return;
|
|
183
|
+
|
|
184
|
+
// Use the real width Yoga gave us
|
|
185
|
+
const CGFloat w = self.bounds.size.width > 1 ? self.bounds.size.width : 320;
|
|
186
|
+
|
|
187
|
+
CGSize size = [_view sizeForLayoutWithConstrainedTo:CGSizeMake(w, 0)];
|
|
188
|
+
|
|
189
|
+
PCSegmentedControlStateFrameSize next;
|
|
190
|
+
next.frameSize = {(Float)size.width, (Float)size.height};
|
|
191
|
+
_state->updateState(std::move(next));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@end
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
// MARK: - Segment model (bridged from ObjC++ as dictionaries)
|
|
4
|
+
|
|
5
|
+
struct PCSegmentedControlSegment {
|
|
6
|
+
let label: String
|
|
7
|
+
let value: String
|
|
8
|
+
let disabled: Bool
|
|
9
|
+
let icon: String
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@objcMembers
|
|
13
|
+
public final class PCSegmentedControlView: UIControl {
|
|
14
|
+
// MARK: - Props (set from ObjC++)
|
|
15
|
+
|
|
16
|
+
/// ObjC++ sets this as an array of dictionaries: [{label, value, disabled, icon}]
|
|
17
|
+
public var segments: [Any] = [] { didSet { rebuildControl() } }
|
|
18
|
+
|
|
19
|
+
/// Controlled selection by value. "" = no selection.
|
|
20
|
+
public var selectedValue: String = "" { didSet { updateSelection() } }
|
|
21
|
+
|
|
22
|
+
/// "enabled" | "disabled"
|
|
23
|
+
public var interactivity: String = "enabled" { didSet { updateEnabled() } }
|
|
24
|
+
|
|
25
|
+
/// iOS-specific: momentary mode (segment springs back after touch)
|
|
26
|
+
public var momentary: Bool = false { didSet { control.isMomentary = momentary } }
|
|
27
|
+
|
|
28
|
+
/// iOS-specific: segment widths proportional to content
|
|
29
|
+
public var apportionsSegmentWidthsByContent: Bool = false {
|
|
30
|
+
didSet { control.apportionsSegmentWidthsByContent = apportionsSegmentWidthsByContent }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// iOS-specific: selected segment tint color (hex string)
|
|
34
|
+
public var selectedSegmentTintColor: String? { didSet { updateTintColor() } }
|
|
35
|
+
|
|
36
|
+
// MARK: - Events back to ObjC++
|
|
37
|
+
|
|
38
|
+
public var onSelect: ((Int, String) -> Void)? // (index, value)
|
|
39
|
+
|
|
40
|
+
// MARK: - Internal
|
|
41
|
+
|
|
42
|
+
private let control = UISegmentedControl()
|
|
43
|
+
private var parsedSegments: [PCSegmentedControlSegment] = []
|
|
44
|
+
|
|
45
|
+
// MARK: - Init
|
|
46
|
+
|
|
47
|
+
public override init(frame: CGRect) {
|
|
48
|
+
super.init(frame: frame)
|
|
49
|
+
setup()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public required init?(coder: NSCoder) {
|
|
53
|
+
super.init(coder: coder)
|
|
54
|
+
setup()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private func setup() {
|
|
58
|
+
control.translatesAutoresizingMaskIntoConstraints = false
|
|
59
|
+
addSubview(control)
|
|
60
|
+
|
|
61
|
+
NSLayoutConstraint.activate([
|
|
62
|
+
control.topAnchor.constraint(equalTo: topAnchor),
|
|
63
|
+
control.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
64
|
+
control.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
65
|
+
control.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
control.addTarget(self, action: #selector(valueChanged), for: .valueChanged)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@objc private func valueChanged() {
|
|
72
|
+
let index = control.selectedSegmentIndex
|
|
73
|
+
guard index != UISegmentedControl.noSegment,
|
|
74
|
+
index >= 0, index < parsedSegments.count else { return }
|
|
75
|
+
|
|
76
|
+
let segment = parsedSegments[index]
|
|
77
|
+
onSelect?(index, segment.value)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MARK: - Props handling
|
|
81
|
+
|
|
82
|
+
private func rebuildControl() {
|
|
83
|
+
parsedSegments = segments.compactMap { any in
|
|
84
|
+
guard let dict = any as? [String: Any] else { return nil }
|
|
85
|
+
let label = (dict["label"] as? String) ?? ""
|
|
86
|
+
let value = (dict["value"] as? String) ?? ""
|
|
87
|
+
let disabled = (dict["disabled"] as? String) == "disabled"
|
|
88
|
+
let icon = (dict["icon"] as? String) ?? ""
|
|
89
|
+
return PCSegmentedControlSegment(
|
|
90
|
+
label: label,
|
|
91
|
+
value: value,
|
|
92
|
+
disabled: disabled,
|
|
93
|
+
icon: icon
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
control.removeAllSegments()
|
|
98
|
+
|
|
99
|
+
for (index, segment) in parsedSegments.enumerated() {
|
|
100
|
+
// Try to use SF Symbol icon if available
|
|
101
|
+
if !segment.icon.isEmpty,
|
|
102
|
+
let sfImage = UIImage(systemName: segment.icon) {
|
|
103
|
+
control.insertSegment(with: sfImage, at: index, animated: false)
|
|
104
|
+
} else {
|
|
105
|
+
control.insertSegment(withTitle: segment.label, at: index, animated: false)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Set enabled state for this segment
|
|
109
|
+
control.setEnabled(!segment.disabled, forSegmentAt: index)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
updateSelection()
|
|
113
|
+
invalidateIntrinsicContentSize()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private func updateSelection() {
|
|
117
|
+
if selectedValue.isEmpty {
|
|
118
|
+
control.selectedSegmentIndex = UISegmentedControl.noSegment
|
|
119
|
+
} else if let index = parsedSegments.firstIndex(where: { $0.value == selectedValue }) {
|
|
120
|
+
control.selectedSegmentIndex = index
|
|
121
|
+
} else {
|
|
122
|
+
control.selectedSegmentIndex = UISegmentedControl.noSegment
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private func updateEnabled() {
|
|
127
|
+
let enabled = interactivity != "disabled"
|
|
128
|
+
control.isEnabled = enabled
|
|
129
|
+
alpha = enabled ? 1.0 : 0.5
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private func updateTintColor() {
|
|
133
|
+
if let colorString = selectedSegmentTintColor, !colorString.isEmpty {
|
|
134
|
+
control.selectedSegmentTintColor = UIColor(hex: colorString)
|
|
135
|
+
} else {
|
|
136
|
+
control.selectedSegmentTintColor = nil
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// MARK: - Sizing
|
|
141
|
+
|
|
142
|
+
public override func sizeThatFits(_ size: CGSize) -> CGSize {
|
|
143
|
+
let fitted = control.sizeThatFits(CGSize(width: size.width, height: .greatestFiniteMagnitude))
|
|
144
|
+
return CGSize(
|
|
145
|
+
width: size.width > 0 ? size.width : fitted.width,
|
|
146
|
+
height: max(PCConstants.minTouchTargetHeight, fitted.height)
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public override var intrinsicContentSize: CGSize {
|
|
151
|
+
let fitted = control.intrinsicContentSize
|
|
152
|
+
return CGSize(
|
|
153
|
+
width: fitted.width,
|
|
154
|
+
height: max(PCConstants.minTouchTargetHeight, fitted.height)
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// Called by the measuring pipeline to get the size for Yoga layout.
|
|
159
|
+
@objc public func sizeForLayout(withConstrainedTo constrainedSize: CGSize) -> CGSize {
|
|
160
|
+
let fitted = control.sizeThatFits(
|
|
161
|
+
CGSize(width: constrainedSize.width > 0 ? constrainedSize.width : .greatestFiniteMagnitude,
|
|
162
|
+
height: .greatestFiniteMagnitude)
|
|
163
|
+
)
|
|
164
|
+
return CGSize(
|
|
165
|
+
width: constrainedSize.width > 0 ? constrainedSize.width : fitted.width,
|
|
166
|
+
height: max(PCConstants.minTouchTargetHeight, fitted.height)
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// MARK: - UIColor hex extension
|
|
172
|
+
|
|
173
|
+
private extension UIColor {
|
|
174
|
+
convenience init?(hex: String) {
|
|
175
|
+
var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
176
|
+
hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
|
|
177
|
+
|
|
178
|
+
var rgb: UInt64 = 0
|
|
179
|
+
guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil }
|
|
180
|
+
|
|
181
|
+
let length = hexSanitized.count
|
|
182
|
+
if length == 6 {
|
|
183
|
+
self.init(
|
|
184
|
+
red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
|
|
185
|
+
green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
|
|
186
|
+
blue: CGFloat(rgb & 0x0000FF) / 255.0,
|
|
187
|
+
alpha: 1.0
|
|
188
|
+
)
|
|
189
|
+
} else if length == 8 {
|
|
190
|
+
self.init(
|
|
191
|
+
red: CGFloat((rgb & 0xFF000000) >> 24) / 255.0,
|
|
192
|
+
green: CGFloat((rgb & 0x00FF0000) >> 16) / 255.0,
|
|
193
|
+
blue: CGFloat((rgb & 0x0000FF00) >> 8) / 255.0,
|
|
194
|
+
alpha: CGFloat(rgb & 0x000000FF) / 255.0
|
|
195
|
+
)
|
|
196
|
+
} else {
|
|
197
|
+
return nil
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SegmentedControl = SegmentedControl;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _SegmentedControlNativeComponent = _interopRequireDefault(require("./SegmentedControlNativeComponent"));
|
|
10
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
13
|
+
// SegmentedControl.tsx
|
|
14
|
+
|
|
15
|
+
// Android: Minimum height to ensure visibility.
|
|
16
|
+
// Fabric's shadow node measurement isn't being called on initial render,
|
|
17
|
+
// so we apply a minHeight that matches Material design touch target guidelines.
|
|
18
|
+
const ANDROID_MIN_HEIGHT = 48;
|
|
19
|
+
function normalizeSelectedValue(selected) {
|
|
20
|
+
return selected ?? '';
|
|
21
|
+
}
|
|
22
|
+
function SegmentedControl(props) {
|
|
23
|
+
const {
|
|
24
|
+
style,
|
|
25
|
+
segments,
|
|
26
|
+
selectedValue,
|
|
27
|
+
disabled,
|
|
28
|
+
onSelect,
|
|
29
|
+
ios,
|
|
30
|
+
android,
|
|
31
|
+
...viewProps
|
|
32
|
+
} = props;
|
|
33
|
+
|
|
34
|
+
// Normalize segments for native
|
|
35
|
+
const nativeSegments = (0, _react.useMemo)(() => {
|
|
36
|
+
return segments.map(seg => ({
|
|
37
|
+
label: seg.label,
|
|
38
|
+
value: seg.value,
|
|
39
|
+
disabled: seg.disabled ? 'disabled' : 'enabled',
|
|
40
|
+
icon: seg.icon ?? ''
|
|
41
|
+
}));
|
|
42
|
+
}, [segments]);
|
|
43
|
+
const selectedData = (0, _react.useMemo)(() => normalizeSelectedValue(selectedValue), [selectedValue]);
|
|
44
|
+
const handleSelect = (0, _react.useCallback)(e => {
|
|
45
|
+
const {
|
|
46
|
+
index,
|
|
47
|
+
value
|
|
48
|
+
} = e.nativeEvent;
|
|
49
|
+
onSelect?.(value, index);
|
|
50
|
+
}, [onSelect]);
|
|
51
|
+
|
|
52
|
+
// Normalize iOS props to native string format
|
|
53
|
+
const nativeIos = (0, _react.useMemo)(() => {
|
|
54
|
+
if (!ios) return undefined;
|
|
55
|
+
return {
|
|
56
|
+
momentary: ios.momentary ? 'true' : 'false',
|
|
57
|
+
apportionsSegmentWidthsByContent: ios.apportionsSegmentWidthsByContent ? 'true' : 'false',
|
|
58
|
+
selectedSegmentTintColor: ios.selectedSegmentTintColor ?? ''
|
|
59
|
+
};
|
|
60
|
+
}, [ios]);
|
|
61
|
+
|
|
62
|
+
// Normalize Android props
|
|
63
|
+
const nativeAndroid = (0, _react.useMemo)(() => {
|
|
64
|
+
if (!android) return undefined;
|
|
65
|
+
return {
|
|
66
|
+
selectionRequired: android.selectionRequired ? 'true' : 'false'
|
|
67
|
+
};
|
|
68
|
+
}, [android]);
|
|
69
|
+
|
|
70
|
+
// Merge user style with Android minHeight default
|
|
71
|
+
const mergedStyle = (0, _react.useMemo)(() => {
|
|
72
|
+
if (_reactNative.Platform.OS === 'android') {
|
|
73
|
+
return [styles.androidDefault, style];
|
|
74
|
+
}
|
|
75
|
+
return style;
|
|
76
|
+
}, [style]);
|
|
77
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_SegmentedControlNativeComponent.default, {
|
|
78
|
+
style: mergedStyle,
|
|
79
|
+
segments: nativeSegments,
|
|
80
|
+
selectedValue: selectedData,
|
|
81
|
+
interactivity: disabled ? 'disabled' : 'enabled',
|
|
82
|
+
onSelect: onSelect ? handleSelect : undefined,
|
|
83
|
+
ios: nativeIos,
|
|
84
|
+
android: nativeAndroid,
|
|
85
|
+
...viewProps
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const styles = _reactNative.StyleSheet.create({
|
|
89
|
+
androidDefault: {
|
|
90
|
+
minHeight: ANDROID_MIN_HEIGHT
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=SegmentedControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_SegmentedControlNativeComponent","_interopRequireDefault","_jsxRuntime","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ANDROID_MIN_HEIGHT","normalizeSelectedValue","selected","SegmentedControl","props","style","segments","selectedValue","disabled","onSelect","ios","android","viewProps","nativeSegments","useMemo","map","seg","label","value","icon","selectedData","handleSelect","useCallback","index","nativeEvent","nativeIos","undefined","momentary","apportionsSegmentWidthsByContent","selectedSegmentTintColor","nativeAndroid","selectionRequired","mergedStyle","Platform","OS","styles","androidDefault","jsx","interactivity","StyleSheet","create","minHeight"],"sourceRoot":"../../src","sources":["SegmentedControl.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// SegmentedControlNativeComponent.ts
|
|
2
|
+
import type { CodegenTypes, ViewProps } from 'react-native';
|
|
3
|
+
import { codegenNativeComponent } from 'react-native';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A single segment in the control.
|
|
7
|
+
*/
|
|
8
|
+
export type SegmentedControlSegment = Readonly<{
|
|
9
|
+
label: string;
|
|
10
|
+
value: string;
|
|
11
|
+
disabled: string; // 'enabled' | 'disabled'
|
|
12
|
+
icon: string; // SF Symbol (iOS) or drawable name (Android), empty = none
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Event emitted when the user selects a segment.
|
|
17
|
+
*/
|
|
18
|
+
export type SegmentedControlSelectEvent = Readonly<{
|
|
19
|
+
/** Selected segment index */
|
|
20
|
+
index: CodegenTypes.Int32;
|
|
21
|
+
|
|
22
|
+
/** Selected segment value */
|
|
23
|
+
value: string;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
/** Interactivity state (no booleans). */
|
|
27
|
+
export type SegmentedControlInteractivity = 'enabled' | 'disabled';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* iOS-specific configuration.
|
|
31
|
+
*/
|
|
32
|
+
export type IOSProps = Readonly<{
|
|
33
|
+
/** Momentary mode: segment springs back after touch */
|
|
34
|
+
momentary?: string; // 'true' | 'false'
|
|
35
|
+
|
|
36
|
+
/** Whether segment widths are proportional to content */
|
|
37
|
+
apportionsSegmentWidthsByContent?: string; // 'true' | 'false'
|
|
38
|
+
|
|
39
|
+
/** Selected segment tint color (hex string) */
|
|
40
|
+
selectedSegmentTintColor?: string;
|
|
41
|
+
}>;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Android-specific configuration.
|
|
45
|
+
*/
|
|
46
|
+
export type AndroidProps = Readonly<{
|
|
47
|
+
/** Whether one segment must always be selected */
|
|
48
|
+
selectionRequired?: string; // 'true' | 'false'
|
|
49
|
+
}>;
|
|
50
|
+
|
|
51
|
+
export interface SegmentedControlProps extends ViewProps {
|
|
52
|
+
/**
|
|
53
|
+
* Segments to display.
|
|
54
|
+
*/
|
|
55
|
+
segments: ReadonlyArray<SegmentedControlSegment>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Controlled selection by `value`.
|
|
59
|
+
* Empty string means "no selection".
|
|
60
|
+
*/
|
|
61
|
+
selectedValue?: CodegenTypes.WithDefault<string, ''>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Enabled / disabled state.
|
|
65
|
+
*/
|
|
66
|
+
interactivity?: string; // SegmentedControlInteractivity
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Fired when the user selects a segment.
|
|
70
|
+
*/
|
|
71
|
+
onSelect?: CodegenTypes.BubblingEventHandler<SegmentedControlSelectEvent>;
|
|
72
|
+
|
|
73
|
+
ios?: IOSProps;
|
|
74
|
+
android?: AndroidProps;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default codegenNativeComponent<SegmentedControlProps>(
|
|
78
|
+
'PCSegmentedControl'
|
|
79
|
+
);
|
package/lib/commonjs/index.js
CHANGED
|
@@ -36,6 +36,17 @@ Object.keys(_ContextMenu).forEach(function (key) {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
});
|
|
39
|
+
var _SegmentedControl = require("./SegmentedControl");
|
|
40
|
+
Object.keys(_SegmentedControl).forEach(function (key) {
|
|
41
|
+
if (key === "default" || key === "__esModule") return;
|
|
42
|
+
if (key in exports && exports[key] === _SegmentedControl[key]) return;
|
|
43
|
+
Object.defineProperty(exports, key, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return _SegmentedControl[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
39
50
|
var _sharedTypes = require("./sharedTypes");
|
|
40
51
|
Object.keys(_sharedTypes).forEach(function (key) {
|
|
41
52
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_DatePicker","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_SelectionMenu","_ContextMenu","_sharedTypes"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,WAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,WAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,WAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,cAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,cAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,cAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,cAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,YAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,YAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,YAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,YAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,
|
|
1
|
+
{"version":3,"names":["_DatePicker","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_SelectionMenu","_ContextMenu","_SegmentedControl","_sharedTypes"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,WAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,WAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,WAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,cAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,cAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,cAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,cAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,YAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,YAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,YAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,YAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,iBAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,iBAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,iBAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,iBAAA,CAAAP,GAAA;IAAA;EAAA;AAAA;AACA,IAAAQ,YAAA,GAAAZ,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAU,YAAA,EAAAT,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,YAAA,CAAAR,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAI,YAAA,CAAAR,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// SegmentedControl.tsx
|
|
4
|
+
import React, { useCallback, useMemo } from 'react';
|
|
5
|
+
import { Platform, StyleSheet } from 'react-native';
|
|
6
|
+
import NativeSegmentedControl from './SegmentedControlNativeComponent';
|
|
7
|
+
|
|
8
|
+
// Android: Minimum height to ensure visibility.
|
|
9
|
+
// Fabric's shadow node measurement isn't being called on initial render,
|
|
10
|
+
// so we apply a minHeight that matches Material design touch target guidelines.
|
|
11
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
const ANDROID_MIN_HEIGHT = 48;
|
|
13
|
+
function normalizeSelectedValue(selected) {
|
|
14
|
+
return selected ?? '';
|
|
15
|
+
}
|
|
16
|
+
export function SegmentedControl(props) {
|
|
17
|
+
const {
|
|
18
|
+
style,
|
|
19
|
+
segments,
|
|
20
|
+
selectedValue,
|
|
21
|
+
disabled,
|
|
22
|
+
onSelect,
|
|
23
|
+
ios,
|
|
24
|
+
android,
|
|
25
|
+
...viewProps
|
|
26
|
+
} = props;
|
|
27
|
+
|
|
28
|
+
// Normalize segments for native
|
|
29
|
+
const nativeSegments = useMemo(() => {
|
|
30
|
+
return segments.map(seg => ({
|
|
31
|
+
label: seg.label,
|
|
32
|
+
value: seg.value,
|
|
33
|
+
disabled: seg.disabled ? 'disabled' : 'enabled',
|
|
34
|
+
icon: seg.icon ?? ''
|
|
35
|
+
}));
|
|
36
|
+
}, [segments]);
|
|
37
|
+
const selectedData = useMemo(() => normalizeSelectedValue(selectedValue), [selectedValue]);
|
|
38
|
+
const handleSelect = useCallback(e => {
|
|
39
|
+
const {
|
|
40
|
+
index,
|
|
41
|
+
value
|
|
42
|
+
} = e.nativeEvent;
|
|
43
|
+
onSelect?.(value, index);
|
|
44
|
+
}, [onSelect]);
|
|
45
|
+
|
|
46
|
+
// Normalize iOS props to native string format
|
|
47
|
+
const nativeIos = useMemo(() => {
|
|
48
|
+
if (!ios) return undefined;
|
|
49
|
+
return {
|
|
50
|
+
momentary: ios.momentary ? 'true' : 'false',
|
|
51
|
+
apportionsSegmentWidthsByContent: ios.apportionsSegmentWidthsByContent ? 'true' : 'false',
|
|
52
|
+
selectedSegmentTintColor: ios.selectedSegmentTintColor ?? ''
|
|
53
|
+
};
|
|
54
|
+
}, [ios]);
|
|
55
|
+
|
|
56
|
+
// Normalize Android props
|
|
57
|
+
const nativeAndroid = useMemo(() => {
|
|
58
|
+
if (!android) return undefined;
|
|
59
|
+
return {
|
|
60
|
+
selectionRequired: android.selectionRequired ? 'true' : 'false'
|
|
61
|
+
};
|
|
62
|
+
}, [android]);
|
|
63
|
+
|
|
64
|
+
// Merge user style with Android minHeight default
|
|
65
|
+
const mergedStyle = useMemo(() => {
|
|
66
|
+
if (Platform.OS === 'android') {
|
|
67
|
+
return [styles.androidDefault, style];
|
|
68
|
+
}
|
|
69
|
+
return style;
|
|
70
|
+
}, [style]);
|
|
71
|
+
return /*#__PURE__*/_jsx(NativeSegmentedControl, {
|
|
72
|
+
style: mergedStyle,
|
|
73
|
+
segments: nativeSegments,
|
|
74
|
+
selectedValue: selectedData,
|
|
75
|
+
interactivity: disabled ? 'disabled' : 'enabled',
|
|
76
|
+
onSelect: onSelect ? handleSelect : undefined,
|
|
77
|
+
ios: nativeIos,
|
|
78
|
+
android: nativeAndroid,
|
|
79
|
+
...viewProps
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const styles = StyleSheet.create({
|
|
83
|
+
androidDefault: {
|
|
84
|
+
minHeight: ANDROID_MIN_HEIGHT
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
//# sourceMappingURL=SegmentedControl.js.map
|