react-native-platform-components 1.3.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 (181) hide show
  1. package/README.md +24 -30
  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/PCSegmentedControlView.kt +11 -3
  11. package/android/src/main/java/com/platformcomponents/PCSegmentedControlViewManager.kt +6 -1
  12. package/android/src/main/java/com/platformcomponents/PCTextFieldView.kt +1018 -0
  13. package/android/src/main/java/com/platformcomponents/PCTextFieldViewManager.kt +248 -0
  14. package/android/src/main/java/com/platformcomponents/PlatformComponentsPackage.kt +4 -0
  15. package/android/src/main/res/values/attrs.xml +13 -0
  16. package/android/src/main/res/values/styles.xml +183 -0
  17. package/ios/PCButton.h +10 -0
  18. package/ios/PCButton.mm +196 -0
  19. package/ios/PCButtonGroup.h +10 -0
  20. package/ios/PCButtonGroup.mm +256 -0
  21. package/ios/PCButtonGroupView.swift +254 -0
  22. package/ios/PCButtonSupport.swift +141 -0
  23. package/ios/PCButtonView.swift +155 -0
  24. package/ios/PCFloatingToolbar.h +10 -0
  25. package/ios/PCFloatingToolbar.mm +76 -0
  26. package/ios/PCFloatingToolbarView.swift +95 -0
  27. package/ios/PCTextField.h +10 -0
  28. package/ios/PCTextField.mm +391 -0
  29. package/ios/PCTextFieldView.swift +1012 -0
  30. package/lib/commonjs/Button.js +77 -0
  31. package/lib/commonjs/Button.js.map +1 -0
  32. package/lib/commonjs/ButtonGroup.js +99 -0
  33. package/lib/commonjs/ButtonGroup.js.map +1 -0
  34. package/lib/commonjs/ButtonGroupNativeComponent.ts +121 -0
  35. package/lib/commonjs/ButtonNativeComponent.ts +76 -0
  36. package/lib/commonjs/FloatingToolbar.js +69 -0
  37. package/lib/commonjs/FloatingToolbar.js.map +1 -0
  38. package/lib/commonjs/FloatingToolbarNativeComponent.ts +31 -0
  39. package/lib/commonjs/SegmentedControl.js +11 -85
  40. package/lib/commonjs/SegmentedControl.js.map +1 -1
  41. package/lib/commonjs/SegmentedControlNativeComponent.ts +3 -0
  42. package/lib/commonjs/TextField.js +195 -0
  43. package/lib/commonjs/TextField.js.map +1 -0
  44. package/lib/commonjs/TextFieldNativeComponent.ts +218 -0
  45. package/lib/commonjs/focusRegistry.js +78 -0
  46. package/lib/commonjs/focusRegistry.js.map +1 -0
  47. package/lib/commonjs/icons.js +92 -0
  48. package/lib/commonjs/icons.js.map +1 -0
  49. package/lib/commonjs/index.js +66 -0
  50. package/lib/commonjs/index.js.map +1 -1
  51. package/lib/commonjs/index.web.js +32 -2
  52. package/lib/commonjs/index.web.js.map +1 -1
  53. package/lib/commonjs/labelStyle.js +27 -0
  54. package/lib/commonjs/labelStyle.js.map +1 -0
  55. package/lib/commonjs/reactNativeInternals.d.js +2 -0
  56. package/lib/commonjs/reactNativeInternals.d.js.map +1 -0
  57. package/lib/module/Button.js +70 -0
  58. package/lib/module/Button.js.map +1 -0
  59. package/lib/module/ButtonGroup.js +92 -0
  60. package/lib/module/ButtonGroup.js.map +1 -0
  61. package/lib/module/ButtonGroupNativeComponent.ts +121 -0
  62. package/lib/module/ButtonNativeComponent.ts +76 -0
  63. package/lib/module/FloatingToolbar.js +62 -0
  64. package/lib/module/FloatingToolbar.js.map +1 -0
  65. package/lib/module/FloatingToolbarNativeComponent.ts +31 -0
  66. package/lib/module/SegmentedControl.js +12 -87
  67. package/lib/module/SegmentedControl.js.map +1 -1
  68. package/lib/module/SegmentedControlNativeComponent.ts +3 -0
  69. package/lib/module/TextField.js +189 -0
  70. package/lib/module/TextField.js.map +1 -0
  71. package/lib/module/TextFieldNativeComponent.ts +218 -0
  72. package/lib/module/focusRegistry.js +74 -0
  73. package/lib/module/focusRegistry.js.map +1 -0
  74. package/lib/module/icons.js +87 -0
  75. package/lib/module/icons.js.map +1 -0
  76. package/lib/module/index.js +6 -0
  77. package/lib/module/index.js.map +1 -1
  78. package/lib/module/index.web.js +28 -0
  79. package/lib/module/index.web.js.map +1 -1
  80. package/lib/module/labelStyle.js +23 -0
  81. package/lib/module/labelStyle.js.map +1 -0
  82. package/lib/module/reactNativeInternals.d.js +2 -0
  83. package/lib/module/reactNativeInternals.d.js.map +1 -0
  84. package/lib/typescript/commonjs/docs/sidebars.d.ts.map +1 -1
  85. package/lib/typescript/commonjs/src/Button.d.ts +76 -0
  86. package/lib/typescript/commonjs/src/Button.d.ts.map +1 -0
  87. package/lib/typescript/commonjs/src/ButtonGroup.d.ts +102 -0
  88. package/lib/typescript/commonjs/src/ButtonGroup.d.ts.map +1 -0
  89. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts +93 -0
  90. package/lib/typescript/commonjs/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  91. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts +57 -0
  92. package/lib/typescript/commonjs/src/ButtonNativeComponent.d.ts.map +1 -0
  93. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts +45 -0
  94. package/lib/typescript/commonjs/src/FloatingToolbar.d.ts.map +1 -0
  95. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts +24 -0
  96. package/lib/typescript/commonjs/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  97. package/lib/typescript/commonjs/src/SegmentedControl.d.ts +17 -46
  98. package/lib/typescript/commonjs/src/SegmentedControl.d.ts.map +1 -1
  99. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts +2 -0
  100. package/lib/typescript/commonjs/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  101. package/lib/typescript/commonjs/src/TextField.d.ts +174 -0
  102. package/lib/typescript/commonjs/src/TextField.d.ts.map +1 -0
  103. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts +162 -0
  104. package/lib/typescript/commonjs/src/TextFieldNativeComponent.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/src/focusRegistry.d.ts +13 -0
  106. package/lib/typescript/commonjs/src/focusRegistry.d.ts.map +1 -0
  107. package/lib/typescript/commonjs/src/icons.d.ts +52 -0
  108. package/lib/typescript/commonjs/src/icons.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/src/index.d.ts +6 -0
  110. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  111. package/lib/typescript/commonjs/src/index.web.d.ts +121 -0
  112. package/lib/typescript/commonjs/src/index.web.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/src/labelStyle.d.ts +20 -0
  114. package/lib/typescript/commonjs/src/labelStyle.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/src/sharedTypes.d.ts +6 -1
  116. package/lib/typescript/commonjs/src/sharedTypes.d.ts.map +1 -1
  117. package/lib/typescript/module/docs/sidebars.d.ts.map +1 -1
  118. package/lib/typescript/module/src/Button.d.ts +76 -0
  119. package/lib/typescript/module/src/Button.d.ts.map +1 -0
  120. package/lib/typescript/module/src/ButtonGroup.d.ts +102 -0
  121. package/lib/typescript/module/src/ButtonGroup.d.ts.map +1 -0
  122. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts +93 -0
  123. package/lib/typescript/module/src/ButtonGroupNativeComponent.d.ts.map +1 -0
  124. package/lib/typescript/module/src/ButtonNativeComponent.d.ts +57 -0
  125. package/lib/typescript/module/src/ButtonNativeComponent.d.ts.map +1 -0
  126. package/lib/typescript/module/src/FloatingToolbar.d.ts +45 -0
  127. package/lib/typescript/module/src/FloatingToolbar.d.ts.map +1 -0
  128. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts +24 -0
  129. package/lib/typescript/module/src/FloatingToolbarNativeComponent.d.ts.map +1 -0
  130. package/lib/typescript/module/src/SegmentedControl.d.ts +17 -46
  131. package/lib/typescript/module/src/SegmentedControl.d.ts.map +1 -1
  132. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts +2 -0
  133. package/lib/typescript/module/src/SegmentedControlNativeComponent.d.ts.map +1 -1
  134. package/lib/typescript/module/src/TextField.d.ts +174 -0
  135. package/lib/typescript/module/src/TextField.d.ts.map +1 -0
  136. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts +162 -0
  137. package/lib/typescript/module/src/TextFieldNativeComponent.d.ts.map +1 -0
  138. package/lib/typescript/module/src/focusRegistry.d.ts +13 -0
  139. package/lib/typescript/module/src/focusRegistry.d.ts.map +1 -0
  140. package/lib/typescript/module/src/icons.d.ts +52 -0
  141. package/lib/typescript/module/src/icons.d.ts.map +1 -0
  142. package/lib/typescript/module/src/index.d.ts +6 -0
  143. package/lib/typescript/module/src/index.d.ts.map +1 -1
  144. package/lib/typescript/module/src/index.web.d.ts +121 -0
  145. package/lib/typescript/module/src/index.web.d.ts.map +1 -1
  146. package/lib/typescript/module/src/labelStyle.d.ts +20 -0
  147. package/lib/typescript/module/src/labelStyle.d.ts.map +1 -0
  148. package/lib/typescript/module/src/sharedTypes.d.ts +6 -1
  149. package/lib/typescript/module/src/sharedTypes.d.ts.map +1 -1
  150. package/package.json +25 -4
  151. package/react-native.config.js +3 -0
  152. package/shared/PCButtonComponentDescriptors-custom.h +22 -0
  153. package/shared/PCButtonGroupComponentDescriptors-custom.h +22 -0
  154. package/shared/PCButtonGroupShadowNode-custom.cpp +48 -0
  155. package/shared/PCButtonGroupShadowNode-custom.h +55 -0
  156. package/shared/PCButtonGroupState-custom.h +61 -0
  157. package/shared/PCButtonShadowNode-custom.cpp +48 -0
  158. package/shared/PCButtonShadowNode-custom.h +55 -0
  159. package/shared/PCButtonState-custom.h +61 -0
  160. package/shared/PCTextFieldComponentDescriptors-custom.h +22 -0
  161. package/shared/PCTextFieldShadowNode-custom.cpp +47 -0
  162. package/shared/PCTextFieldShadowNode-custom.h +55 -0
  163. package/shared/PCTextFieldState-custom.h +61 -0
  164. package/shared/react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h +3 -0
  165. package/src/Button.tsx +144 -0
  166. package/src/ButtonGroup.tsx +233 -0
  167. package/src/ButtonGroupNativeComponent.ts +121 -0
  168. package/src/ButtonNativeComponent.ts +76 -0
  169. package/src/FloatingToolbar.tsx +113 -0
  170. package/src/FloatingToolbarNativeComponent.ts +31 -0
  171. package/src/SegmentedControl.tsx +26 -118
  172. package/src/SegmentedControlNativeComponent.ts +3 -0
  173. package/src/TextField.tsx +494 -0
  174. package/src/TextFieldNativeComponent.ts +218 -0
  175. package/src/focusRegistry.ts +89 -0
  176. package/src/icons.ts +116 -0
  177. package/src/index.tsx +6 -0
  178. package/src/index.web.tsx +194 -0
  179. package/src/labelStyle.ts +36 -0
  180. package/src/reactNativeInternals.d.ts +22 -0
  181. package/src/sharedTypes.ts +7 -1
@@ -0,0 +1,248 @@
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.PCTextFieldManagerDelegate
14
+ import com.facebook.react.viewmanagers.PCTextFieldManagerInterface
15
+ import com.platformcomponents.PCButtonSupport.doubleOr
16
+ import com.platformcomponents.PCButtonSupport.stringOr
17
+
18
+ class PCTextFieldViewManager :
19
+ SimpleViewManager<PCTextFieldView>(),
20
+ PCTextFieldManagerInterface<PCTextFieldView> {
21
+
22
+ companion object {
23
+ private const val TAG = "PCTextField"
24
+ }
25
+
26
+ private val delegate: ViewManagerDelegate<PCTextFieldView> = PCTextFieldManagerDelegate(this)
27
+
28
+ override fun getName(): String = "PCTextField"
29
+
30
+ override fun getDelegate(): ViewManagerDelegate<PCTextFieldView> = delegate
31
+
32
+ override fun createViewInstance(reactContext: ThemedReactContext): PCTextFieldView {
33
+ return PCTextFieldView(reactContext)
34
+ }
35
+
36
+ /**
37
+ * Pass the StateWrapper to the view so it can update Fabric state with its
38
+ * natural height, and report it right away so the first layout already fits.
39
+ */
40
+ override fun updateState(
41
+ view: PCTextFieldView,
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: PCTextFieldView) {
51
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
52
+
53
+ view.onChange = { text, eventCount ->
54
+ dispatcher?.dispatchEvent(ChangeEvent(view.id, text, eventCount))
55
+ }
56
+ view.onFocusChange = { focused, text ->
57
+ dispatcher?.dispatchEvent(TextEvent(view.id, if (focused) "topFieldFocus" else "topFieldBlur", text))
58
+ }
59
+ view.onSubmit = { text ->
60
+ dispatcher?.dispatchEvent(TextEvent(view.id, "topFieldSubmit", text))
61
+ }
62
+ view.onTrailingIconPress = {
63
+ dispatcher?.dispatchEvent(TrailingIconPressEvent(view.id))
64
+ }
65
+ }
66
+
67
+ // --- Props ---
68
+
69
+ override fun setInitialText(view: PCTextFieldView, value: String?) {
70
+ view.applyInitialText(value ?: "")
71
+ }
72
+
73
+ override fun setLabel(view: PCTextFieldView, value: String?) {
74
+ view.applyLabel(value ?: "")
75
+ }
76
+
77
+ override fun setPlaceholder(view: PCTextFieldView, value: String?) {
78
+ view.applyPlaceholder(value ?: "")
79
+ }
80
+
81
+ override fun setSupportingText(view: PCTextFieldView, value: String?) {
82
+ view.applySupportingText(value ?: "")
83
+ }
84
+
85
+ override fun setErrorState(view: PCTextFieldView, value: String?) {
86
+ view.applyError(value ?: "none", view.errorText)
87
+ }
88
+
89
+ override fun setErrorText(view: PCTextFieldView, value: String?) {
90
+ view.applyError(view.errorState, value ?: "")
91
+ }
92
+
93
+ override fun setPrefix(view: PCTextFieldView, value: String?) {
94
+ view.applyPrefix(value ?: "")
95
+ }
96
+
97
+ override fun setSuffix(view: PCTextFieldView, value: String?) {
98
+ view.applySuffix(value ?: "")
99
+ }
100
+
101
+ // icons: {iconType, iconName, iconUri, iconScale, iconTinted}
102
+ override fun setLeadingIcon(view: PCTextFieldView, value: ReadableMap?) {
103
+ view.applyLeadingIcon(PCButtonSupport.parseIcon(value))
104
+ }
105
+
106
+ override fun setTrailingIcon(view: PCTextFieldView, value: ReadableMap?) {
107
+ view.applyTrailingIcon(PCButtonSupport.parseIcon(value))
108
+ }
109
+
110
+ override fun setClearButtonMode(view: PCTextFieldView, value: String?) {
111
+ view.applyClearButtonMode(value ?: "never")
112
+ }
113
+
114
+ override fun setPasswordToggle(view: PCTextFieldView, value: String?) {
115
+ view.applyPasswordToggle(value == "shown")
116
+ }
117
+
118
+ override fun setCharacterCount(view: PCTextFieldView, value: String?) {
119
+ view.applyCharacterCount(value == "shown")
120
+ }
121
+
122
+ override fun setMaxLength(view: PCTextFieldView, value: Int) {
123
+ view.applyMaxLength(value)
124
+ }
125
+
126
+ override fun setKeyboardType(view: PCTextFieldView, value: String?) {
127
+ view.applyKeyboardType(value ?: "default")
128
+ }
129
+
130
+ override fun setReturnKeyType(view: PCTextFieldView, value: String?) {
131
+ view.applyReturnKeyType(value ?: "default")
132
+ }
133
+
134
+ override fun setAutoCapitalize(view: PCTextFieldView, value: String?) {
135
+ view.applyAutoCapitalize(value ?: "sentences")
136
+ }
137
+
138
+ override fun setAutoCorrect(view: PCTextFieldView, value: String?) {
139
+ view.applyAutoCorrect(value != "disabled")
140
+ }
141
+
142
+ override fun setSecureTextEntry(view: PCTextFieldView, value: String?) {
143
+ view.applySecure(value == "secure")
144
+ }
145
+
146
+ override fun setLines(view: PCTextFieldView, value: String?) {
147
+ view.applyMultiline(value == "multiline")
148
+ }
149
+
150
+ override fun setInteractivity(view: PCTextFieldView, value: String?) {
151
+ view.applyInteractivity(value)
152
+ }
153
+
154
+ override fun setAutoFocus(view: PCTextFieldView, value: String?) {
155
+ view.applyAutoFocus(value == "focus")
156
+ }
157
+
158
+ override fun setSelectTextOnFocus(view: PCTextFieldView, value: String?) {
159
+ view.applySelectTextOnFocus(value == "select")
160
+ }
161
+
162
+ override fun setAutoComplete(view: PCTextFieldView, value: String?) {
163
+ view.applyAutoComplete(value ?: "")
164
+ }
165
+
166
+ override fun setKeyboardAppearance(view: PCTextFieldView, value: String?) {
167
+ // iOS only
168
+ }
169
+
170
+ // textStyle: {fontFamily, fontSize, fontWeight, fontStyle}; empty / 0 = default
171
+ override fun setTextStyle(view: PCTextFieldView, value: ReadableMap?) {
172
+ view.applyTextStyle(
173
+ family = value?.stringOr("fontFamily", "") ?: "",
174
+ size = value?.doubleOr("fontSize", 0.0)?.toFloat() ?: 0f,
175
+ weight = value?.stringOr("fontWeight", "") ?: "",
176
+ style = value?.stringOr("fontStyle", "") ?: ""
177
+ )
178
+ }
179
+
180
+ override fun setSpokenLabel(view: PCTextFieldView, value: String?) {
181
+ view.applySpokenLabel(value ?: "")
182
+ }
183
+
184
+ override fun setIos(view: PCTextFieldView, value: ReadableMap?) {
185
+ // Android ignores iOS config
186
+ }
187
+
188
+ // android: {material, variant, density}
189
+ override fun setAndroid(view: PCTextFieldView, value: ReadableMap?) {
190
+ view.applyMaterial(value?.stringOr("material", "m3"))
191
+ view.applyVariant(value?.stringOr("variant", "outlined"))
192
+ view.applyDensity(value?.stringOr("density", "standard"))
193
+ }
194
+
195
+ // --- Commands ---
196
+
197
+ override fun focus(view: PCTextFieldView) {
198
+ view.focusFromJS()
199
+ }
200
+
201
+ override fun blur(view: PCTextFieldView) {
202
+ view.blurFromJS()
203
+ }
204
+
205
+ override fun clear(view: PCTextFieldView) {
206
+ view.clearFromJS()
207
+ }
208
+
209
+ override fun setText(view: PCTextFieldView, eventCount: Int, text: String?) {
210
+ view.setTextFromJS(eventCount, text ?: "")
211
+ }
212
+
213
+ // --- Events ---
214
+
215
+ private class ChangeEvent(
216
+ surfaceId: Int,
217
+ private val text: String,
218
+ private val eventCount: Int
219
+ ) : Event<ChangeEvent>(surfaceId) {
220
+ override fun getEventName(): String = "topFieldChange"
221
+ override fun dispatch(rctEventEmitter: RCTEventEmitter) {
222
+ val payload = Arguments.createMap().apply {
223
+ putString("text", text)
224
+ putInt("eventCount", eventCount)
225
+ }
226
+ rctEventEmitter.receiveEvent(viewTag, eventName, payload)
227
+ }
228
+ }
229
+
230
+ private class TextEvent(
231
+ surfaceId: Int,
232
+ private val name: String,
233
+ private val text: String
234
+ ) : Event<TextEvent>(surfaceId) {
235
+ override fun getEventName(): String = name
236
+ override fun dispatch(rctEventEmitter: RCTEventEmitter) {
237
+ val payload = Arguments.createMap().apply { putString("text", text) }
238
+ rctEventEmitter.receiveEvent(viewTag, eventName, payload)
239
+ }
240
+ }
241
+
242
+ private class TrailingIconPressEvent(surfaceId: Int) : Event<TrailingIconPressEvent>(surfaceId) {
243
+ override fun getEventName(): String = "topTrailingIconPress"
244
+ override fun dispatch(rctEventEmitter: RCTEventEmitter) {
245
+ rctEventEmitter.receiveEvent(viewTag, eventName, Arguments.createMap())
246
+ }
247
+ }
248
+ }
@@ -16,7 +16,11 @@ class PlatformComponentsViewPackage : BaseReactPackage() {
16
16
  PCDatePickerViewManager(),
17
17
  PCContextMenuViewManager(),
18
18
  PCSegmentedControlViewManager(),
19
+ PCButtonViewManager(),
20
+ PCButtonGroupViewManager(),
21
+ PCFloatingToolbarViewManager(),
19
22
  PCLiquidGlassViewManager(),
23
+ PCTextFieldViewManager(),
20
24
  )
21
25
  }
22
26
 
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <resources>
3
+ <!--
4
+ The Material 3 Expressive size overlay for buttons built by this library
5
+ (see PCExpressive). The Expressive button styles carry a fixed Small
6
+ materialSizeOverlay; the library's copies point it at these attributes so
7
+ the size can be chosen per button through a theme overlay (PCSize.*), while
8
+ Material's own buttons built from the same context (a button group's
9
+ overflow button) still get a size.
10
+ -->
11
+ <attr name="pcButtonSizeOverlay" format="reference" />
12
+ <attr name="pcIconButtonSizeOverlay" format="reference" />
13
+ </resources>
@@ -168,4 +168,187 @@
168
168
  <item name="android:colorAccent">?attr/colorPrimary</item>
169
169
  <item name="android:colorControlActivated">?attr/colorPrimary</item>
170
170
  </style>
171
+
172
+ <!--
173
+ Material 3 Expressive, for Button and ButtonGroup. Theme.Material3Expressive
174
+ only swaps widget styles and motion springs, so applying those as an overlay
175
+ on the host theme keeps the app's colors. The button styles take their
176
+ materialSizeOverlay from the pcButtonSizeOverlay / pcIconButtonSizeOverlay
177
+ theme attributes (attrs.xml), so a PCSize.* overlay around the context
178
+ decides the size and shape.
179
+ -->
180
+ <style name="PCExpressiveOverlay" parent="">
181
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small</item>
182
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Small</item>
183
+ <item name="materialButtonStyle">@style/PCButton.Filled</item>
184
+ <item name="materialButtonTonalStyle">@style/PCButton.Tonal</item>
185
+ <item name="materialButtonOutlinedStyle">@style/PCButton.Outlined</item>
186
+ <item name="materialButtonElevatedStyle">@style/PCButton.Elevated</item>
187
+ <item name="borderlessButtonStyle">@style/PCButton.Text</item>
188
+ <item name="materialIconButtonStyle">@style/PCButton.IconStandard</item>
189
+ <item name="materialIconButtonFilledStyle">@style/PCButton.IconFilled</item>
190
+ <item name="materialIconButtonFilledTonalStyle">@style/PCButton.IconTonal</item>
191
+ <item name="materialIconButtonOutlinedStyle">@style/PCButton.IconOutlined</item>
192
+ <item name="materialButtonGroupStyle">@style/Widget.Material3Expressive.MaterialButtonGroup</item>
193
+ <item name="materialButtonToggleGroupStyle">@style/Widget.Material3Expressive.MaterialButtonToggleGroup</item>
194
+ <item name="motionSpringFastSpatial">@style/Motion.Material3.Spring.Expressive.Fast.Spatial</item>
195
+ <item name="motionSpringFastEffects">@style/Motion.Material3.Spring.Expressive.Fast.Effects</item>
196
+ <item name="motionSpringDefaultSpatial">@style/Motion.Material3.Spring.Expressive.Default.Spatial</item>
197
+ <item name="motionSpringDefaultEffects">@style/Motion.Material3.Spring.Expressive.Default.Effects</item>
198
+ <item name="motionSpringSlowSpatial">@style/Motion.Material3.Spring.Expressive.Slow.Spatial</item>
199
+ <item name="motionSpringSlowEffects">@style/Motion.Material3.Spring.Expressive.Slow.Effects</item>
200
+ </style>
201
+
202
+ <!-- Connected group of plain actions (the standard group is the default). -->
203
+ <style name="PCExpressiveOverlay.ConnectedGroup">
204
+ <item name="materialButtonGroupStyle">@style/Widget.Material3Expressive.MaterialButtonGroup.Connected</item>
205
+ </style>
206
+
207
+ <!-- Toggle group with the standard (unconnected) spacing and shapes. -->
208
+ <style name="PCExpressiveOverlay.StandardToggleGroup">
209
+ <item name="materialButtonToggleGroupStyle">@style/Widget.Material3Expressive.MaterialButtonGroup</item>
210
+ </style>
211
+
212
+ <!--
213
+ Classic Material 3 (android.material: 'm3'): the theme's own button styles,
214
+ plus the group variants Material only names as styles.
215
+ -->
216
+ <style name="PCM3Overlay.ConnectedGroup" parent="">
217
+ <item name="materialButtonGroupStyle">@style/Widget.Material3.MaterialButtonGroup.Connected</item>
218
+ </style>
219
+ <style name="PCM3Overlay.StandardToggleGroup" parent="">
220
+ <item name="materialButtonToggleGroupStyle">@style/Widget.Material3.MaterialButtonGroup</item>
221
+ </style>
222
+
223
+ <style name="PCButton.Filled" parent="Widget.Material3Expressive.Button">
224
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
225
+ </style>
226
+ <style name="PCButton.Tonal" parent="Widget.Material3Expressive.Button.TonalButton">
227
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
228
+ </style>
229
+ <style name="PCButton.Outlined" parent="Widget.Material3Expressive.Button.OutlinedButton">
230
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
231
+ </style>
232
+ <style name="PCButton.Text" parent="Widget.Material3Expressive.Button.TextButton">
233
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
234
+ </style>
235
+ <style name="PCButton.Elevated" parent="Widget.Material3Expressive.Button.ElevatedButton">
236
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
237
+ </style>
238
+ <style name="PCButton.IconStandard" parent="Widget.Material3Expressive.Button.IconButton.Standard">
239
+ <item name="materialSizeOverlay">?attr/pcIconButtonSizeOverlay</item>
240
+ </style>
241
+ <style name="PCButton.IconFilled" parent="Widget.Material3Expressive.Button.IconButton.Filled">
242
+ <item name="materialSizeOverlay">?attr/pcIconButtonSizeOverlay</item>
243
+ </style>
244
+ <style name="PCButton.IconTonal" parent="Widget.Material3Expressive.Button.IconButton.Tonal">
245
+ <item name="materialSizeOverlay">?attr/pcIconButtonSizeOverlay</item>
246
+ </style>
247
+ <style name="PCButton.IconOutlined" parent="Widget.Material3Expressive.Button.IconButton.Outlined">
248
+ <item name="materialSizeOverlay">?attr/pcIconButtonSizeOverlay</item>
249
+ </style>
250
+
251
+
252
+ <!-- Size (and shape) of the buttons built from a context; see PCExpressive.sizeOverlay. -->
253
+ <style name="PCSize.Xsmall" parent="">
254
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Xsmall</item>
255
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Xsmall</item>
256
+ </style>
257
+ <style name="PCSize.Xsmall.Square">
258
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Xsmall.Square</item>
259
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Xsmall.Square</item>
260
+ </style>
261
+ <style name="PCSize.Small" parent="">
262
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small</item>
263
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Small</item>
264
+ </style>
265
+ <style name="PCSize.Small.Square">
266
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small.Square</item>
267
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Small.Square</item>
268
+ </style>
269
+ <style name="PCSize.Medium" parent="">
270
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium</item>
271
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Medium</item>
272
+ </style>
273
+ <style name="PCSize.Medium.Square">
274
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium.Square</item>
275
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Medium.Square</item>
276
+ </style>
277
+ <style name="PCSize.Large" parent="">
278
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Large</item>
279
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Large</item>
280
+ </style>
281
+ <style name="PCSize.Large.Square">
282
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Large.Square</item>
283
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Large.Square</item>
284
+ </style>
285
+ <style name="PCSize.Xlarge" parent="">
286
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Xlarge</item>
287
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Xlarge</item>
288
+ </style>
289
+ <style name="PCSize.Xlarge.Square">
290
+ <item name="pcButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Xlarge.Square</item>
291
+ <item name="pcIconButtonSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Xlarge.Square</item>
292
+ </style>
293
+
294
+ <!--
295
+ FloatingToolbar: the Material container without its window-inset margins,
296
+ which React Native lays out itself.
297
+ -->
298
+ <style name="PCFloatingToolbar" parent="Widget.Material3.FloatingToolbar">
299
+ <item name="marginLeftSystemWindowInsets">false</item>
300
+ <item name="marginTopSystemWindowInsets">false</item>
301
+ <item name="marginRightSystemWindowInsets">false</item>
302
+ <item name="marginBottomSystemWindowInsets">false</item>
303
+ </style>
304
+
305
+ <!--
306
+ Buttons inside a FloatingToolbar take the toolbar's button styles, as XML
307
+ children of a FloatingToolbarLayout would (ThemeOverlay.Material3.FloatingToolbar).
308
+ -->
309
+ <style name="PCToolbarOverlay" parent="">
310
+ <item name="materialButtonStyle">@style/PCToolbarButton</item>
311
+ <item name="borderlessButtonStyle">@style/PCToolbarButton.Text</item>
312
+ <item name="materialIconButtonStyle">@style/PCToolbarButton.Icon</item>
313
+ </style>
314
+ <style name="PCToolbarOverlay.Vibrant">
315
+ <item name="materialButtonStyle">@style/PCToolbarButton.Vibrant</item>
316
+ <item name="borderlessButtonStyle">@style/PCToolbarButton.Text.Vibrant</item>
317
+ <item name="materialIconButtonStyle">@style/PCToolbarButton.Icon.Vibrant</item>
318
+ </style>
319
+ <style name="PCToolbarButton" parent="Widget.Material3.FloatingToolbar.Button">
320
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
321
+ </style>
322
+ <style name="PCToolbarButton.Vibrant" parent="Widget.Material3.FloatingToolbar.Button.Vibrant">
323
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
324
+ </style>
325
+ <style name="PCToolbarButton.Text" parent="Widget.Material3.FloatingToolbar.TextButton">
326
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
327
+ </style>
328
+ <style name="PCToolbarButton.Text.Vibrant" parent="Widget.Material3.FloatingToolbar.TextButton.Vibrant">
329
+ <item name="materialSizeOverlay">?attr/pcButtonSizeOverlay</item>
330
+ </style>
331
+ <style name="PCToolbarButton.Icon" parent="Widget.Material3.FloatingToolbar.IconButton">
332
+ <item name="materialSizeOverlay">?attr/pcIconButtonSizeOverlay</item>
333
+ </style>
334
+ <style name="PCToolbarButton.Icon.Vibrant" parent="Widget.Material3.FloatingToolbar.IconButton.Vibrant">
335
+ <item name="materialSizeOverlay">?attr/pcIconButtonSizeOverlay</item>
336
+ </style>
337
+ <!--
338
+ TextField: theme overlays that select the Material 3 text field style. A
339
+ TextInputLayout takes its style from the textInputStyle theme attribute, so
340
+ the variant is chosen by wrapping the context (see PCTextFieldView).
341
+ -->
342
+ <style name="PCTextField.Outlined" parent="">
343
+ <item name="textInputStyle">@style/Widget.Material3.TextInputLayout.OutlinedBox</item>
344
+ </style>
345
+ <style name="PCTextField.Outlined.Dense">
346
+ <item name="textInputStyle">@style/Widget.Material3.TextInputLayout.OutlinedBox.Dense</item>
347
+ </style>
348
+ <style name="PCTextField.Filled" parent="">
349
+ <item name="textInputStyle">@style/Widget.Material3.TextInputLayout.FilledBox</item>
350
+ </style>
351
+ <style name="PCTextField.Filled.Dense">
352
+ <item name="textInputStyle">@style/Widget.Material3.TextInputLayout.FilledBox.Dense</item>
353
+ </style>
171
354
  </resources>
package/ios/PCButton.h ADDED
@@ -0,0 +1,10 @@
1
+ // PCButton.h
2
+
3
+ #import <React/RCTViewComponentView.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface PCButton : RCTViewComponentView
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,196 @@
1
+ // PCButton.mm
2
+
3
+ #import "PCButton.h"
4
+
5
+ #import <React/RCTComponentViewFactory.h>
6
+ #import <React/RCTConversions.h>
7
+ #import <React/RCTFabricComponentsPlugins.h>
8
+ #import <React/RCTFont.h>
9
+
10
+ #import <react/renderer/components/PlatformComponentsViewSpec/ComponentDescriptors.h>
11
+ #import <react/renderer/components/PlatformComponentsViewSpec/EventEmitters.h>
12
+ #import <react/renderer/components/PlatformComponentsViewSpec/Props.h>
13
+ #import <react/renderer/core/LayoutPrimitives.h>
14
+
15
+ #if __has_include(<PlatformComponents/PlatformComponents-Swift.h>)
16
+ #import <PlatformComponents/PlatformComponents-Swift.h>
17
+ #else
18
+ #import "PlatformComponents-Swift.h"
19
+ #endif
20
+
21
+ #import "PCButtonComponentDescriptors-custom.h"
22
+ #import "PCButtonShadowNode-custom.h"
23
+ #import "PCButtonState-custom.h"
24
+
25
+ using namespace facebook::react;
26
+
27
+ namespace {
28
+ static inline NSString *NSStringFromStd(const std::string &s, NSString *fallback) {
29
+ return s.empty() ? fallback : [NSString stringWithUTF8String:s.c_str()];
30
+ }
31
+
32
+ static inline bool IconEqual(const PCButtonIconStruct &a, const PCButtonIconStruct &b) {
33
+ return a.iconType == b.iconType && a.iconName == b.iconName && a.iconUri == b.iconUri &&
34
+ a.iconScale == b.iconScale && a.iconTinted == b.iconTinted;
35
+ }
36
+
37
+ static inline bool LabelStyleEqual(
38
+ const PCButtonLabelStyleStruct &a,
39
+ const PCButtonLabelStyleStruct &b) {
40
+ return a.fontFamily == b.fontFamily && a.fontSize == b.fontSize &&
41
+ a.fontWeight == b.fontWeight && a.fontStyle == b.fontStyle;
42
+ }
43
+
44
+ /// Builds the label font from RN-style font props, or nil when every field is
45
+ /// unset so the button keeps the configuration's font.
46
+ static UIFont *FontFromLabelStyle(const PCButtonLabelStyleStruct &style) {
47
+ if (style.fontFamily.empty() && style.fontSize <= 0 &&
48
+ style.fontWeight.empty() && style.fontStyle.empty()) {
49
+ return nil;
50
+ }
51
+ // UIButton titles default to the body text style; start there so a lone
52
+ // fontWeight or fontStyle doesn't change the size.
53
+ return [RCTFont updateFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]
54
+ withFamily:NSStringFromStd(style.fontFamily, nil)
55
+ size:style.fontSize > 0 ? @(style.fontSize) : nil
56
+ weight:NSStringFromStd(style.fontWeight, nil)
57
+ style:NSStringFromStd(style.fontStyle, nil)
58
+ variant:nil
59
+ scaleMultiplier:1.0];
60
+ }
61
+ } // namespace
62
+
63
+ @interface PCButton ()
64
+
65
+ - (void)updateMeasurements;
66
+
67
+ @end
68
+
69
+ @implementation PCButton {
70
+ PCButtonView *_view;
71
+ MeasuringPCButtonShadowNode::ConcreteState::Shared _state;
72
+ }
73
+
74
+ + (ComponentDescriptorProvider)componentDescriptorProvider {
75
+ return concreteComponentDescriptorProvider<MeasuringPCButtonComponentDescriptor>();
76
+ }
77
+
78
+ - (instancetype)initWithFrame:(CGRect)frame {
79
+ if (self = [super initWithFrame:frame]) {
80
+ _view = [PCButtonView new];
81
+ self.contentView = _view;
82
+
83
+ __weak __typeof(self) weakSelf = self;
84
+
85
+ _view.onPress = ^{
86
+ __typeof(self) strongSelf = weakSelf;
87
+ if (!strongSelf) return;
88
+
89
+ auto eventEmitter =
90
+ std::static_pointer_cast<const PCButtonEventEmitter>(strongSelf->_eventEmitter);
91
+ if (!eventEmitter) return;
92
+
93
+ eventEmitter->onButtonPress({});
94
+ };
95
+
96
+ _view.onNeedsRemeasure = ^{
97
+ __typeof(self) strongSelf = weakSelf;
98
+ if (!strongSelf) return;
99
+ [strongSelf updateMeasurements];
100
+ };
101
+ }
102
+ return self;
103
+ }
104
+
105
+ - (void)updateProps:(Props::Shared const &)props
106
+ oldProps:(Props::Shared const &)oldProps {
107
+ const auto &newProps = *std::static_pointer_cast<const PCButtonProps>(props);
108
+ const auto prevProps = std::static_pointer_cast<const PCButtonProps>(oldProps);
109
+
110
+ if (!prevProps || newProps.label != prevProps->label) {
111
+ _view.label = NSStringFromStd(newProps.label, @"");
112
+ }
113
+
114
+ // icon: {iconType, iconName, iconUri, iconScale, iconTinted}
115
+ if (!prevProps || !IconEqual(newProps.icon, prevProps->icon)) {
116
+ const auto &icon = newProps.icon;
117
+ [_view setIconWithType:NSStringFromStd(icon.iconType, @"")
118
+ name:NSStringFromStd(icon.iconName, @"")
119
+ uri:NSStringFromStd(icon.iconUri, @"")
120
+ scale:icon.iconScale
121
+ tinted:(icon.iconTinted != "false")];
122
+ }
123
+
124
+ if (!prevProps || newProps.variant != prevProps->variant) {
125
+ _view.variant = NSStringFromStd(newProps.variant, @"filled");
126
+ }
127
+
128
+ if (!prevProps || newProps.size != prevProps->size) {
129
+ _view.size = NSStringFromStd(newProps.size, @"small");
130
+ }
131
+
132
+ if (!prevProps || newProps.shape != prevProps->shape) {
133
+ _view.shape = NSStringFromStd(newProps.shape, @"");
134
+ }
135
+
136
+ if (!prevProps || newProps.interactivity != prevProps->interactivity) {
137
+ _view.interactivity = NSStringFromStd(newProps.interactivity, @"enabled");
138
+ }
139
+
140
+ // Colors arrive as SharedColor (already processed by React Native)
141
+ if (!prevProps || newProps.color != prevProps->color) {
142
+ _view.containerColor = RCTUIColorFromSharedColor(newProps.color);
143
+ }
144
+
145
+ if (!prevProps || newProps.foregroundColor != prevProps->foregroundColor) {
146
+ _view.foregroundColor = RCTUIColorFromSharedColor(newProps.foregroundColor);
147
+ }
148
+
149
+ // labelStyle: {fontFamily, fontSize, fontWeight, fontStyle}
150
+ if (!prevProps || !LabelStyleEqual(newProps.labelStyle, prevProps->labelStyle)) {
151
+ _view.labelFont = FontFromLabelStyle(newProps.labelStyle);
152
+ }
153
+
154
+ if (!prevProps || newProps.spokenLabel != prevProps->spokenLabel) {
155
+ _view.spokenLabel = NSStringFromStd(newProps.spokenLabel, @"");
156
+ }
157
+
158
+ // androidRippleColor / androidStrokeColor: Android only
159
+
160
+ [super updateProps:props oldProps:oldProps];
161
+
162
+ // Update measurements when props change that affect layout
163
+ [self updateMeasurements];
164
+ }
165
+
166
+ #pragma mark - State (Measuring)
167
+
168
+ - (void)updateState:(const State::Shared &)state
169
+ oldState:(const State::Shared &)oldState {
170
+ _state = std::static_pointer_cast<const MeasuringPCButtonShadowNode::ConcreteState>(state);
171
+
172
+ if (oldState == nullptr) {
173
+ // First time: compute initial size.
174
+ [self updateMeasurements];
175
+ }
176
+
177
+ [super updateState:state oldState:oldState];
178
+ }
179
+
180
+ - (void)updateMeasurements {
181
+ if (_state == nullptr)
182
+ return;
183
+
184
+ // The button's natural size; Yoga clamps it to the available width
185
+ CGSize size = [_view sizeForLayoutWithConstrainedTo:CGSizeZero];
186
+
187
+ PCButtonStateFrameSize next;
188
+ next.frameSize = {(Float)size.width, (Float)size.height};
189
+ _state->updateState(std::move(next));
190
+ }
191
+
192
+ @end
193
+
194
+ Class<RCTComponentViewProtocol> PCButtonCls(void) {
195
+ return PCButton.class;
196
+ }
@@ -0,0 +1,10 @@
1
+ // PCButtonGroup.h
2
+
3
+ #import <React/RCTViewComponentView.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ @interface PCButtonGroup : RCTViewComponentView
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END