@rematter/pylon-react-native 0.1.5 → 0.1.6

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.
@@ -18,96 +18,107 @@ import com.pylon.chatwidget.PylonUser
18
18
  * This is kept as minimal as possible to avoid interfering with touch pass-through.
19
19
  */
20
20
  class RNPylonChatView(context: Context) : FrameLayout(context) {
21
-
21
+
22
22
  private var pylonChatView: PylonChatView? = null
23
23
  private var config: PylonConfig? = null
24
24
  private var user: PylonUser? = null
25
-
25
+
26
26
  // Config properties
27
27
  var appId: String? = null
28
28
  set(value) {
29
29
  field = value
30
30
  updateConfig()
31
31
  }
32
-
32
+
33
33
  var widgetBaseUrl: String? = null
34
34
  set(value) {
35
35
  field = value
36
36
  updateConfig()
37
37
  }
38
-
38
+
39
39
  var widgetScriptUrl: String? = null
40
40
  set(value) {
41
41
  field = value
42
42
  updateConfig()
43
43
  }
44
-
44
+
45
45
  var enableLogging: Boolean = true
46
46
  set(value) {
47
47
  field = value
48
48
  updateConfig()
49
49
  }
50
-
50
+
51
51
  var debugMode: Boolean = false
52
52
  set(value) {
53
53
  field = value
54
54
  updateConfig()
55
55
  }
56
-
56
+
57
57
  var primaryColor: String? = null
58
58
  set(value) {
59
59
  field = value
60
60
  updateConfig()
61
61
  }
62
-
62
+
63
63
  // User properties
64
64
  var userEmail: String? = null
65
65
  set(value) {
66
66
  field = value
67
67
  updateUser()
68
68
  }
69
-
69
+
70
70
  var userName: String? = null
71
71
  set(value) {
72
72
  field = value
73
73
  updateUser()
74
74
  }
75
-
75
+
76
76
  var userAvatarUrl: String? = null
77
77
  set(value) {
78
78
  field = value
79
79
  updateUser()
80
80
  }
81
-
81
+
82
82
  var userEmailHash: String? = null
83
83
  set(value) {
84
84
  field = value
85
85
  updateUser()
86
86
  }
87
-
87
+
88
88
  var userAccountId: String? = null
89
89
  set(value) {
90
90
  field = value
91
91
  updateUser()
92
92
  }
93
-
93
+
94
94
  var userAccountExternalId: String? = null
95
95
  set(value) {
96
96
  field = value
97
97
  updateUser()
98
98
  }
99
99
 
100
+ // Safe area top inset for coordinate space adjustment
101
+ var topInset: Float = 0f
102
+ set(value) {
103
+ field = value
104
+ // Apply to pylonChatView if it exists
105
+ pylonChatView?.let {
106
+ // Note: Android PylonChat doesn't have topInset support yet,
107
+ // but we store it here for future use or coordinate adjustments
108
+ }
109
+ }
110
+
100
111
  init {
101
112
  layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
102
113
  }
103
-
114
+
104
115
  // Track pointer events setting
105
116
  private var pointerEventsMode = "auto"
106
-
117
+
107
118
  fun setPointerEventsMode(mode: String) {
108
119
  pointerEventsMode = mode
109
120
  }
110
-
121
+
111
122
  /**
112
123
  * This is the CRITICAL method for pointerEvents.
113
124
  * By returning false here when pointerEvents="none", we tell React Native's
@@ -139,7 +150,7 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
139
150
 
140
151
  private fun updateConfig() {
141
152
  val id = appId ?: return
142
-
153
+
143
154
  config = PylonConfig.build(id) {
144
155
  this.enableLogging = this@RNPylonChatView.enableLogging
145
156
  this.primaryColor = this@RNPylonChatView.primaryColor
@@ -147,14 +158,14 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
147
158
  this@RNPylonChatView.widgetBaseUrl?.let { this.widgetBaseUrl = it }
148
159
  this@RNPylonChatView.widgetScriptUrl?.let { this.widgetScriptUrl = it }
149
160
  }
150
-
161
+
151
162
  recreatePylonView()
152
163
  }
153
-
164
+
154
165
  private fun updateUser() {
155
166
  val email = userEmail ?: return
156
167
  val name = userName ?: return
157
-
168
+
158
169
  user = PylonUser(
159
170
  email = email,
160
171
  name = name,
@@ -163,48 +174,48 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
163
174
  accountId = userAccountId,
164
175
  accountExternalId = userAccountExternalId
165
176
  )
166
-
177
+
167
178
  recreatePylonView()
168
179
  }
169
-
180
+
170
181
  private fun recreatePylonView() {
171
182
  val cfg = config ?: return
172
183
  val usr = user ?: return
173
-
184
+
174
185
  // Remove old view
175
186
  pylonChatView?.let { removeView(it) }
176
-
187
+
177
188
  // Create new PylonChatView
178
189
  val newView = PylonChatView(context, cfg, usr)
179
190
  newView.setListener(object : PylonChatListener {
180
191
  override fun onPylonLoaded() {
181
192
  sendEvent("onPylonLoaded", Arguments.createMap())
182
193
  }
183
-
194
+
184
195
  override fun onPylonInitialized() {
185
196
  sendEvent("onPylonInitialized", Arguments.createMap())
186
197
  }
187
-
198
+
188
199
  override fun onPylonReady() {
189
200
  sendEvent("onPylonReady", Arguments.createMap())
190
201
  }
191
-
202
+
192
203
  override fun onMessageReceived(message: String) {
193
204
  val params = Arguments.createMap()
194
205
  params.putString("message", message)
195
206
  sendEvent("onMessageReceived", params)
196
207
  }
197
-
208
+
198
209
  override fun onChatOpened() {
199
210
  sendEvent("onChatOpened", Arguments.createMap())
200
211
  }
201
-
212
+
202
213
  override fun onChatClosed() {
203
214
  val params = Arguments.createMap()
204
215
  params.putBoolean("wasOpen", true)
205
216
  sendEvent("onChatClosed", params)
206
217
  }
207
-
218
+
208
219
  override fun onInteractiveBoundsChanged(selector: String, left: Float, top: Float, right: Float, bottom: Float) {
209
220
  // Convert pixels to density-independent pixels (dp) for React Native.
210
221
  val density = resources.displayMetrics.density
@@ -216,57 +227,57 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
216
227
  params.putDouble("bottom", (bottom / density).toDouble())
217
228
  sendEvent("onInteractiveBoundsChanged", params)
218
229
  }
219
-
230
+
220
231
  override fun onPylonError(error: String) {
221
232
  val params = Arguments.createMap()
222
233
  params.putString("error", error)
223
234
  sendEvent("onPylonError", params)
224
235
  }
225
-
236
+
226
237
  override fun onUnreadCountChanged(count: Int) {
227
238
  val params = Arguments.createMap()
228
239
  params.putInt("count", count)
229
240
  sendEvent("onUnreadCountChanged", params)
230
241
  }
231
-
242
+
232
243
  override fun onFileChooserLaunched(requestCode: Int) {
233
244
  // Handle file chooser if needed
234
245
  }
235
246
  })
236
-
247
+
237
248
  newView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
238
249
  addView(newView)
239
250
  pylonChatView = newView
240
251
  }
241
-
252
+
242
253
  private fun sendEvent(eventName: String, params: WritableMap) {
243
254
  val reactContext = context as ReactContext
244
255
  reactContext
245
256
  .getJSModule(RCTEventEmitter::class.java)
246
257
  .receiveEvent(id, eventName, params)
247
258
  }
248
-
259
+
249
260
  // Imperative methods
250
261
  fun openChat() {
251
262
  pylonChatView?.openChat()
252
263
  }
253
-
264
+
254
265
  fun closeChat() {
255
266
  pylonChatView?.closeChat()
256
267
  }
257
-
268
+
258
269
  fun showChatBubble() {
259
270
  pylonChatView?.showChatBubble()
260
271
  }
261
-
272
+
262
273
  fun hideChatBubble() {
263
274
  pylonChatView?.hideChatBubble()
264
275
  }
265
-
276
+
266
277
  fun showNewMessage(message: String, isHtml: Boolean) {
267
278
  pylonChatView?.showNewMessage(message, isHtml)
268
279
  }
269
-
280
+
270
281
  fun setNewIssueCustomFields(fields: Map<String, Any?>) {
271
282
  @Suppress("UNCHECKED_CAST")
272
283
  pylonChatView?.setNewIssueCustomFields(fields as Map<String, Any>)
@@ -276,19 +287,19 @@ class RNPylonChatView(context: Context) : FrameLayout(context) {
276
287
  @Suppress("UNCHECKED_CAST")
277
288
  pylonChatView?.setTicketFormFields(fields as Map<String, Any>)
278
289
  }
279
-
290
+
280
291
  fun updateEmailHash(emailHash: String?) {
281
292
  pylonChatView?.setEmailHash(emailHash)
282
293
  }
283
-
294
+
284
295
  fun showTicketForm(slug: String) {
285
296
  pylonChatView?.showTicketForm(slug)
286
297
  }
287
-
298
+
288
299
  fun showKnowledgeBaseArticle(articleId: String) {
289
300
  pylonChatView?.showKnowledgeBaseArticle(articleId)
290
301
  }
291
-
302
+
292
303
  fun clickElementAtSelector(selector: String) {
293
304
  // Trigger a click on the element with the given ID selector.
294
305
  // This is used for Android's proxy-based touch pass-through system.
@@ -15,7 +15,7 @@ import com.pylon.chatwidget.PylonConfig
15
15
  import com.pylon.chatwidget.PylonUser
16
16
 
17
17
  class RNPylonChatViewManager : SimpleViewManager<RNPylonChatView>() {
18
-
18
+
19
19
  companion object {
20
20
  const val REACT_CLASS = "RNPylonChatView"
21
21
  const val COMMAND_OPEN_CHAT = 1
@@ -67,7 +67,7 @@ class RNPylonChatViewManager : SimpleViewManager<RNPylonChatView>() {
67
67
  fun setPointerEvents(view: RNPylonChatView, pointerEvents: String?) {
68
68
  val mode = pointerEvents ?: "auto"
69
69
  view.setPointerEventsMode(mode)
70
-
70
+
71
71
  when (mode) {
72
72
  "none" -> {
73
73
  // Don't handle any touches - let them pass through
@@ -128,6 +128,12 @@ class RNPylonChatViewManager : SimpleViewManager<RNPylonChatView>() {
128
128
  view.userAccountExternalId = id
129
129
  }
130
130
 
131
+ // Coordinate space adjustment
132
+ @ReactProp(name = "topInset", defaultFloat = 0f)
133
+ fun setTopInset(view: RNPylonChatView, inset: Float) {
134
+ view.topInset = inset
135
+ }
136
+
131
137
  // Event names
132
138
  override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
133
139
  return MapBuilder.builder<String, Any>()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rematter/pylon-react-native",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Pylon Chat SDK for React Native",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",