diff --git a/ios/RNDateTimePicker.m b/ios/RNDateTimePicker.m index 9c73c8ef..799162e7 100644 --- a/ios/RNDateTimePicker.m +++ b/ios/RNDateTimePicker.m @@ -72,4 +72,21 @@ - (void)setDate:(NSDate *)date { } } +- (CGSize)intrinsicContentSize { + CGSize size = [super intrinsicContentSize]; + // iOS DatePicker requires a minimum width of 280 points for proper display + // See: https://github.com/react-native-datetimepicker/datetimepicker/issues/1014 + size.width = MAX(size.width, 280); + + // For inline (calendar) display style, suggest a larger width + // This helps the calendar expand to fill available width + if (@available(iOS 14.0, *)) { + if (self.preferredDatePickerStyle == UIDatePickerStyleInline) { + size.width = MAX(size.width, 375); // Standard iPhone width + } + } + + return size; +} + @end diff --git a/ios/RNDateTimePickerShadowView.m b/ios/RNDateTimePickerShadowView.m index 4ff33623..62a808fa 100644 --- a/ios/RNDateTimePickerShadowView.m +++ b/ios/RNDateTimePickerShadowView.m @@ -69,7 +69,30 @@ static YGSize RNDateTimePickerShadowViewMeasure(YGNodeConstRef node, float width } size = [shadowPickerView.picker sizeThatFits:UILayoutFittingCompressedSize]; - size.width += 10; + // iOS DatePicker requires a minimum width of 280 points for proper display + // See: https://github.com/react-native-datetimepicker/datetimepicker/issues/1014 + size.width = MAX(size.width, 280); + + // Respect the provided width constraint to allow the picker to expand to full width + // when a specific width is provided or when measuring at-most mode + if (widthMode == YGMeasureModeExactly) { + size.width = width; + } else if (widthMode == YGMeasureModeAtMost) { + // For inline/calendar style, try to use the full available width + // For other styles, use the minimum width needed + if (@available(iOS 14.0, *)) { + if (shadowPickerView.picker.preferredDatePickerStyle == UIDatePickerStyleInline) { + size.width = width; // Use full available width for calendar + } else { + size.width = MIN(size.width + 10, width); + } + } else { + size.width = MIN(size.width + 10, width); + } + } else { + // For undefined mode, add small padding + size.width += 10; + } }); return (YGSize){ diff --git a/ios/fabric/RNDateTimePickerComponentView.mm b/ios/fabric/RNDateTimePickerComponentView.mm index ec9d7cdc..ebe5bab4 100644 --- a/ios/fabric/RNDateTimePickerComponentView.mm +++ b/ios/fabric/RNDateTimePickerComponentView.mm @@ -104,6 +104,21 @@ - (void) updateMeasurements { } CGSize size = [_dummyPicker sizeThatFits:UILayoutFittingCompressedSize]; size.width += 10; + + // Workaround: sizeThatFits: returns incorrect height for + // UIDatePickerModeDateAndTime + UIDatePickerStyleInline (Apple bug). + // The returned height only accounts for the calendar, missing the time row. + if (@available(iOS 14.0, *)) { + if (_dummyPicker.datePickerMode == UIDatePickerModeDateAndTime && + _dummyPicker.preferredDatePickerStyle == UIDatePickerStyleInline) { + UIDatePicker *timePicker = [UIDatePicker new]; + timePicker.datePickerMode = UIDatePickerModeTime; + timePicker.preferredDatePickerStyle = UIDatePickerStyleInline; + CGSize timeSize = [timePicker sizeThatFits:UILayoutFittingCompressedSize]; + size.height += timeSize.height; + } + } + auto newState = RNDateTimePickerState{RCTSizeFromCGSize(size)}; _state->updateState(std::move(newState)); } diff --git a/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ComponentDescriptors.h b/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ComponentDescriptors.h index d51a3272..19874156 100644 --- a/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ComponentDescriptors.h +++ b/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ComponentDescriptors.h @@ -20,13 +20,12 @@ class RNDateTimePickerComponentDescriptor final : public ConcreteComponentDescri void adopt(ShadowNode& shadowNode) const override { auto& pickerShadowNode = static_cast(shadowNode); - auto& layoutableShadowNode = static_cast(pickerShadowNode); auto state = std::static_pointer_cast(shadowNode.getState()); auto stateData = state->getData(); - if(stateData.frameSize.width != 0 && stateData.frameSize.height != 0) { - layoutableShadowNode.setSize(Size{stateData.frameSize.width, stateData.frameSize.height}); + if(stateData.frameSize.height != 0) { + pickerShadowNode.setMeasuredHeight(stateData.frameSize.height); } ConcreteComponentDescriptor::adopt(shadowNode); diff --git a/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ShadowNodes.h b/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ShadowNodes.h index bf2fa2ea..59cdef98 100644 --- a/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ShadowNodes.h +++ b/ios/fabric/cpp/react/renderer/components/RNDateTimePicker/ShadowNodes.h @@ -33,6 +33,13 @@ class JSI_EXPORT RNDateTimePickerShadowNode final : public ConcreteViewShadowNod traits.set(ShadowNodeTraits::Trait::LeafYogaNode); return traits; } + + void setMeasuredHeight(float height) const { + auto style = yogaNode_.style(); + style.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(height)); + yogaNode_.setStyle(style); + yogaNode_.setDirty(true); + } }; } // namespace react