react-native-platform-components 0.5.3 → 0.5.4

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.
Files changed (28) hide show
  1. package/README.md +6 -1
  2. package/android/build.gradle +3 -1
  3. package/android/src/main/java/com/platformcomponents/PCConstants.kt +3 -0
  4. package/android/src/main/java/com/platformcomponents/PCDatePickerView.kt +53 -1
  5. package/android/src/main/java/com/platformcomponents/PCDatePickerViewManager.kt +14 -0
  6. package/android/src/main/java/com/platformcomponents/PCSelectionMenuView.kt +169 -10
  7. package/android/src/main/java/com/platformcomponents/PCSelectionMenuViewManager.kt +14 -0
  8. package/android/src/main/jni/CMakeLists.txt +47 -0
  9. package/android/src/main/jni/OnLoad.cpp +33 -0
  10. package/ios/PCDatePickerView.swift +19 -2
  11. package/ios/PCSelectionMenu.mm +42 -0
  12. package/ios/PCSelectionMenu.swift +17 -0
  13. package/lib/module/SelectionMenu.js +1 -8
  14. package/lib/module/SelectionMenu.js.map +1 -1
  15. package/lib/typescript/src/SelectionMenu.d.ts.map +1 -1
  16. package/package.json +1 -1
  17. package/react-native.config.js +13 -0
  18. package/shared/PCDatePickerComponentDescriptors-custom.h +14 -43
  19. package/shared/PCDatePickerShadowNode-custom.cpp +35 -0
  20. package/shared/PCDatePickerShadowNode-custom.h +40 -18
  21. package/shared/PCDatePickerState-custom.h +53 -1
  22. package/shared/PCSelectionMenuComponentDescriptors-custom.h +15 -18
  23. package/shared/PCSelectionMenuShadowNode-custom.cpp +42 -21
  24. package/shared/PCSelectionMenuShadowNode-custom.h +23 -10
  25. package/shared/PCSelectionMenuState-custom.h +65 -0
  26. package/shared/README.md +179 -0
  27. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +9 -0
  28. package/src/SelectionMenu.tsx +2 -12
@@ -2,7 +2,6 @@
2
2
 
3
3
  // SelectionMenu.tsx
4
4
  import React, { useCallback, useMemo } from 'react';
5
- import { Platform, StyleSheet } from 'react-native';
6
5
  import NativeSelectionMenu from './SelectionMenuNativeComponent';
7
6
  import { jsx as _jsx } from "react/jsx-runtime";
8
7
  function normalizeSelectedData(selected) {
@@ -49,9 +48,8 @@ export function SelectionMenu(props) {
49
48
  material: android.material
50
49
  };
51
50
  }, [android]);
52
- const isAndroidM3Inline = android?.material && inlineMode && android.material === 'm3' && Platform.OS === 'android';
53
51
  return /*#__PURE__*/_jsx(NativeSelectionMenu, {
54
- style: [style, isAndroidM3Inline && styles.androidInline],
52
+ style: style,
55
53
  options: options,
56
54
  selectedData: selectedData,
57
55
  interactivity: disabled ? 'disabled' : 'enabled',
@@ -65,9 +63,4 @@ export function SelectionMenu(props) {
65
63
  ...viewProps
66
64
  });
67
65
  }
68
- const styles = StyleSheet.create({
69
- androidInline: {
70
- minHeight: 60
71
- }
72
- });
73
66
  //# sourceMappingURL=SelectionMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["React","useCallback","useMemo","Platform","StyleSheet","NativeSelectionMenu","jsx","_jsx","normalizeSelectedData","selected","normalizeNativeVisible","inlineMode","visible","undefined","SelectionMenu","props","style","options","disabled","placeholder","onSelect","onRequestClose","ios","android","viewProps","selectedData","nativeVisible","handleSelect","e","index","label","data","nativeEvent","handleRequestClose","nativeAndroid","material","isAndroidM3Inline","OS","styles","androidInline","interactivity","anchorMode","create","minHeight"],"sourceRoot":"../../src","sources":["SelectionMenu.tsx"],"mappings":";;AAAA;AACA,OAAOA,KAAK,IAAIC,WAAW,EAAEC,OAAO,QAAQ,OAAO;AACnD,SAASC,QAAQ,EAAEC,UAAU,QAAwB,cAAc;AAEnE,OAAOC,mBAAmB,MAGnB,gCAAgC;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAsDxC,SAASC,qBAAqBA,CAACC,QAAuB,EAAU;EAC9D,OAAOA,QAAQ,IAAI,EAAE;AACvB;AAEA,SAASC,sBAAsBA,CAC7BC,UAA+B,EAC/BC,OAA4B,EACG;EAC/B;EACA,IAAID,UAAU,EAAE,OAAOE,SAAS;EAChC,OAAOD,OAAO,GAAG,MAAM,GAAG,QAAQ;AACpC;AAEA,OAAO,SAASE,aAAaA,CAACC,KAAyB,EAAsB;EAC3E,MAAM;IACJC,KAAK;IACLC,OAAO;IACPR,QAAQ;IACRS,QAAQ;IACRC,WAAW;IACXR,UAAU;IACVC,OAAO;IACPQ,QAAQ;IACRC,cAAc;IACdC,GAAG;IACHC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGT,KAAK;EAET,MAAMU,YAAY,GAAGvB,OAAO,CAC1B,MAAMM,qBAAqB,CAACC,QAAQ,CAAC,EACrC,CAACA,QAAQ,CACX,CAAC;EAED,MAAMiB,aAAa,GAAGxB,OAAO,CAC3B,MAAMQ,sBAAsB,CAACC,UAAU,EAAEC,OAAO,CAAC,EACjD,CAACD,UAAU,EAAEC,OAAO,CACtB,CAAC;EAED,MAAMe,YAAY,GAAG1B,WAAW,CAC7B2B,CAA4C,IAAK;IAChD,MAAM;MAAEC,KAAK;MAAEC,KAAK;MAAEC;IAAK,CAAC,GAAGH,CAAC,CAACI,WAAW;IAC5CZ,QAAQ,GAAGW,IAAI,EAAED,KAAK,EAAED,KAAK,CAAC;EAChC,CAAC,EACD,CAACT,QAAQ,CACX,CAAC;EAED,MAAMa,kBAAkB,GAAGhC,WAAW,CAAC,MAAM;IAC3CoB,cAAc,GAAG,CAAC;EACpB,CAAC,EAAE,CAACA,cAAc,CAAC,CAAC;;EAEpB;EACA,MAAMa,aAAa,GAAGhC,OAAO,CAAC,MAAM;IAClC,IAAI,CAACqB,OAAO,EAAE,OAAOV,SAAS;IAC9B,OAAO;MAAEsB,QAAQ,EAAEZ,OAAO,CAACY;IAAS,CAAC;EACvC,CAAC,EAAE,CAACZ,OAAO,CAAC,CAAC;EAEb,MAAMa,iBAAiB,GACrBb,OAAO,EAAEY,QAAQ,IACjBxB,UAAU,IACVY,OAAO,CAACY,QAAQ,KAAK,IAAI,IACzBhC,QAAQ,CAACkC,EAAE,KAAK,SAAS;EAE3B,oBACE9B,IAAA,CAACF,mBAAmB;IAClBW,KAAK,EAAE,CAACA,KAAK,EAAEoB,iBAAiB,IAAIE,MAAM,CAACC,aAAa,CAAE;IAC1DtB,OAAO,EAAEA,OAAQ;IACjBQ,YAAY,EAAEA,YAAa;IAC3Be,aAAa,EAAEtB,QAAQ,GAAG,UAAU,GAAG,SAAU;IACjDC,WAAW,EAAEA,WAAY;IACzBsB,UAAU,EAAE9B,UAAU,GAAG,QAAQ,GAAG,UAAW;IAC/CC,OAAO,EAAEc,aAAc;IACvBN,QAAQ,EAAEA,QAAQ,GAAGO,YAAY,GAAGd,SAAU;IAC9CQ,cAAc,EAAEA,cAAc,GAAGY,kBAAkB,GAAGpB,SAAU;IAChES,GAAG,EAAEA,GAAI;IACTC,OAAO,EAAEW,aAAc;IAAA,GACnBV;EAAS,CACd,CAAC;AAEN;AAEA,MAAMc,MAAM,GAAGlC,UAAU,CAACsC,MAAM,CAAC;EAC/BH,aAAa,EAAE;IAAEI,SAAS,EAAE;EAAG;AACjC,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["React","useCallback","useMemo","NativeSelectionMenu","jsx","_jsx","normalizeSelectedData","selected","normalizeNativeVisible","inlineMode","visible","undefined","SelectionMenu","props","style","options","disabled","placeholder","onSelect","onRequestClose","ios","android","viewProps","selectedData","nativeVisible","handleSelect","e","index","label","data","nativeEvent","handleRequestClose","nativeAndroid","material","interactivity","anchorMode"],"sourceRoot":"../../src","sources":["SelectionMenu.tsx"],"mappings":";;AAAA;AACA,OAAOA,KAAK,IAAIC,WAAW,EAAEC,OAAO,QAAQ,OAAO;AAGnD,OAAOC,mBAAmB,MAGnB,gCAAgC;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAsDxC,SAASC,qBAAqBA,CAACC,QAAuB,EAAU;EAC9D,OAAOA,QAAQ,IAAI,EAAE;AACvB;AAEA,SAASC,sBAAsBA,CAC7BC,UAA+B,EAC/BC,OAA4B,EACG;EAC/B;EACA,IAAID,UAAU,EAAE,OAAOE,SAAS;EAChC,OAAOD,OAAO,GAAG,MAAM,GAAG,QAAQ;AACpC;AAEA,OAAO,SAASE,aAAaA,CAACC,KAAyB,EAAsB;EAC3E,MAAM;IACJC,KAAK;IACLC,OAAO;IACPR,QAAQ;IACRS,QAAQ;IACRC,WAAW;IACXR,UAAU;IACVC,OAAO;IACPQ,QAAQ;IACRC,cAAc;IACdC,GAAG;IACHC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGT,KAAK;EAET,MAAMU,YAAY,GAAGrB,OAAO,CAC1B,MAAMI,qBAAqB,CAACC,QAAQ,CAAC,EACrC,CAACA,QAAQ,CACX,CAAC;EAED,MAAMiB,aAAa,GAAGtB,OAAO,CAC3B,MAAMM,sBAAsB,CAACC,UAAU,EAAEC,OAAO,CAAC,EACjD,CAACD,UAAU,EAAEC,OAAO,CACtB,CAAC;EAED,MAAMe,YAAY,GAAGxB,WAAW,CAC7ByB,CAA4C,IAAK;IAChD,MAAM;MAAEC,KAAK;MAAEC,KAAK;MAAEC;IAAK,CAAC,GAAGH,CAAC,CAACI,WAAW;IAC5CZ,QAAQ,GAAGW,IAAI,EAAED,KAAK,EAAED,KAAK,CAAC;EAChC,CAAC,EACD,CAACT,QAAQ,CACX,CAAC;EAED,MAAMa,kBAAkB,GAAG9B,WAAW,CAAC,MAAM;IAC3CkB,cAAc,GAAG,CAAC;EACpB,CAAC,EAAE,CAACA,cAAc,CAAC,CAAC;;EAEpB;EACA,MAAMa,aAAa,GAAG9B,OAAO,CAAC,MAAM;IAClC,IAAI,CAACmB,OAAO,EAAE,OAAOV,SAAS;IAC9B,OAAO;MAAEsB,QAAQ,EAAEZ,OAAO,CAACY;IAAS,CAAC;EACvC,CAAC,EAAE,CAACZ,OAAO,CAAC,CAAC;EAEb,oBACEhB,IAAA,CAACF,mBAAmB;IAClBW,KAAK,EAAEA,KAAM;IACbC,OAAO,EAAEA,OAAQ;IACjBQ,YAAY,EAAEA,YAAa;IAC3BW,aAAa,EAAElB,QAAQ,GAAG,UAAU,GAAG,SAAU;IACjDC,WAAW,EAAEA,WAAY;IACzBkB,UAAU,EAAE1B,UAAU,GAAG,QAAQ,GAAG,UAAW;IAC/CC,OAAO,EAAEc,aAAc;IACvBN,QAAQ,EAAEA,QAAQ,GAAGO,YAAY,GAAGd,SAAU;IAC9CQ,cAAc,EAAEA,cAAc,GAAGY,kBAAkB,GAAGpB,SAAU;IAChES,GAAG,EAAEA,GAAI;IACTC,OAAO,EAAEW,aAAc;IAAA,GACnBV;EAAS,CACd,CAAC;AAEN","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"SelectionMenu.d.ts","sourceRoot":"","sources":["../../../src/SelectionMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAC;AACpD,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,OAA4B,EAC1B,KAAK,mBAAmB,EAEzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,yCAAyC;IACzC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAExC;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhE;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,CAAC;IAET,OAAO,CAAC,EAAE;QACR,6CAA6C;QAC7C,QAAQ,CAAC,EAAE,mBAAmB,CAAC;KAChC,CAAC;IAEF,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAkE3E"}
1
+ {"version":3,"file":"SelectionMenu.d.ts","sourceRoot":"","sources":["../../../src/SelectionMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,OAA4B,EAC1B,KAAK,mBAAmB,EAEzB,MAAM,gCAAgC,CAAC;AAExC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEzD,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,yCAAyC;IACzC,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAExC;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEhE;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,CAAC;IAET,OAAO,CAAC,EAAE;QACR,6CAA6C;QAC7C,QAAQ,CAAC,EAAE,mBAAmB,CAAC;KAChC,CAAC;IAEF,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAeD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CA4D3E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-platform-components",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "A cross-platform toolkit of native UI components for React Native.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ dependency: {
3
+ platforms: {
4
+ android: {
5
+ componentDescriptors: [
6
+ 'MeasuringPCSelectionMenuComponentDescriptor',
7
+ 'MeasuringPCDatePickerComponentDescriptor',
8
+ ],
9
+ cmakeListsPath: 'src/main/jni/CMakeLists.txt',
10
+ },
11
+ },
12
+ },
13
+ };
@@ -1,52 +1,23 @@
1
1
  #pragma once
2
2
 
3
- #include "PCDatePickerShadowNode-custom.h"
4
-
5
3
  #include <react/renderer/core/ConcreteComponentDescriptor.h>
6
- #include <react/renderer/mounting/ShadowView.h>
7
- #include <react/renderer/core/ShadowNode.h>
8
- #include <react/renderer/core/ShadowNodeTraits.h>
9
- #include <react/renderer/core/ShadowNodeFragment.h>
10
- #include <react/renderer/core/ShadowNodeFamily.h>
11
- #include <react/renderer/components/view/YogaLayoutableShadowNode.h>
12
-
13
- namespace facebook::react
14
- {
15
4
 
16
- class MeasuringPCDatePickerComponentDescriptor final
17
- : public ConcreteComponentDescriptor<MeasuringPCDatePickerShadowNode>
18
- {
19
- public:
20
- using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
5
+ // Forward declaration to avoid circular includes
6
+ namespace facebook::react {
7
+ class MeasuringPCDatePickerShadowNode;
8
+ }
21
9
 
22
- void adopt(ShadowNode &shadowNode) const override
23
- {
24
- auto &pickerShadowNode =
25
- static_cast<MeasuringPCDatePickerShadowNode &>(shadowNode);
26
- auto &layoutableShadowNode =
27
- static_cast<YogaLayoutableShadowNode &>(pickerShadowNode);
28
-
29
- auto state =
30
- std::static_pointer_cast<
31
- const MeasuringPCDatePickerShadowNode::ConcreteState
32
- >(shadowNode.getState());
33
-
34
- if (state)
35
- {
36
- auto stateData = state->getData();
37
- auto frameSize = stateData.frameSize;
10
+ // Include the actual shadow node definition
11
+ #include "PCDatePickerShadowNode-custom.h"
38
12
 
39
- if (frameSize.width >= 0 && frameSize.height >= 0)
40
- {
41
- layoutableShadowNode.setSize(Size{
42
- frameSize.width,
43
- frameSize.height,
44
- });
45
- }
46
- }
13
+ namespace facebook::react {
47
14
 
48
- ConcreteComponentDescriptor::adopt(shadowNode);
49
- }
50
- };
15
+ /**
16
+ * Custom component descriptor that uses our measuring shadow node
17
+ * instead of the generated one. No custom adopt() needed since
18
+ * measurement is handled via measureContent().
19
+ */
20
+ using MeasuringPCDatePickerComponentDescriptor =
21
+ ConcreteComponentDescriptor<MeasuringPCDatePickerShadowNode>;
51
22
 
52
23
  } // namespace facebook::react
@@ -1 +1,36 @@
1
1
  #include "PCDatePickerShadowNode-custom.h"
2
+
3
+ #include <react/renderer/core/LayoutConstraints.h>
4
+ #include <react/renderer/core/ConcreteShadowNode.h>
5
+ #include <algorithm>
6
+
7
+ namespace facebook::react {
8
+
9
+ Size MeasuringPCDatePickerShadowNode::measureContent(
10
+ const LayoutContext& /*layoutContext*/,
11
+ const LayoutConstraints& layoutConstraints) const {
12
+
13
+ // Get frame size from native state - native measures the actual picker
14
+ const auto& stateData = this->getStateData();
15
+ Float measuredW = stateData.frameSize.width;
16
+ Float measuredH = stateData.frameSize.height;
17
+
18
+ // If width is 0, use available width from constraints
19
+ const Float kHuge = static_cast<Float>(1.0e9);
20
+ if (measuredW <= 0) {
21
+ const Float maxW = layoutConstraints.maximumSize.width;
22
+ measuredW = (maxW > 0 && maxW < kHuge) ? maxW : 0;
23
+ }
24
+
25
+ // Respect layout constraints
26
+ measuredW = std::max<Float>(measuredW, layoutConstraints.minimumSize.width);
27
+ measuredW = std::min<Float>(measuredW, layoutConstraints.maximumSize.width);
28
+
29
+ measuredH = std::max<Float>(measuredH, layoutConstraints.minimumSize.height);
30
+ measuredH = std::min<Float>(measuredH, layoutConstraints.maximumSize.height);
31
+
32
+ Size result{measuredW, measuredH};
33
+ return layoutConstraints.clamp(result);
34
+ }
35
+
36
+ } // namespace facebook::react
@@ -1,27 +1,49 @@
1
1
  #pragma once
2
2
 
3
- #include <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
3
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
4
+
5
+ // Only include what we need for the shadow node definition
6
+ // Do NOT include ComponentDescriptors.h here to avoid circular dependency
4
7
  #include <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
5
8
  #include <react/renderer/components/PlatformComponentsViewSpec/Props.h>
6
9
 
7
- #include <react/renderer/components/view/ConcreteViewShadowNode.h>
8
- #include <react/renderer/core/ConcreteState.h>
9
- #include <react/renderer/core/ShadowNodeTraits.h>
10
- #include <react/renderer/mounting/ShadowView.h>
11
-
12
10
  #include "PCDatePickerState-custom.h"
13
11
 
14
- namespace facebook::react
15
- {
16
- class MeasuringPCDatePickerShadowNode final
17
- : public ConcreteViewShadowNode<
18
- PCDatePickerComponentName,
19
- PCDatePickerProps,
20
- PCDatePickerEventEmitter,
21
- PCDatePickerStateFrameSize>
22
- {
23
- public:
24
- using ConcreteViewShadowNode::ConcreteViewShadowNode;
25
- };
12
+ namespace facebook::react {
13
+
14
+ extern const char PCDatePickerComponentName[];
15
+
16
+ /**
17
+ * Custom ShadowNode for DatePicker that supports Yoga measurement.
18
+ *
19
+ * Key behavior:
20
+ * - Native side measures the actual picker and updates state with frameSize
21
+ * - measureContent() returns the size from state for proper Yoga layout
22
+ * - No hardcoded dimensions - uses actual measured values from native
23
+ */
24
+ class MeasuringPCDatePickerShadowNode final
25
+ : public ConcreteViewShadowNode<
26
+ PCDatePickerComponentName,
27
+ PCDatePickerProps,
28
+ PCDatePickerEventEmitter,
29
+ PCDatePickerStateFrameSize> {
30
+ public:
31
+ using ConcreteViewShadowNode::ConcreteViewShadowNode;
32
+
33
+ static ShadowNodeTraits BaseTraits() {
34
+ auto traits = ConcreteViewShadowNode::BaseTraits();
35
+ traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
36
+ traits.set(ShadowNodeTraits::Trait::MeasurableYogaNode);
37
+ return traits;
38
+ }
39
+
40
+ /**
41
+ * Called by Yoga when it needs the intrinsic size of the component.
42
+ * Returns the size provided by native through state - no hardcoding.
43
+ */
44
+ Size measureContent(
45
+ const LayoutContext& layoutContext,
46
+ const LayoutConstraints& layoutConstraints) const override;
47
+ };
26
48
 
27
49
  } // namespace facebook::react
@@ -1,13 +1,65 @@
1
1
  #pragma once
2
2
 
3
3
  #include <react/renderer/core/LayoutPrimitives.h>
4
+ #include <memory>
5
+
6
+ #ifdef RN_SERIALIZABLE_STATE
7
+ #include <folly/dynamic.h>
8
+ #include <react/renderer/mapbuffer/MapBuffer.h>
9
+ #include <react/renderer/mapbuffer/MapBufferBuilder.h>
10
+ #endif
4
11
 
5
12
  namespace facebook::react {
6
13
 
7
- struct PCDatePickerStateFrameSize final {
14
+ /**
15
+ * Custom state for DatePicker that holds the measured frame size from native.
16
+ * This allows the native side to measure the actual picker and communicate
17
+ * the size to the shadow node for proper Yoga layout.
18
+ *
19
+ * Note: Does NOT inherit from StateData (which is final). Custom state types
20
+ * are standalone structs that satisfy the ConcreteState template requirements.
21
+ */
22
+ struct PCDatePickerStateFrameSize {
8
23
  using Shared = std::shared_ptr<const PCDatePickerStateFrameSize>;
9
24
 
10
25
  Size frameSize{}; // {width, height} in points
26
+
27
+ PCDatePickerStateFrameSize() = default;
28
+
29
+ explicit PCDatePickerStateFrameSize(Size size) : frameSize(size) {}
30
+
31
+ bool operator==(const PCDatePickerStateFrameSize& other) const {
32
+ return frameSize.width == other.frameSize.width &&
33
+ frameSize.height == other.frameSize.height;
34
+ }
35
+
36
+ bool operator!=(const PCDatePickerStateFrameSize& other) const {
37
+ return !(*this == other);
38
+ }
39
+
40
+ #ifdef RN_SERIALIZABLE_STATE
41
+ // Required for Android state serialization
42
+ PCDatePickerStateFrameSize(
43
+ const PCDatePickerStateFrameSize& previousState,
44
+ folly::dynamic data)
45
+ : frameSize(previousState.frameSize) {
46
+ // Parse frame size from dynamic data if provided
47
+ if (data.isObject()) {
48
+ if (data.count("width") && data.count("height")) {
49
+ frameSize.width = static_cast<Float>(data["width"].asDouble());
50
+ frameSize.height = static_cast<Float>(data["height"].asDouble());
51
+ }
52
+ }
53
+ }
54
+
55
+ folly::dynamic getDynamic() const {
56
+ return folly::dynamic::object("width", frameSize.width)("height", frameSize.height);
57
+ }
58
+
59
+ MapBuffer getMapBuffer() const {
60
+ return MapBufferBuilder::EMPTY();
61
+ }
62
+ #endif
11
63
  };
12
64
 
13
65
  } // namespace facebook::react
@@ -1,25 +1,22 @@
1
1
  #pragma once
2
2
 
3
- #include "PCSelectionMenuShadowNode-custom.h"
4
-
5
3
  #include <react/renderer/core/ConcreteComponentDescriptor.h>
6
- #include <react/renderer/mounting/ShadowView.h>
7
- #include <react/renderer/core/ShadowNode.h>
8
- #include <react/renderer/core/ShadowNodeTraits.h>
9
- #include <react/renderer/core/ShadowNodeFragment.h>
10
- #include <react/renderer/core/ShadowNodeFamily.h>
11
- #include <react/renderer/components/view/YogaLayoutableShadowNode.h>
12
4
 
13
- namespace facebook::react
14
- {
15
- using MeasuringPCSelectionMenuComponentDescriptor = ConcreteComponentDescriptor<MeasuringPCSelectionMenuShadowNode>;
5
+ // Forward declaration to avoid circular includes
6
+ namespace facebook::react {
7
+ class MeasuringPCSelectionMenuShadowNode;
8
+ }
9
+
10
+ // Include the actual shadow node definition
11
+ #include "PCSelectionMenuShadowNode-custom.h"
12
+
13
+ namespace facebook::react {
16
14
 
17
- /*
18
- class MeasuringPCDatePickerComponentDescriptor final
19
- : public ConcreteComponentDescriptor<MeasuringPCSelectionMenuShadowNode>
20
- {
21
- public:
22
- using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
23
- };*/
15
+ /**
16
+ * Custom component descriptor that uses our measuring shadow node
17
+ * instead of the generated one.
18
+ */
19
+ using MeasuringPCSelectionMenuComponentDescriptor =
20
+ ConcreteComponentDescriptor<MeasuringPCSelectionMenuShadowNode>;
24
21
 
25
22
  } // namespace facebook::react
@@ -1,36 +1,57 @@
1
- #include <react/renderer/core/LayoutConstraints.h>
2
1
  #include "PCSelectionMenuShadowNode-custom.h"
3
2
 
3
+ #include <react/renderer/core/LayoutConstraints.h>
4
4
  #include <algorithm>
5
5
 
6
6
  namespace facebook::react {
7
7
 
8
- Size MeasuringPCSelectionMenuShadowNode::measureContent(
9
- const LayoutContext&,
10
- const LayoutConstraints& layoutConstraints) const {
11
-
12
- const Float kHuge = static_cast<Float>(1.0e9);
8
+ Size MeasuringPCSelectionMenuShadowNode::measureContent(
9
+ const LayoutContext& /*layoutContext*/,
10
+ const LayoutConstraints& layoutConstraints) const {
13
11
 
14
- const Float maxW = layoutConstraints.maximumSize.width;
15
- const Float measuredW = (maxW > 0 && maxW < kHuge) ? maxW : 0;
16
-
17
- const auto& props = *std::static_pointer_cast<const PCSelectionMenuProps>(getProps());
18
- const bool inlineMode = props.anchorMode == "inline";
12
+ const auto& props = *std::static_pointer_cast<const PCSelectionMenuProps>(getProps());
13
+ const bool inlineMode = props.anchorMode == "inline";
19
14
 
20
- Float measuredH = 0;
15
+ // Headless mode: zero size
16
+ if (!inlineMode) {
17
+ return layoutConstraints.clamp(Size{0, 0});
18
+ }
21
19
 
22
- if (inlineMode) {
23
- measuredH = static_cast<Float>(kMinRowHeight); // 44
20
+ // Get frame size from native state - native measures the actual picker
21
+ const auto& stateData = this->getStateData();
22
+ Float measuredW = stateData.frameSize.width;
23
+ Float measuredH = stateData.frameSize.height;
24
+
25
+ // If height is 0, use fallback values (state not yet set by native)
26
+ if (measuredH <= 0) {
27
+ #ifdef __ANDROID__
28
+ const std::string& material = props.android.material;
29
+ if (material == "m3") {
30
+ measuredH = static_cast<Float>(kFallbackHeightAndroidM3);
24
31
  } else {
25
- measuredH = 0;
32
+ measuredH = static_cast<Float>(kFallbackHeightAndroid);
26
33
  }
34
+ #else
35
+ measuredH = static_cast<Float>(kFallbackHeightIOS);
36
+ #endif
37
+ }
27
38
 
28
- // Respect layout constraints (min/max) coming from JS styles
29
- measuredH = std::max<Float>(measuredH, layoutConstraints.minimumSize.height);
30
- measuredH = std::min<Float>(measuredH, layoutConstraints.maximumSize.height);
31
-
32
- Size result{measuredW, measuredH};
33
- return layoutConstraints.clamp(result);
39
+ // If width is 0, use available width from constraints
40
+ const Float kHuge = static_cast<Float>(1.0e9);
41
+ if (measuredW <= 0) {
42
+ const Float maxW = layoutConstraints.maximumSize.width;
43
+ measuredW = (maxW > 0 && maxW < kHuge) ? maxW : 0;
34
44
  }
35
45
 
46
+ // Respect layout constraints
47
+ measuredW = std::max<Float>(measuredW, layoutConstraints.minimumSize.width);
48
+ measuredW = std::min<Float>(measuredW, layoutConstraints.maximumSize.width);
49
+
50
+ measuredH = std::max<Float>(measuredH, layoutConstraints.minimumSize.height);
51
+ measuredH = std::min<Float>(measuredH, layoutConstraints.maximumSize.height);
52
+
53
+ Size result{measuredW, measuredH};
54
+ return layoutConstraints.clamp(result);
55
+ }
56
+
36
57
  } // namespace facebook::react
@@ -2,31 +2,43 @@
2
2
 
3
3
  #include <react/renderer/components/view/ConcreteViewShadowNode.h>
4
4
 
5
- #import <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
6
- #import <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
7
- #import <react/renderer/components/PlatformComponentsViewSpec/Props.h>
5
+ // Only include what we need for the shadow node definition
6
+ // Do NOT include ComponentDescriptors.h here to avoid circular dependency
7
+ #include <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
8
+ #include <react/renderer/components/PlatformComponentsViewSpec/Props.h>
9
+
10
+ #include "PCSelectionMenuState-custom.h"
8
11
 
9
12
  namespace facebook::react {
10
13
 
11
14
  extern const char PCSelectionMenuComponentName[];
12
15
 
13
16
  /**
14
- * ShadowNode for SelectionMenu.
17
+ * Custom ShadowNode for SelectionMenu that supports Yoga measurement.
15
18
  *
16
19
  * Key behavior:
17
- * - Provides a non-zero default measured height (minRowHeight) so the view
18
- * remains tappable when JS does not specify an explicit height.
20
+ * - Native side measures the actual picker and updates state with frameSize
21
+ * - measureContent() returns the size from state for proper Yoga layout
22
+ * - Falls back to platform-specific defaults if state hasn't been set yet
19
23
  */
20
24
  class MeasuringPCSelectionMenuShadowNode final : public ConcreteViewShadowNode<
21
25
  PCSelectionMenuComponentName,
22
26
  PCSelectionMenuProps,
23
27
  PCSelectionMenuEventEmitter,
24
- PCSelectionMenuState> {
28
+ PCSelectionMenuStateFrameSize> {
25
29
  public:
26
30
  using ConcreteViewShadowNode::ConcreteViewShadowNode;
27
31
 
28
- static constexpr float kMinRowHeight = 44.0f;
29
-
32
+ // Fallback heights used when native hasn't reported measurements yet
33
+ // iOS standard row height
34
+ static constexpr float kFallbackHeightIOS = 44.0f;
35
+
36
+ // Android System Spinner height
37
+ static constexpr float kFallbackHeightAndroid = 56.0f;
38
+
39
+ // Android M3 TextInputLayout with floating label height
40
+ static constexpr float kFallbackHeightAndroidM3 = 72.0f;
41
+
30
42
  static ShadowNodeTraits BaseTraits() {
31
43
  auto traits = ConcreteViewShadowNode::BaseTraits();
32
44
  traits.set(ShadowNodeTraits::Trait::LeafYogaNode);
@@ -36,7 +48,8 @@ class MeasuringPCSelectionMenuShadowNode final : public ConcreteViewShadowNode<
36
48
 
37
49
  /**
38
50
  * Called by Yoga when it needs the intrinsic size of the component.
39
- * We ensure a sensible minimum height so the view doesn't measure to 0.
51
+ * Returns the size provided by native through state, with fallback to
52
+ * platform-specific defaults if state hasn't been set.
40
53
  */
41
54
  Size measureContent(
42
55
  const LayoutContext& layoutContext,
@@ -0,0 +1,65 @@
1
+ #pragma once
2
+
3
+ #include <react/renderer/core/LayoutPrimitives.h>
4
+ #include <memory>
5
+
6
+ #ifdef RN_SERIALIZABLE_STATE
7
+ #include <folly/dynamic.h>
8
+ #include <react/renderer/mapbuffer/MapBuffer.h>
9
+ #include <react/renderer/mapbuffer/MapBufferBuilder.h>
10
+ #endif
11
+
12
+ namespace facebook::react {
13
+
14
+ /**
15
+ * Custom state for SelectionMenu that holds the measured frame size from native.
16
+ * This allows the native side to measure the actual picker and communicate
17
+ * the size to the shadow node for proper Yoga layout.
18
+ *
19
+ * Note: Does NOT inherit from StateData (which is final). Custom state types
20
+ * are standalone structs that satisfy the ConcreteState template requirements.
21
+ */
22
+ struct PCSelectionMenuStateFrameSize {
23
+ using Shared = std::shared_ptr<const PCSelectionMenuStateFrameSize>;
24
+
25
+ Size frameSize{}; // {width, height} in points
26
+
27
+ PCSelectionMenuStateFrameSize() = default;
28
+
29
+ explicit PCSelectionMenuStateFrameSize(Size size) : frameSize(size) {}
30
+
31
+ bool operator==(const PCSelectionMenuStateFrameSize& other) const {
32
+ return frameSize.width == other.frameSize.width &&
33
+ frameSize.height == other.frameSize.height;
34
+ }
35
+
36
+ bool operator!=(const PCSelectionMenuStateFrameSize& other) const {
37
+ return !(*this == other);
38
+ }
39
+
40
+ #ifdef RN_SERIALIZABLE_STATE
41
+ // Required for Android state serialization
42
+ PCSelectionMenuStateFrameSize(
43
+ const PCSelectionMenuStateFrameSize& previousState,
44
+ folly::dynamic data)
45
+ : frameSize(previousState.frameSize) {
46
+ // Parse frame size from dynamic data if provided
47
+ if (data.isObject()) {
48
+ if (data.count("width") && data.count("height")) {
49
+ frameSize.width = static_cast<Float>(data["width"].asDouble());
50
+ frameSize.height = static_cast<Float>(data["height"].asDouble());
51
+ }
52
+ }
53
+ }
54
+
55
+ folly::dynamic getDynamic() const {
56
+ return folly::dynamic::object("width", frameSize.width)("height", frameSize.height);
57
+ }
58
+
59
+ MapBuffer getMapBuffer() const {
60
+ return MapBufferBuilder::EMPTY();
61
+ }
62
+ #endif
63
+ };
64
+
65
+ } // namespace facebook::react