react-native-platform-components 1.2.0 → 1.4.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.
Files changed (242) hide show
  1. package/README.md +33 -31
  2. package/android/src/main/java/com/platformcomponents/PCButtonGroupView.kt +498 -0
  3. package/android/src/main/java/com/platformcomponents/PCButtonGroupViewManager.kt +191 -0
  4. package/android/src/main/java/com/platformcomponents/PCButtonSupport.kt +127 -0
  5. package/android/src/main/java/com/platformcomponents/PCButtonView.kt +345 -0
  6. package/android/src/main/java/com/platformcomponents/PCButtonViewManager.kt +126 -0
  7. package/android/src/main/java/com/platformcomponents/PCExpressive.kt +107 -0
  8. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarView.kt +115 -0
  9. package/android/src/main/java/com/platformcomponents/PCFloatingToolbarViewManager.kt +65 -0
  10. package/android/src/main/java/com/platformcomponents/PCNativeThemeModule.kt +3 -0
  11. package/android/src/main/java/com/platformcomponents/PCSegmentedControlView.kt +13 -5
  12. package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +6 -1
  13. package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +1018 -0
  14. package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +248 -0
  15. package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +13 -6
  16. package/android/src/main/jni/CMakeLists.txt +13 -1
  17. package/android/src/main/res/values/attrs.xml +13 -0
  18. package/android/src/main/res/values/styles.xml +183 -0
  19. package/ios/PCButton.h +10 -0
  20. package/ios/PCButton.mm +196 -0
  21. package/ios/PCButtonGroup.h +10 -0
  22. package/ios/PCButtonGroup.mm +256 -0
  23. package/ios/PCButtonGroupView.swift +254 -0
  24. package/ios/PCButtonSupport.swift +141 -0
  25. package/ios/PCButtonView.swift +155 -0
  26. package/ios/PCFloatingToolbar.h +10 -0
  27. package/ios/PCFloatingToolbar.mm +76 -0
  28. package/ios/PCFloatingToolbarView.swift +95 -0
  29. package/ios/PCNativeThemeModule.mm +13 -0
  30. package/ios/PCSelectionMenu.swift +9 -1
  31. package/ios/PCTextField.h +10 -0
  32. package/ios/PCTextField.mm +391 -0
  33. package/ios/PCTextFieldView.swift +1012 -0
  34. package/lib/commonjs/Button.js +77 -0
  35. package/lib/commonjs/Button.js.map +1 -0
  36. package/lib/commonjs/ButtonGroup.js +99 -0
  37. package/lib/commonjs/ButtonGroup.js.map +1 -0
  38. package/lib/commonjs/ButtonGroupNativeComponent.ts +121 -0
  39. package/lib/commonjs/ButtonNativeComponent.ts +76 -0
  40. package/lib/commonjs/ContextMenuNativeComponent.ts +5 -4
  41. package/lib/commonjs/DatePickerNativeComponent.ts +17 -11
  42. package/lib/commonjs/FloatingToolbar.js +69 -0
  43. package/lib/commonjs/FloatingToolbar.js.map +1 -0
  44. package/lib/commonjs/FloatingToolbarNativeComponent.ts +31 -0
  45. package/lib/commonjs/LiquidGlass.js +24 -4
  46. package/lib/commonjs/LiquidGlass.js.map +1 -1
  47. package/lib/commonjs/LiquidGlassNativeComponent.ts +6 -5
  48. package/lib/commonjs/NativePlatformComponentsTheme.js.map +1 -1
  49. package/lib/commonjs/SegmentedControl.js +11 -85
  50. package/lib/commonjs/SegmentedControl.js.map +1 -1
  51. package/lib/commonjs/SegmentedControlNativeComponent.ts +15 -11
  52. package/lib/commonjs/SelectionMenuNativeComponent.ts +6 -5
  53. package/lib/commonjs/TextField.js +195 -0
  54. package/lib/commonjs/TextField.js.map +1 -0
  55. package/lib/commonjs/TextFieldNativeComponent.ts +218 -0
  56. package/lib/commonjs/codegenTypes.js +6 -0
  57. package/lib/commonjs/codegenTypes.js.map +1 -0
  58. package/lib/commonjs/focusRegistry.js +78 -0
  59. package/lib/commonjs/focusRegistry.js.map +1 -0
  60. package/lib/commonjs/icons.js +92 -0
  61. package/lib/commonjs/icons.js.map +1 -0
  62. package/lib/commonjs/index.js +66 -0
  63. package/lib/commonjs/index.js.map +1 -1
  64. package/lib/commonjs/index.web.js +32 -2
  65. package/lib/commonjs/index.web.js.map +1 -1
  66. package/lib/commonjs/labelStyle.js +27 -0
  67. package/lib/commonjs/labelStyle.js.map +1 -0
  68. package/lib/commonjs/reactNativeInternals.d.js +2 -0
  69. package/lib/commonjs/reactNativeInternals.d.js.map +1 -0
  70. package/lib/module/Button.js +70 -0
  71. package/lib/module/Button.js.map +1 -0
  72. package/lib/module/ButtonGroup.js +92 -0
  73. package/lib/module/ButtonGroup.js.map +1 -0
  74. package/lib/module/ButtonGroupNativeComponent.ts +121 -0
  75. package/lib/module/ButtonNativeComponent.ts +76 -0
  76. package/lib/module/ContextMenuNativeComponent.ts +5 -4
  77. package/lib/module/DatePickerNativeComponent.ts +17 -11
  78. package/lib/module/FloatingToolbar.js +62 -0
  79. package/lib/module/FloatingToolbar.js.map +1 -0
  80. package/lib/module/FloatingToolbarNativeComponent.ts +31 -0
  81. package/lib/module/LiquidGlass.js +24 -4
  82. package/lib/module/LiquidGlass.js.map +1 -1
  83. package/lib/module/LiquidGlassNativeComponent.ts +6 -5
  84. package/lib/module/NativePlatformComponentsTheme.js.map +1 -1
  85. package/lib/module/SegmentedControl.js +12 -87
  86. package/lib/module/SegmentedControl.js.map +1 -1
  87. package/lib/module/SegmentedControlNativeComponent.ts +15 -11
  88. package/lib/module/SelectionMenuNativeComponent.ts +6 -5
  89. package/lib/module/TextField.js +189 -0
  90. package/lib/module/TextField.js.map +1 -0
  91. package/lib/module/TextFieldNativeComponent.ts +218 -0
  92. package/lib/module/codegenTypes.js +4 -0
  93. package/lib/module/codegenTypes.js.map +1 -0
  94. package/lib/module/focusRegistry.js +74 -0
  95. package/lib/module/focusRegistry.js.map +1 -0
  96. package/lib/module/icons.js +87 -0
  97. package/lib/module/icons.js.map +1 -0
  98. package/lib/module/index.js +6 -0
  99. package/lib/module/index.js.map +1 -1
  100. package/lib/module/index.web.js +28 -0
  101. package/lib/module/index.web.js.map +1 -1
  102. package/lib/module/labelStyle.js +23 -0
  103. package/lib/module/labelStyle.js.map +1 -0
  104. package/lib/module/reactNativeInternals.d.js +2 -0
  105. package/lib/module/reactNativeInternals.d.js.map +1 -0
  106. package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
  107. package/lib/typescript/commonjs/src/Button.d.ts +76 -0
  108. package/lib/typescript/commonjs/src/Button.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/src/ButtonGroup.d.ts +102 -0
  110. package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +93 -0
  112. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +57 -0
  114. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts +5 -4
  116. package/lib/typescript/commonjs/src/ContextMenuNativeComponent.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts +12 -11
  118. package/lib/typescript/commonjs/src/DatePickerNativeComponent.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +45 -0
  120. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +24 -0
  122. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/src/LiquidGlass.d.ts +4 -3
  124. package/lib/typescript/commonjs/src/LiquidGlass.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts +6 -5
  126. package/lib/typescript/commonjs/src/LiquidGlassNativeComponent.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts +10 -2
  128. package/lib/typescript/commonjs/src/NativePlatformComponentsTheme.d.ts.map +1 -1
  129. package/lib/typescript/commonjs/src/SegmentedControl.d.ts +17 -46
  130. package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +9 -6
  132. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts +6 -5
  134. package/lib/typescript/commonjs/src/SelectionMenuNativeComponent.d.ts.map +1 -1
  135. package/lib/typescript/commonjs/src/TextField.d.ts +174 -0
  136. package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -0
  137. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +162 -0
  138. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -0
  139. package/lib/typescript/commonjs/src/codegenTypes.d.ts +12 -0
  140. package/lib/typescript/commonjs/src/codegenTypes.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/src/focusRegistry.d.ts +13 -0
  142. package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -0
  143. package/lib/typescript/commonjs/src/icons.d.ts +52 -0
  144. package/lib/typescript/commonjs/src/icons.d.ts.map +1 -0
  145. package/lib/typescript/commonjs/src/index.d.ts +6 -0
  146. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  147. package/lib/typescript/commonjs/src/index.web.d.ts +121 -0
  148. package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
  149. package/lib/typescript/commonjs/src/labelStyle.d.ts +20 -0
  150. package/lib/typescript/commonjs/src/labelStyle.d.ts.map +1 -0
  151. package/lib/typescript/commonjs/src/sharedTypes.d.ts +8 -3
  152. package/lib/typescript/commonjs/src/sharedTypes.d.ts.map +1 -1
  153. package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
  154. package/lib/typescript/module/src/Button.d.ts +76 -0
  155. package/lib/typescript/module/src/Button.d.ts.map +1 -0
  156. package/lib/typescript/module/src/ButtonGroup.d.ts +102 -0
  157. package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -0
  158. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +93 -0
  159. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  160. package/lib/typescript/module/src/ButtonNativeComponent.d.ts +57 -0
  161. package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -0
  162. package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts +5 -4
  163. package/lib/typescript/module/src/ContextMenuNativeComponent.d.ts.map +1 -1
  164. package/lib/typescript/module/src/DatePickerNativeComponent.d.ts +12 -11
  165. package/lib/typescript/module/src/DatePickerNativeComponent.d.ts.map +1 -1
  166. package/lib/typescript/module/src/FloatingToolbar.d.ts +45 -0
  167. package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -0
  168. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +24 -0
  169. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  170. package/lib/typescript/module/src/LiquidGlass.d.ts +4 -3
  171. package/lib/typescript/module/src/LiquidGlass.d.ts.map +1 -1
  172. package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts +6 -5
  173. package/lib/typescript/module/src/LiquidGlassNativeComponent.d.ts.map +1 -1
  174. package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts +10 -2
  175. package/lib/typescript/module/src/NativePlatformComponentsTheme.d.ts.map +1 -1
  176. package/lib/typescript/module/src/SegmentedControl.d.ts +17 -46
  177. package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
  178. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +9 -6
  179. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  180. package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts +6 -5
  181. package/lib/typescript/module/src/SelectionMenuNativeComponent.d.ts.map +1 -1
  182. package/lib/typescript/module/src/TextField.d.ts +174 -0
  183. package/lib/typescript/module/src/TextField.d.ts.map +1 -0
  184. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +162 -0
  185. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -0
  186. package/lib/typescript/module/src/codegenTypes.d.ts +12 -0
  187. package/lib/typescript/module/src/codegenTypes.d.ts.map +1 -0
  188. package/lib/typescript/module/src/focusRegistry.d.ts +13 -0
  189. package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -0
  190. package/lib/typescript/module/src/icons.d.ts +52 -0
  191. package/lib/typescript/module/src/icons.d.ts.map +1 -0
  192. package/lib/typescript/module/src/index.d.ts +6 -0
  193. package/lib/typescript/module/src/index.d.ts.map +1 -1
  194. package/lib/typescript/module/src/index.web.d.ts +121 -0
  195. package/lib/typescript/module/src/index.web.d.ts.map +1 -1
  196. package/lib/typescript/module/src/labelStyle.d.ts +20 -0
  197. package/lib/typescript/module/src/labelStyle.d.ts.map +1 -0
  198. package/lib/typescript/module/src/sharedTypes.d.ts +8 -3
  199. package/lib/typescript/module/src/sharedTypes.d.ts.map +1 -1
  200. package/package.json +28 -6
  201. package/react-native.config.js +3 -0
  202. package/shared/PCButtonComponentDescriptors-custom.h +22 -0
  203. package/shared/PCButtonGroupComponentDescriptors-custom.h +22 -0
  204. package/shared/PCButtonGroupShadowNode-custom.cpp +48 -0
  205. package/shared/PCButtonGroupShadowNode-custom.h +55 -0
  206. package/shared/PCButtonGroupState-custom.h +61 -0
  207. package/shared/PCButtonShadowNode-custom.cpp +48 -0
  208. package/shared/PCButtonShadowNode-custom.h +55 -0
  209. package/shared/PCButtonState-custom.h +61 -0
  210. package/shared/PCDatePickerState-custom.h +2 -2
  211. package/shared/PCSegmentedControlState-custom.h +2 -2
  212. package/shared/PCSelectionMenuState-custom.h +2 -2
  213. package/shared/PCTextFieldComponentDescriptors-custom.h +22 -0
  214. package/shared/PCTextFieldShadowNode-custom.cpp +47 -0
  215. package/shared/PCTextFieldShadowNode-custom.h +55 -0
  216. package/shared/PCTextFieldState-custom.h +61 -0
  217. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
  218. package/src/Button.tsx +144 -0
  219. package/src/ButtonGroup.tsx +233 -0
  220. package/src/ButtonGroupNativeComponent.ts +121 -0
  221. package/src/ButtonNativeComponent.ts +76 -0
  222. package/src/ContextMenuNativeComponent.ts +5 -4
  223. package/src/DatePickerNativeComponent.ts +17 -11
  224. package/src/FloatingToolbar.tsx +113 -0
  225. package/src/FloatingToolbarNativeComponent.ts +31 -0
  226. package/src/LiquidGlass.tsx +24 -5
  227. package/src/LiquidGlassNativeComponent.ts +6 -5
  228. package/src/NativePlatformComponentsTheme.ts +11 -2
  229. package/src/SegmentedControl.tsx +26 -118
  230. package/src/SegmentedControlNativeComponent.ts +15 -11
  231. package/src/SelectionMenuNativeComponent.ts +6 -5
  232. package/src/TextField.tsx +494 -0
  233. package/src/TextFieldNativeComponent.ts +218 -0
  234. package/src/codegenTypes.ts +40 -0
  235. package/src/focusRegistry.ts +89 -0
  236. package/src/icons.ts +116 -0
  237. package/src/index.tsx +6 -0
  238. package/src/index.web.tsx +194 -0
  239. package/src/labelStyle.ts +36 -0
  240. package/src/reactNativeInternals.d.ts +22 -0
  241. package/src/sharedTypes.ts +9 -3
  242. /package/{app.plugin.cjs → app.plugin.js} +0 -0
@@ -0,0 +1,126 @@
1
+ package com.platformcomponents
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.uimanager.ReactStylesDiffMap
6
+ import com.facebook.react.uimanager.SimpleViewManager
7
+ import com.facebook.react.uimanager.StateWrapper
8
+ import com.facebook.react.uimanager.ThemedReactContext
9
+ import com.facebook.react.uimanager.UIManagerHelper
10
+ import com.facebook.react.uimanager.ViewManagerDelegate
11
+ import com.facebook.react.uimanager.events.Event
12
+ import com.facebook.react.uimanager.events.RCTEventEmitter
13
+ import com.facebook.react.viewmanagers.PCButtonManagerDelegate
14
+ import com.facebook.react.viewmanagers.PCButtonManagerInterface
15
+ import com.platformcomponents.PCButtonSupport.doubleOr
16
+ import com.platformcomponents.PCButtonSupport.stringOr
17
+
18
+ class PCButtonViewManager :
19
+ SimpleViewManager<PCButtonView>(),
20
+ PCButtonManagerInterface<PCButtonView> {
21
+
22
+ companion object {
23
+ private const val TAG = "PCButton"
24
+ }
25
+
26
+ private val delegate: ViewManagerDelegate<PCButtonView> = PCButtonManagerDelegate(this)
27
+
28
+ override fun getName(): String = "PCButton"
29
+
30
+ override fun getDelegate(): ViewManagerDelegate<PCButtonView> = delegate
31
+
32
+ override fun createViewInstance(reactContext: ThemedReactContext): PCButtonView {
33
+ return PCButtonView(reactContext)
34
+ }
35
+
36
+ /**
37
+ * Pass the StateWrapper to the view so it can update Fabric state with its
38
+ * natural size, and report it right away so the first layout already fits.
39
+ */
40
+ override fun updateState(
41
+ view: PCButtonView,
42
+ props: ReactStylesDiffMap,
43
+ stateWrapper: StateWrapper
44
+ ): Any? {
45
+ view.stateWrapper = stateWrapper
46
+ view.reportIntrinsicSize()
47
+ return null
48
+ }
49
+
50
+ override fun addEventEmitters(reactContext: ThemedReactContext, view: PCButtonView) {
51
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
52
+
53
+ view.onPress = {
54
+ dispatcher?.dispatchEvent(PressEvent(view.id))
55
+ }
56
+ }
57
+
58
+ override fun setLabel(view: PCButtonView, value: String?) {
59
+ view.applyLabel(value ?: "")
60
+ }
61
+
62
+ // icon: {iconType, iconName, iconUri, iconScale, iconTinted}
63
+ override fun setIcon(view: PCButtonView, value: ReadableMap?) {
64
+ view.applyIcon(PCButtonSupport.parseIcon(value))
65
+ }
66
+
67
+ override fun setVariant(view: PCButtonView, value: String?) {
68
+ view.applyVariant(value)
69
+ }
70
+
71
+ override fun setSize(view: PCButtonView, value: String?) {
72
+ view.applySize(value)
73
+ }
74
+
75
+ override fun setShape(view: PCButtonView, value: String?) {
76
+ view.applyShape(value)
77
+ }
78
+
79
+ override fun setInteractivity(view: PCButtonView, value: String?) {
80
+ view.applyInteractivity(value)
81
+ }
82
+
83
+ // Colors arrive already processed by React Native (ARGB ints)
84
+ override fun setColor(view: PCButtonView, value: Int?) {
85
+ view.applyColors(value, view.foregroundColor, view.rippleColor, view.strokeColor)
86
+ }
87
+
88
+ override fun setForegroundColor(view: PCButtonView, value: Int?) {
89
+ view.applyColors(view.containerColor, value, view.rippleColor, view.strokeColor)
90
+ }
91
+
92
+ override fun setAndroidRippleColor(view: PCButtonView, value: Int?) {
93
+ view.applyColors(view.containerColor, view.foregroundColor, value, view.strokeColor)
94
+ }
95
+
96
+ override fun setAndroidStrokeColor(view: PCButtonView, value: Int?) {
97
+ view.applyColors(view.containerColor, view.foregroundColor, view.rippleColor, value)
98
+ }
99
+
100
+ // labelStyle: {fontFamily, fontSize, fontWeight, fontStyle}; empty / 0 = default
101
+ override fun setLabelStyle(view: PCButtonView, value: ReadableMap?) {
102
+ view.applyLabelStyle(
103
+ fontFamily = value?.stringOr("fontFamily", "") ?: "",
104
+ fontSize = value?.doubleOr("fontSize", 0.0)?.toFloat() ?: 0f,
105
+ fontWeight = value?.stringOr("fontWeight", "") ?: "",
106
+ fontStyle = value?.stringOr("fontStyle", "") ?: ""
107
+ )
108
+ }
109
+
110
+ override fun setSpokenLabel(view: PCButtonView, value: String?) {
111
+ view.applySpokenLabel(value ?: "")
112
+ }
113
+
114
+ // "expressive" (default) | "m3"
115
+ override fun setAndroidMaterial(view: PCButtonView, value: String?) {
116
+ view.applyMaterial(value)
117
+ }
118
+
119
+ // --- Events ---
120
+ private class PressEvent(surfaceId: Int) : Event<PressEvent>(surfaceId) {
121
+ override fun getEventName(): String = "topButtonPress"
122
+ override fun dispatch(rctEventEmitter: RCTEventEmitter) {
123
+ rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap())
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,107 @@
1
+ package com.platformcomponents
2
+
3
+ import android.content.Context
4
+ import android.view.ContextThemeWrapper
5
+ import androidx.appcompat.R as AppCompatR
6
+ import com.google.android.material.R as MaterialR
7
+ import com.google.android.material.button.MaterialButton
8
+
9
+ /**
10
+ * Material 3 Expressive contexts and styles for Button and ButtonGroup.
11
+ *
12
+ * The Expressive look is a set of widget styles (PCExpressiveOverlay in
13
+ * styles.xml) layered over the host theme, plus one of Material's size overlays,
14
+ * which the Expressive button styles read their padding, icon size, label style
15
+ * and shapes from.
16
+ */
17
+ object PCExpressive {
18
+ enum class Variant { FILLED, TONAL, OUTLINED, TEXT, ELEVATED }
19
+
20
+ fun parseVariant(value: String?): Variant =
21
+ when (value) {
22
+ "tonal" -> Variant.TONAL
23
+ "outlined" -> Variant.OUTLINED
24
+ "text" -> Variant.TEXT
25
+ "elevated" -> Variant.ELEVATED
26
+ else -> Variant.FILLED
27
+ }
28
+
29
+ /** "xsmall" | "small" | "medium" | "large" | "xlarge" */
30
+ fun parseSize(value: String?): String =
31
+ when (value) {
32
+ "xsmall", "medium", "large", "xlarge" -> value
33
+ else -> "small"
34
+ }
35
+
36
+ /** "round" | "square"; the spec's empty string is the Material default, round. */
37
+ fun parseShape(value: String?): String = if (value == "square") "square" else "round"
38
+
39
+ /**
40
+ * The theme overlay choosing the buttons' size and shape (PCSize.* in
41
+ * styles.xml): it sets the size overlay attributes the library's button
42
+ * styles read, for text buttons and for icon-only buttons, which use
43
+ * Material's square icon button sizes.
44
+ */
45
+ fun sizeOverlay(size: String, shape: String): Int {
46
+ val square = shape == "square"
47
+ return when (size) {
48
+ "xsmall" -> if (square) R.style.PCSize_Xsmall_Square else R.style.PCSize_Xsmall
49
+ "medium" -> if (square) R.style.PCSize_Medium_Square else R.style.PCSize_Medium
50
+ "large" -> if (square) R.style.PCSize_Large_Square else R.style.PCSize_Large
51
+ "xlarge" -> if (square) R.style.PCSize_Xlarge_Square else R.style.PCSize_Xlarge
52
+ else -> if (square) R.style.PCSize_Small_Square else R.style.PCSize_Small
53
+ }
54
+ }
55
+
56
+ /** The theme attribute naming the widget style for a variant. */
57
+ fun styleAttr(variant: Variant, iconOnly: Boolean): Int =
58
+ if (iconOnly) {
59
+ when (variant) {
60
+ Variant.FILLED -> MaterialR.attr.materialIconButtonFilledStyle
61
+ Variant.TONAL -> MaterialR.attr.materialIconButtonFilledTonalStyle
62
+ Variant.OUTLINED -> MaterialR.attr.materialIconButtonOutlinedStyle
63
+ Variant.TEXT, Variant.ELEVATED -> MaterialR.attr.materialIconButtonStyle
64
+ }
65
+ } else {
66
+ when (variant) {
67
+ Variant.FILLED -> MaterialR.attr.materialButtonStyle
68
+ Variant.TONAL -> MaterialR.attr.materialButtonTonalStyle
69
+ Variant.OUTLINED -> MaterialR.attr.materialButtonOutlinedStyle
70
+ Variant.TEXT -> AppCompatR.attr.borderlessButtonStyle
71
+ Variant.ELEVATED -> MaterialR.attr.materialButtonElevatedStyle
72
+ }
73
+ }
74
+
75
+ /** "expressive" (default) | "m3" */
76
+ fun parseExpressive(value: String?): Boolean = value != "m3"
77
+
78
+ /**
79
+ * Creates a button. [base] is a Material 3 context (see
80
+ * PCThemeSupport.materialContext); [toolbarOverlay] is the enclosing
81
+ * FloatingToolbar's button overlay, or 0 outside a toolbar.
82
+ *
83
+ * With [expressive] the Material 3 Expressive styles apply, sized by the
84
+ * size overlay; otherwise the theme's classic Material 3 button styles,
85
+ * which have one size and shape. The toolbar overlay replaces the filled,
86
+ * text and standard icon button styles with the toolbar's, as it does for
87
+ * XML children of a FloatingToolbarLayout; the toolbar itself is an
88
+ * Expressive component, so its buttons always are.
89
+ */
90
+ fun createButton(
91
+ base: Context,
92
+ variant: Variant,
93
+ size: String,
94
+ shape: String,
95
+ iconOnly: Boolean,
96
+ toolbarOverlay: Int,
97
+ expressive: Boolean = true
98
+ ): MaterialButton {
99
+ if (!expressive && toolbarOverlay == 0) {
100
+ return MaterialButton(base, null, styleAttr(variant, iconOnly))
101
+ }
102
+ val overlaid = ContextThemeWrapper(base, R.style.PCExpressiveOverlay)
103
+ val themed = if (toolbarOverlay != 0) ContextThemeWrapper(overlaid, toolbarOverlay) else overlaid
104
+ val sized = ContextThemeWrapper(themed, sizeOverlay(size, shape))
105
+ return MaterialButton(sized, null, styleAttr(variant, iconOnly))
106
+ }
107
+ }
@@ -0,0 +1,115 @@
1
+ package com.platformcomponents
2
+
3
+ import android.content.Context
4
+ import android.content.res.ColorStateList
5
+ import android.graphics.Color
6
+ import androidx.core.content.res.ResourcesCompat
7
+ import com.google.android.material.R as MaterialR
8
+ import com.google.android.material.color.MaterialColors
9
+ import com.google.android.material.floatingtoolbar.FloatingToolbarLayout
10
+ import com.google.android.material.shape.MaterialShapeDrawable
11
+
12
+ /**
13
+ * A Material 3 floating toolbar. The Material container (shape, elevation,
14
+ * color) hosts React children, which Fabric lays out itself.
15
+ */
16
+ class PCFloatingToolbarView(context: Context) :
17
+ FloatingToolbarLayout(
18
+ // Material widgets need a Material theme; fall back to Material 3 defaults instead of crashing.
19
+ PCThemeSupport.materialContext(context, "FloatingToolbar"),
20
+ null,
21
+ 0,
22
+ R.style.PCFloatingToolbar
23
+ ) {
24
+
25
+ companion object {
26
+ private const val TAG = "PCFloatingToolbar"
27
+ }
28
+
29
+ // --- Props ---
30
+ var variant: String = "standard" // "standard" | "vibrant"
31
+ var color: Int? = null
32
+
33
+ /** The button overlay for Buttons inside this toolbar (see PCButtonView). */
34
+ val buttonOverlay: Int
35
+ get() = if (variant == "vibrant") R.style.PCToolbarOverlay_Vibrant else R.style.PCToolbarOverlay
36
+
37
+ // --- Native theme ---
38
+ private val nativeThemeListener = PCNativeTheme.Listener {
39
+ ResourcesCompat.clearCachesForTheme(context.theme)
40
+ applyColors()
41
+ }
42
+
43
+ init {
44
+ clipChildren = false
45
+ clipToPadding = false
46
+ applyColors()
47
+ }
48
+
49
+ // ---- Public apply* (called by manager) ----
50
+
51
+ fun applyVariant(value: String?) {
52
+ val parsed = if (value == "vibrant") "vibrant" else "standard"
53
+ if (variant == parsed) return
54
+ variant = parsed
55
+ applyColors()
56
+ // Buttons inside take the toolbar's button styles
57
+ for (i in 0 until childCount) {
58
+ (getChildAt(i) as? PCButtonView)?.refreshToolbarStyle()
59
+ }
60
+ }
61
+
62
+ fun applyColor(value: Int?) {
63
+ if (color == value) return
64
+ color = value
65
+ applyColors()
66
+ }
67
+
68
+ /**
69
+ * A `backgroundColor` style would replace the Material shape; route it into
70
+ * the color instead. React Native resets it with transparent.
71
+ */
72
+ override fun setBackgroundColor(color: Int) {
73
+ applyColor(if (color == Color.TRANSPARENT) null else color)
74
+ }
75
+
76
+ private fun applyColors() {
77
+ val resolved = color ?: MaterialColors.getColor(
78
+ this,
79
+ if (variant == "vibrant") MaterialR.attr.colorPrimaryContainer else MaterialR.attr.colorSurfaceContainer,
80
+ Color.TRANSPARENT
81
+ )
82
+ val shape = background as? MaterialShapeDrawable
83
+ if (shape != null) {
84
+ shape.fillColor = ColorStateList.valueOf(resolved)
85
+ } else {
86
+ backgroundTintList = ColorStateList.valueOf(resolved)
87
+ }
88
+ }
89
+
90
+ override fun onAttachedToWindow() {
91
+ super.onAttachedToWindow()
92
+ PCNativeTheme.addListener(nativeThemeListener)
93
+ PCNativeTheme.attach(context)
94
+ }
95
+
96
+ override fun onDetachedFromWindow() {
97
+ PCNativeTheme.removeListener(nativeThemeListener)
98
+ super.onDetachedFromWindow()
99
+ }
100
+
101
+ // ---- Layout ----
102
+ // Fabric sizes this view and positions its children; FrameLayout must not
103
+ // re-measure or re-position them against its own padding and gravity.
104
+
105
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
106
+ setMeasuredDimension(
107
+ MeasureSpec.getSize(widthMeasureSpec),
108
+ MeasureSpec.getSize(heightMeasureSpec)
109
+ )
110
+ }
111
+
112
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
113
+ // No-op: Fabric lays out the children
114
+ }
115
+ }
@@ -0,0 +1,65 @@
1
+ package com.platformcomponents
2
+
3
+ import android.view.View
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.uimanager.ThemedReactContext
6
+ import com.facebook.react.uimanager.ViewGroupManager
7
+ import com.facebook.react.uimanager.ViewManagerDelegate
8
+ import com.facebook.react.viewmanagers.PCFloatingToolbarManagerDelegate
9
+ import com.facebook.react.viewmanagers.PCFloatingToolbarManagerInterface
10
+ import com.platformcomponents.PCButtonSupport.stringOr
11
+
12
+ /**
13
+ * Android ViewManager for FloatingToolbar. Uses ViewGroupManager since the
14
+ * toolbar hosts React children.
15
+ */
16
+ class PCFloatingToolbarViewManager :
17
+ ViewGroupManager<PCFloatingToolbarView>(),
18
+ PCFloatingToolbarManagerInterface<PCFloatingToolbarView> {
19
+
20
+ companion object {
21
+ private const val TAG = "PCFloatingToolbar"
22
+ }
23
+
24
+ private val delegate: ViewManagerDelegate<PCFloatingToolbarView> =
25
+ PCFloatingToolbarManagerDelegate(this)
26
+
27
+ override fun getName(): String = "PCFloatingToolbar"
28
+
29
+ override fun getDelegate(): ViewManagerDelegate<PCFloatingToolbarView> = delegate
30
+
31
+ override fun createViewInstance(reactContext: ThemedReactContext): PCFloatingToolbarView {
32
+ return PCFloatingToolbarView(reactContext)
33
+ }
34
+
35
+ // Colors arrive already processed by React Native (ARGB ints)
36
+ override fun setColor(view: PCFloatingToolbarView, value: Int?) {
37
+ view.applyColor(value)
38
+ }
39
+
40
+ override fun setIos(view: PCFloatingToolbarView, value: ReadableMap?) {
41
+ // iOS props are ignored on Android
42
+ }
43
+
44
+ // android: {variant}
45
+ override fun setAndroid(view: PCFloatingToolbarView, value: ReadableMap?) {
46
+ view.applyVariant(value?.stringOr("variant", "standard"))
47
+ }
48
+
49
+ // --- ViewGroupManager child management ---
50
+ override fun addView(parent: PCFloatingToolbarView, child: View, index: Int) {
51
+ parent.addView(child, index)
52
+ }
53
+
54
+ override fun removeViewAt(parent: PCFloatingToolbarView, index: Int) {
55
+ parent.removeViewAt(index)
56
+ }
57
+
58
+ override fun getChildCount(parent: PCFloatingToolbarView): Int {
59
+ return parent.childCount
60
+ }
61
+
62
+ override fun getChildAt(parent: PCFloatingToolbarView, index: Int): View? {
63
+ return parent.getChildAt(index)
64
+ }
65
+ }
@@ -35,6 +35,9 @@ class PCNativeThemeModule(reactContext: ReactApplicationContext) :
35
35
  }
36
36
  }
37
37
 
38
+ /** Liquid Glass is an iOS effect; Android renders the fallback View. */
39
+ override fun isLiquidGlassSupported(): Boolean = false
40
+
38
41
  companion object {
39
42
  const val NAME = "PlatformComponentsTheme"
40
43
  private const val TAG = "PlatformComponents"
@@ -6,6 +6,7 @@ import android.graphics.Color
6
6
  import android.graphics.drawable.BitmapDrawable
7
7
  import android.text.TextUtils
8
8
  import android.util.TypedValue
9
+ import android.view.ContextThemeWrapper
9
10
  import android.view.View
10
11
  import android.widget.FrameLayout
11
12
  import android.widget.LinearLayout
@@ -66,6 +67,8 @@ class PCSegmentedControlView(context: Context) :
66
67
  var labelVisibility: String = "auto" // "auto" | "labeled" | "unlabeled"
67
68
  // Matches iOS, where a UISegmentedControl selection cannot be cleared by tapping.
68
69
  var selectionRequired: Boolean = true
70
+ // android.material: "expressive" (the Material 3 Expressive connected buttons) | "m3"
71
+ var expressive: Boolean = true
69
72
 
70
73
  // --- Styling (null / empty = Material theme default) ---
71
74
  var selectedSegmentColor: Int? = null
@@ -140,9 +143,10 @@ class PCSegmentedControlView(context: Context) :
140
143
  rebuildUI()
141
144
  }
142
145
 
143
- fun applyAndroidProps(required: Boolean) {
144
- if (selectionRequired != required) {
146
+ fun applyAndroidProps(required: Boolean, expressiveStyle: Boolean) {
147
+ if (selectionRequired != required || expressive != expressiveStyle) {
145
148
  selectionRequired = required
149
+ expressive = expressiveStyle
146
150
  rebuildUI()
147
151
  }
148
152
  }
@@ -224,7 +228,11 @@ class PCSegmentedControlView(context: Context) :
224
228
  val generation = rebuildGeneration
225
229
 
226
230
  // Material widgets need a Material theme; fall back to Material 3 defaults instead of crashing.
227
- val themedContext = PCThemeSupport.materialContext(context, "SegmentedControl")
231
+ val materialContext = PCThemeSupport.materialContext(context, "SegmentedControl")
232
+ // Expressive: the connected button group styles (2dp gaps, small inner
233
+ // corners, the selected segment a pill) in place of the classic segmented buttons.
234
+ val themedContext =
235
+ if (expressive) ContextThemeWrapper(materialContext, R.style.PCExpressiveOverlay) else materialContext
228
236
  val group = MaterialButtonToggleGroup(themedContext).apply {
229
237
  layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
230
238
  isSingleSelection = true
@@ -319,13 +327,13 @@ class PCSegmentedControlView(context: Context) :
319
327
 
320
328
  when (segment.iconType) {
321
329
  "drawable" -> {
322
- button.icon = ResourceDrawableIdHelper.getResourceDrawable(context, segment.iconName)
330
+ button.icon = ResourceDrawableIdHelper.instance.getResourceDrawable(context, segment.iconName)
323
331
  }
324
332
  "image" -> {
325
333
  val uri = segment.iconUri
326
334
  val isResourceName = !uri.contains(':')
327
335
  if (isResourceName) {
328
- button.icon = ResourceDrawableIdHelper.getResourceDrawable(context, uri)
336
+ button.icon = ResourceDrawableIdHelper.instance.getResourceDrawable(context, uri)
329
337
  } else {
330
338
  PCImageLoader.load(context, uri, segment.iconScale) { bitmap ->
331
339
  if (bitmap == null || generation != rebuildGeneration) return@load
@@ -146,7 +146,12 @@ class PCSegmentedControlViewManager :
146
146
  } else {
147
147
  true
148
148
  }
149
- view.applyAndroidProps(selectionRequired)
149
+ // Spec sentinel: "expressive" (default) | "m3"
150
+ val expressive = !(
151
+ value != null && value.hasKey("material") && !value.isNull("material") &&
152
+ value.getString("material") == "m3"
153
+ )
154
+ view.applyAndroidProps(selectionRequired, expressive)
150
155
  }
151
156
 
152
157
  override fun setIos(view: PCSegmentedControlView, value: ReadableMap?) {