react-native-advanced-text 0.1.9 → 0.1.11

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.
@@ -1,4 +1,3 @@
1
- // File: AdvancedTextView.kt
2
1
  package com.advancedtext
3
2
 
4
3
  import android.content.Context
@@ -30,13 +29,14 @@ class AdvancedTextView : TextView {
30
29
  private var menuOptions: List<String> = emptyList()
31
30
  private var indicatorWordIndex: Int = -1
32
31
  private var lastSelectedText: String = ""
32
+ private var isSelectionEnabled: Boolean = true
33
33
  private var customActionMode: ActionMode? = null
34
34
 
35
35
  constructor(context: Context?) : super(context) { init() }
36
36
  constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { init() }
37
37
  constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { init() }
38
38
 
39
- private fun init() {
39
+ private fun init() {
40
40
  Log.d(TAG, "AdvancedTextView initialized")
41
41
 
42
42
  // Set default text appearance - DON'T set black color here
@@ -46,7 +46,6 @@ class AdvancedTextView : TextView {
46
46
  movementMethod = LinkMovementMethod.getInstance()
47
47
  setTextIsSelectable(true)
48
48
 
49
- // Use custom action mode for selection menu
50
49
  customSelectionActionModeCallback = object : ActionMode.Callback {
51
50
  override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
52
51
  Log.d(TAG, "onCreateActionMode triggered")
@@ -96,8 +95,14 @@ class AdvancedTextView : TextView {
96
95
 
97
96
  fun setAdvancedText(text: String) {
98
97
  Log.d(TAG, "setAdvancedText: $text (length=${text.length})")
99
- this.text = text
98
+
99
+ // Set the text first
100
+ super.setText(text, BufferType.SPANNABLE)
101
+
102
+ // Then apply highlights
100
103
  updateTextWithHighlights()
104
+
105
+ // Force layout update
101
106
  requestLayout()
102
107
  invalidate()
103
108
  }
@@ -132,59 +137,78 @@ class AdvancedTextView : TextView {
132
137
  }
133
138
 
134
139
  val spannableString = SpannableString(textValue)
135
- val words = textValue.split("\\s+".toRegex())
140
+
141
+ // Split words while preserving spaces for accurate indexing
142
+ val words = textValue.split("\\s+".toRegex()).filter { it.isNotEmpty() }
136
143
 
137
144
  var currentIndex = 0
138
145
  words.forEachIndexed { wordIndex, word ->
139
146
 
140
- if (word.isNotEmpty()) {
141
- val wordStart = textValue.indexOf(word, currentIndex)
142
- if (wordStart >= 0) {
143
- val wordEnd = wordStart + word.length
144
-
145
- highlightedWords.find { it.index == wordIndex }?.let { highlightedWord ->
146
- val color = try {
147
- Color.parseColor(highlightedWord.highlightColor)
148
- } catch (e: IllegalArgumentException) {
149
- Log.e(TAG, "Invalid color: ${highlightedWord.highlightColor}, using yellow")
150
- Color.YELLOW
151
- }
152
- Log.d(TAG, "Applying highlight to word '$word' at index $wordIndex with color ${highlightedWord.highlightColor}")
153
-
154
- spannableString.setSpan(
155
- BackgroundColorSpan(color),
156
- wordStart,
157
- wordEnd,
158
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
159
- )
147
+ // Find the actual position of the word in the text
148
+ val wordStart = textValue.indexOf(word, currentIndex)
149
+ if (wordStart >= 0) {
150
+ val wordEnd = wordStart + word.length
151
+
152
+ Log.d(TAG, "Processing word '$word' at position $wordStart-$wordEnd, index $wordIndex")
153
+
154
+ // Apply clickable span FIRST (this is important)
155
+ spannableString.setSpan(
156
+ WordClickableSpan(wordIndex, word),
157
+ wordStart,
158
+ wordEnd,
159
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
160
+ )
161
+
162
+ // Then apply background color for highlighted words
163
+ highlightedWords.find { it.index == wordIndex }?.let { highlightedWord ->
164
+ val color = try {
165
+ Color.parseColor(highlightedWord.highlightColor)
166
+ } catch (e: IllegalArgumentException) {
167
+ Log.e(TAG, "Invalid color: ${highlightedWord.highlightColor}, using yellow")
168
+ Color.YELLOW
160
169
  }
170
+ Log.d(TAG, "Applying highlight to word '$word' at index $wordIndex with color ${highlightedWord.highlightColor}")
161
171
 
162
- if (wordIndex == indicatorWordIndex) {
163
- Log.d(TAG, "Applying indicator span to word '$word' at index $wordIndex")
164
- // Apply red color to the indicator word
165
- spannableString.setSpan(
166
- ForegroundColorSpan(Color.RED),
167
- wordStart,
168
- wordEnd,
169
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
170
- )
171
- }
172
-
173
- // Make words clickable
174
172
  spannableString.setSpan(
175
- WordClickableSpan(wordIndex, word),
173
+ BackgroundColorSpan(color),
176
174
  wordStart,
177
175
  wordEnd,
178
176
  Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
179
177
  )
178
+ }
179
+
180
+ // Then apply indicator span
181
+ if (wordIndex == indicatorWordIndex) {
182
+ Log.d(TAG, "Applying indicator span to word '$word' at index $wordIndex")
180
183
 
181
- currentIndex = wordEnd
184
+ spannableString.setSpan(
185
+ IndicatorSpan(),
186
+ wordStart,
187
+ wordEnd,
188
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
189
+ )
182
190
  }
191
+
192
+ currentIndex = wordEnd
183
193
  }
184
194
  }
185
195
 
196
+ // Set the spannable text
186
197
  setText(spannableString, BufferType.SPANNABLE)
187
- Log.d(TAG, "Text updated with spans")
198
+
199
+ // Ensure movement method is still set
200
+ movementMethod = LinkMovementMethod.getInstance()
201
+
202
+ Log.d(TAG, "Text updated with spans, total spans")
203
+ }
204
+
205
+
206
+
207
+ private fun onMenuItemClick(item: MenuItem, selectedText: String): Boolean {
208
+ val menuItemText = menuOptions[item.itemId]
209
+ Log.d(TAG, "onMenuItemClick: menuOption='$menuItemText', selectedText='$selectedText'")
210
+ sendSelectionEvent(selectedText, menuItemText)
211
+ return true
188
212
  }
189
213
 
190
214
  private fun sendSelectionEvent(selectedText: String, eventType: String) {
@@ -205,23 +229,36 @@ class AdvancedTextView : TextView {
205
229
  }
206
230
 
207
231
  private inner class WordClickableSpan(
208
- private val wordIndex: Int,
209
- private val word: String
232
+ private val wordIndex: Int,
233
+ private val word: String
210
234
  ) : ClickableSpan() {
211
235
 
212
236
  override fun onClick(widget: View) {
213
- Log.d(TAG, "Word clicked: '$word' (index=$wordIndex)")
214
- // Clear any selection first to prevent interference
215
- val spannable = widget as? TextView
216
- spannable?.let {
217
- Selection.removeSelection(it.text as? android.text.Spannable)
237
+ Log.d(TAG, "WordClickableSpan onClick triggered: '$word' (index=$wordIndex)")
238
+
239
+ // Small delay to ensure the click is processed
240
+ widget.post {
241
+ sendWordPressEvent(word, wordIndex)
218
242
  }
219
- sendWordPressEvent(word, wordIndex)
220
243
  }
221
244
 
222
245
  override fun updateDrawState(ds: TextPaint) {
223
- super.updateDrawState(ds)
224
- // Don't change the color - let ForegroundColorSpan handle it
246
+ // Don't call super to avoid default link styling (blue color, underline)
247
+ // Keep the original text appearance
248
+ ds.color = currentTextColor
249
+ ds.isUnderlineText = false
250
+ ds.bgColor = Color.TRANSPARENT
251
+ }
252
+ }
253
+
254
+ private inner class IndicatorSpan : ClickableSpan() {
255
+ override fun onClick(widget: View) {
256
+ Log.d(TAG, "IndicatorSpan clicked (shouldn't trigger action)")
257
+ }
258
+
259
+ override fun updateDrawState(ds: TextPaint) {
260
+
261
+ ds.isFakeBoldText = true
225
262
  ds.isUnderlineText = false
226
263
  }
227
264
  }
@@ -1,7 +1,7 @@
1
1
  // File: AdvancedTextViewManager.kt
2
+ // This should be the ONLY content in this file
2
3
  package com.advancedtext
3
4
 
4
- import android.graphics.Color
5
5
  import android.view.ViewGroup
6
6
  import com.facebook.react.bridge.ReadableArray
7
7
  import com.facebook.react.module.annotations.ReactModule
@@ -31,10 +31,10 @@ class AdvancedTextViewManager : SimpleViewManager<AdvancedTextView>(),
31
31
 
32
32
  public override fun createViewInstance(context: ThemedReactContext): AdvancedTextView {
33
33
  val view = AdvancedTextView(context)
34
- // Set layout params for proper sizing
34
+ // Set default layout params to ensure the view is visible
35
35
  view.layoutParams = ViewGroup.LayoutParams(
36
36
  ViewGroup.LayoutParams.MATCH_PARENT,
37
- ViewGroup.LayoutParams.WRAP_CONTENT // Changed to WRAP_CONTENT for auto height
37
+ ViewGroup.LayoutParams.WRAP_CONTENT
38
38
  )
39
39
  return view
40
40
  }
@@ -81,15 +81,7 @@ class AdvancedTextViewManager : SimpleViewManager<AdvancedTextView>(),
81
81
  view?.setIndicatorWordIndex(index)
82
82
  }
83
83
 
84
- // Handle color prop from React Native style
85
- @ReactProp(name = "color", customType = "Color")
86
- fun setColor(view: AdvancedTextView?, color: Int?) {
87
- color?.let {
88
- view?.setTextColor(it)
89
- }
90
- }
91
-
92
- // Register custom events
84
+ // Add this method to register custom events
93
85
  override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
94
86
  return mapOf(
95
87
  "onWordPress" to mapOf("registrationName" to "onWordPress"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-advanced-text",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": " Advanced text component for React Native with custom select options.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",