Skip to content

Commit b19650b

Browse files
committed
feat(picker): add configuration support for dynamic option generation and update computed options handling
1 parent 28c3c65 commit b19650b

File tree

3 files changed

+76
-7
lines changed

3 files changed

+76
-7
lines changed

ios/components/Picker/PickerProps.swift

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import SwiftUI
44

55
public final class PickerProps: ObservableObject, Decodable {
66
@Published var options: [PickerOption] = []
7+
@Published var config: PickerConfig?
78
@Published var selection: String = ""
89
@Published var label: String = ""
910
@Published var pickerStyle: PickerStyle = .default
@@ -20,6 +21,36 @@ public final class PickerProps: ObservableObject, Decodable {
2021
var id: String { value } // Use value as the unique identifier
2122
}
2223

24+
struct PickerConfig: Decodable, Hashable {
25+
let min: Int
26+
let max: Int
27+
let step: Int
28+
let prefix: String
29+
let suffix: String
30+
31+
// Generate options based on numeric configuration
32+
func generateOptions() -> [PickerOption] {
33+
var options: [PickerOption] = []
34+
var current = min
35+
36+
while current <= max {
37+
let valueString = "\(current)"
38+
let labelString = "\(prefix)\(current)\(suffix)"
39+
options.append(PickerOption(label: labelString, value: valueString))
40+
current += step
41+
}
42+
43+
return options
44+
}
45+
}
46+
47+
var computedOptions: [PickerOption] {
48+
if config != nil {
49+
return config!.generateOptions()
50+
}
51+
return options
52+
}
53+
2354
enum PickerStyle: String, CaseIterable {
2455
case `default`
2556
case menu
@@ -46,7 +77,7 @@ public final class PickerProps: ObservableObject, Decodable {
4677

4778
// Coding keys for decoding
4879
enum CodingKeys: String, CodingKey, CaseIterable {
49-
case label, selection, options, pickerStyle, disabled, style
80+
case label, selection, options, config, pickerStyle, disabled, style
5081
}
5182

5283
// Decodable initializer
@@ -55,6 +86,7 @@ public final class PickerProps: ObservableObject, Decodable {
5586
label = try container.decodeIfPresent(String.self, forKey: .label) ?? ""
5687
selection = try container.decodeIfPresent(String.self, forKey: .selection) ?? ""
5788
options = try container.decodeIfPresent([PickerOption].self, forKey: .options) ?? []
89+
config = try container.decodeIfPresent(PickerConfig.self, forKey: .config)
5890
if let styleString = try container.decodeIfPresent(String.self, forKey: .pickerStyle),
5991
let style = PickerStyle(rawValue: styleString)
6092
{
@@ -71,6 +103,7 @@ public final class PickerProps: ObservableObject, Decodable {
71103
public func merge(from other: PickerProps) {
72104
options = other.options
73105
selection = other.selection
106+
config = other.config
74107
label = other.label
75108
pickerStyle = other.pickerStyle
76109
disabled = other.disabled

ios/components/Picker/PickerView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public struct PickerView: View {
3131
private func pickerContent() -> some View {
3232
props.pickerStyle.applyStyle(
3333
Picker(props.label, selection: $props.selection) {
34-
ForEach(props.options) { option in
34+
ForEach(props.computedOptions) { option in
3535
Text(option.label).tag(option.value)
3636
}
3737
}

src/components/Picker.tsx

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,25 @@ export type NativePickerStyle = "default" | "inline" | "menu" | "segmented" | "w
99

1010
export type NativePickerOption<T extends string> = { value: T; label: string } | T;
1111

12+
export type NativePickerConfig = {
13+
min: number;
14+
max: number;
15+
step?: number;
16+
prefix?: string;
17+
suffix?: string;
18+
};
19+
20+
const DEFAULT_PICKER_CONFIG = {
21+
min: 0,
22+
max: 100,
23+
step: 1,
24+
prefix: "",
25+
suffix: "",
26+
} satisfies NativePickerConfig;
27+
1228
export type NativePickerProps<T extends string> = {
13-
options: readonly NativePickerOption<T>[];
29+
options?: readonly NativePickerOption<T>[];
30+
config?: NativePickerConfig;
1431
selection?: T;
1532
label?: string;
1633
pickerStyle?: NativePickerStyle;
@@ -24,6 +41,7 @@ export type NativePickerProps<T extends string> = {
2441
export const Picker = <T extends string>({
2542
selection,
2643
options,
44+
config,
2745
onChange: onChangeProp,
2846
onFocus,
2947
onBlur,
@@ -41,19 +59,37 @@ export const Picker = <T extends string>({
4159
);
4260

4361
const normalizedSelection = selection ? String(selection) : undefined;
62+
const normalizedConfig = useMemo(
63+
() =>
64+
config
65+
? {
66+
...DEFAULT_PICKER_CONFIG,
67+
...config,
68+
}
69+
: undefined,
70+
[config],
71+
);
4472
const normalizedOptions = useMemo(
4573
() =>
46-
options.length > 0 && typeof options[0] === "string"
47-
? options.map((value) => ({ value, label: value }))
48-
: options,
74+
options
75+
? options.length > 0 && typeof options[0] === "string"
76+
? options.map((value) => ({ value, label: value }))
77+
: options
78+
: [],
4979
[options],
5080
);
5181

5282
const normalizedStyles = useNormalizedStyles<NativeTextStyle>(style);
5383

5484
useSwiftUINode(
5585
"Picker",
56-
{ options: normalizedOptions, selection: normalizedSelection, style: normalizedStyles, ...otherProps },
86+
{
87+
selection: normalizedSelection,
88+
options: normalizedOptions,
89+
config: normalizedConfig,
90+
style: normalizedStyles,
91+
...otherProps,
92+
},
5793
{
5894
change: onChange,
5995
focus: onFocus,

0 commit comments

Comments
 (0)