Skip to content

Commit 0d9c417

Browse files
committed
feat(date-picker): enhance date selection decoding with fallback formats and improve component handling
feat(picker): update options type for better flexibility refactor(text): normalize styles in Text component and improve type definitions
1 parent 32f7b69 commit 0d9c417

File tree

5 files changed

+123
-60
lines changed

5 files changed

+123
-60
lines changed

ios/components/DatePicker/DatePickerProps.swift

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,24 +59,41 @@ public final class DatePickerProps: ObservableObject, Decodable {
5959
let container = try decoder.container(keyedBy: CodingKeys.self)
6060

6161
label = try container.decodeIfPresent(String.self, forKey: .label) ?? ""
62+
63+
// Ensure we have at least one component
64+
displayedComponents = try container.decodeDatePickerComponents(forKey: .displayedComponents)
6265
// Decode selection as ISO8601 date string
63-
let selectionString = try container.decode(String.self, forKey: .selection)
64-
let formatter = ISO8601DateFormatter()
65-
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
66-
guard let date = formatter.date(from: selectionString) else {
67-
throw DecodingError.dataCorruptedError(
68-
forKey: .selection,
69-
in: container,
70-
debugDescription: "Invalid date format: \(selectionString)"
71-
)
66+
let selectionString = try container.decodeIfPresent(String.self, forKey: .selection) ?? ""
67+
if !selectionString.isEmpty {
68+
let formatter = ISO8601DateFormatter()
69+
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
70+
71+
if let date = formatter.date(from: selectionString) {
72+
selection = date
73+
} else {
74+
// Try more permissive formats if strict ISO8601 fails
75+
let fallbackFormatter = DateFormatter()
76+
fallbackFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
77+
78+
if let date = fallbackFormatter.date(from: selectionString) {
79+
selection = date
80+
} else {
81+
throw DecodingError.dataCorruptedError(
82+
forKey: .selection,
83+
in: container,
84+
debugDescription: "Invalid date format: \(selectionString)"
85+
)
86+
}
87+
}
88+
} else {
89+
var calendar = Calendar.current
90+
// calendar.timeZone = TimeZone(identifier: "UTC")!
91+
selection = calendar.startOfDay(for: Date())
7292
}
73-
selection = date
93+
7494
// Decode datePickerStyle
7595
let styleString = try container.decodeIfPresent(String.self, forKey: .datePickerStyle) ?? "default"
7696
datePickerStyle = DatePickerStyle(rawValue: styleString) ?? .default
77-
// Decode displayedComponents
78-
let componentsString = try container.decodeIfPresent(String.self, forKey: .displayedComponents)
79-
displayedComponents = componentsString == "date" ? .date : [.date, .hourAndMinute]
8097
disabled = try container.decodeIfPresent(Bool.self, forKey: .disabled) ?? false
8198
}
8299

@@ -88,3 +105,44 @@ public final class DatePickerProps: ObservableObject, Decodable {
88105
disabled = other.disabled
89106
}
90107
}
108+
109+
extension KeyedDecodingContainer {
110+
func decodeDatePickerComponents(forKey key: Key) throws -> DatePickerComponents {
111+
var datePickerComponents: DatePickerComponents = .date // Default to date
112+
if let componentArray = try? decodeIfPresent([String].self, forKey: key) {
113+
// Handle array of components: ["date", "hourAndMinute"]
114+
datePickerComponents = []
115+
for component in componentArray {
116+
switch component.lowercased() {
117+
case "date":
118+
datePickerComponents.insert(.date)
119+
case "hourandminute":
120+
datePickerComponents.insert(.hourAndMinute)
121+
// case "era", "epoch":
122+
// if #available(iOS 16.0, *) {
123+
// datePickerComponents.insert(.era)
124+
// }
125+
default:
126+
break
127+
}
128+
}
129+
} else if let singleComponent = try? decodeIfPresent(String.self, forKey: key) {
130+
// Simple single string component
131+
switch singleComponent.lowercased() {
132+
case "date":
133+
datePickerComponents = .date
134+
case "time":
135+
datePickerComponents = .hourAndMinute
136+
case "datetime":
137+
datePickerComponents = [.date, .hourAndMinute]
138+
// case "era", "epoch":
139+
// if #available(iOS 16.0, *) {
140+
// datePickerComponents = .era
141+
// }
142+
default:
143+
datePickerComponents = .date
144+
}
145+
}
146+
return datePickerComponents
147+
}
148+
}

ios/extensions/Color+Parsing.swift

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -184,44 +184,44 @@ extension UIColor {
184184
}
185185
}
186186

187-
// extension Color {
188-
// // Backgrounds
189-
// static let systemBackground = Color(UIColor.systemBackground)
190-
// static let secondarySystemBackground = Color(UIColor.secondarySystemBackground)
191-
// static let tertiarySystemBackground = Color(UIColor.tertiarySystemBackground)
192-
// static let systemGroupedBackground = Color(UIColor.systemGroupedBackground)
193-
// static let secondarySystemGroupedBackground = Color(UIColor.secondarySystemGroupedBackground)
194-
// static let tertiarySystemGroupedBackground = Color(UIColor.tertiarySystemGroupedBackground)
195-
196-
// // Labels
197-
// static let label = Color(UIColor.label)
198-
// static let secondaryLabel = Color(UIColor.secondaryLabel)
199-
// static let tertiaryLabel = Color(UIColor.tertiaryLabel)
200-
// static let quaternaryLabel = Color(UIColor.quaternaryLabel)
201-
// static let placeholderText = Color(UIColor.placeholderText)
202-
203-
// // Fill colors
204-
// static let systemFill = Color(UIColor.systemFill)
205-
// static let secondarySystemFill = Color(UIColor.secondarySystemFill)
206-
// static let tertiarySystemFill = Color(UIColor.tertiarySystemFill)
207-
// static let quaternarySystemFill = Color(UIColor.quaternarySystemFill)
208-
209-
// // Standard colors
210-
// static let systemRed = Color(UIColor.systemRed)
211-
// static let systemBlue = Color(UIColor.systemBlue)
212-
// static let systemGreen = Color(UIColor.systemGreen)
213-
// static let systemOrange = Color(UIColor.systemOrange)
214-
// static let systemYellow = Color(UIColor.systemYellow)
215-
// static let systemPink = Color(UIColor.systemPink)
216-
// static let systemPurple = Color(UIColor.systemPurple)
217-
// static let systemTeal = Color(UIColor.systemTeal)
218-
// static let systemIndigo = Color(UIColor.systemIndigo)
219-
220-
// // Grays
221-
// static let systemGray = Color(UIColor.systemGray)
222-
// static let systemGray2 = Color(UIColor.systemGray2)
223-
// static let systemGray3 = Color(UIColor.systemGray3)
224-
// static let systemGray4 = Color(UIColor.systemGray4)
225-
// static let systemGray5 = Color(UIColor.systemGray5)
226-
// static let systemGray6 = Color(UIColor.systemGray6)
227-
// }
187+
extension Color {
188+
// Backgrounds
189+
static let systemBackground = Color(UIColor.systemBackground)
190+
static let secondarySystemBackground = Color(UIColor.secondarySystemBackground)
191+
static let tertiarySystemBackground = Color(UIColor.tertiarySystemBackground)
192+
static let systemGroupedBackground = Color(UIColor.systemGroupedBackground)
193+
static let secondarySystemGroupedBackground = Color(UIColor.secondarySystemGroupedBackground)
194+
static let tertiarySystemGroupedBackground = Color(UIColor.tertiarySystemGroupedBackground)
195+
196+
// Labels
197+
static let label = Color(UIColor.label)
198+
static let secondaryLabel = Color(UIColor.secondaryLabel)
199+
static let tertiaryLabel = Color(UIColor.tertiaryLabel)
200+
static let quaternaryLabel = Color(UIColor.quaternaryLabel)
201+
static let placeholderText = Color(UIColor.placeholderText)
202+
203+
// Fill colors
204+
static let systemFill = Color(UIColor.systemFill)
205+
static let secondarySystemFill = Color(UIColor.secondarySystemFill)
206+
static let tertiarySystemFill = Color(UIColor.tertiarySystemFill)
207+
static let quaternarySystemFill = Color(UIColor.quaternarySystemFill)
208+
209+
// Standard colors
210+
static let systemRed = Color(UIColor.systemRed)
211+
static let systemBlue = Color(UIColor.systemBlue)
212+
static let systemGreen = Color(UIColor.systemGreen)
213+
static let systemOrange = Color(UIColor.systemOrange)
214+
static let systemYellow = Color(UIColor.systemYellow)
215+
static let systemPink = Color(UIColor.systemPink)
216+
static let systemPurple = Color(UIColor.systemPurple)
217+
static let systemTeal = Color(UIColor.systemTeal)
218+
static let systemIndigo = Color(UIColor.systemIndigo)
219+
220+
// Grays
221+
static let systemGray = Color(UIColor.systemGray)
222+
static let systemGray2 = Color(UIColor.systemGray2)
223+
static let systemGray3 = Color(UIColor.systemGray3)
224+
static let systemGray4 = Color(UIColor.systemGray4)
225+
static let systemGray5 = Color(UIColor.systemGray5)
226+
static let systemGray6 = Color(UIColor.systemGray6)
227+
}

src/components/DatePicker.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ export type NativeDatePickerStyle = "automatic" | "compact" | "field" | "graphic
77

88
// https://developer.apple.com/documentation/swiftui/datepickercomponents
99
export type NativeDatePickerComponents = "date" | "hourAndMinute" | "hourMinuteAndSecond";
10+
export type NativeDatePickerComponentsAliases = "date" | "time" | "datetime";
1011

1112
export type NativeDatePickerProps = {
1213
selection?: Date;
1314
label?: string;
1415
datePickerStyle?: NativeDatePickerStyle;
15-
displayedComponents?: NativeDatePickerComponents;
16+
displayedComponents?: NativeDatePickerComponents[] | NativeDatePickerComponentsAliases;
1617
disabled?: boolean;
1718
onChange?: (value: Date) => void;
1819
onFocus?: () => void;

src/components/Picker.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import type { NativeTextStyle } from "../types";
77

88
export type NativePickerStyle = "default" | "inline" | "menu" | "segmented" | "wheel";
99

10+
export type NativePickerOption<T extends string> = { value: T; label: string } | T;
11+
1012
export type NativePickerProps<T extends string> = {
11-
options: readonly { value: T; label: string }[] | readonly T[];
13+
options: readonly NativePickerOption<T>[];
1214
selection?: T;
1315
label?: string;
1416
pickerStyle?: NativePickerStyle;

src/components/Text.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
import { useSwiftUINode } from "../hooks";
1+
import { type StyleProp } from "react-native";
2+
import { useNormalizedStyles, useSwiftUINode } from "../hooks";
23
import type { FunctionComponentWithId, NativeTextStyle } from "../types";
34

45
export type NativeTextProps = {
56
text: string;
67
alignment?: "leading" | "center" | "trailing";
7-
style?: NativeTextStyle;
8+
style?: StyleProp<NativeTextStyle>;
89
};
910

10-
export const Text: FunctionComponentWithId<NativeTextProps> = ({ ...otherProps }) => {
11-
useSwiftUINode("Text", otherProps);
11+
export const Text: FunctionComponentWithId<NativeTextProps> = ({ style, ...otherProps }) => {
12+
const normalizedStyles = useNormalizedStyles<NativeTextStyle>(style);
13+
useSwiftUINode("Text", { style: normalizedStyles, ...otherProps });
1214

1315
return null;
1416
};

0 commit comments

Comments
 (0)