Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ class EnrichedTextInputView :
var experimentalSynchronousEvents: Boolean = false
var useHtmlNormalizer: Boolean = false

// Triple: (trigger, style, type) where type is "block" or "inline"
var textShortcuts: List<Triple<String, String, String>> = emptyList()

var fontSize: Float? = null
private var lineHeight: Float? = null
var submitBehavior: String? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,23 @@ class EnrichedTextInputViewManager :
view?.useHtmlNormalizer = value
}

override fun setTextShortcuts(
view: EnrichedTextInputView?,
value: ReadableArray?,
) {
val shortcuts = mutableListOf<Triple<String, String, String>>()
if (value != null) {
for (i in 0 until value.size()) {
val map = value.getMap(i) ?: continue
val trigger = map.getString("trigger") ?: continue
val style = map.getString("style") ?: continue
val type = map.getString("type") ?: "block"
shortcuts.add(Triple(trigger, style, type))
}
}
view?.textShortcuts = shortcuts
}

override fun focus(view: EnrichedTextInputView?) {
view?.requestFocusProgrammatically()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ object EnrichedSpans {

val listSpans: Map<String, ListSpanConfig> =
mapOf(
UNORDERED_LIST to ListSpanConfig(EnrichedInputUnorderedListSpan::class.java, "- "),
ORDERED_LIST to ListSpanConfig(EnrichedInputOrderedListSpan::class.java, "1. "),
UNORDERED_LIST to ListSpanConfig(EnrichedInputUnorderedListSpan::class.java, null),
ORDERED_LIST to ListSpanConfig(EnrichedInputOrderedListSpan::class.java, null),
CHECKBOX_LIST to ListSpanConfig(EnrichedInputCheckboxListSpan::class.java, null),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,111 @@ class ListStyles(
}
}

private fun resolveInlineStyleName(name: String): String? = when (name) {
"bold" -> EnrichedSpans.BOLD
"italic" -> EnrichedSpans.ITALIC
"underline" -> EnrichedSpans.UNDERLINE
"strikethrough" -> EnrichedSpans.STRIKETHROUGH
"inline_code" -> EnrichedSpans.INLINE_CODE
else -> null
}

private fun resolveStyleName(name: String): String? = when (name) {
"h1" -> EnrichedSpans.H1
"h2" -> EnrichedSpans.H2
"h3" -> EnrichedSpans.H3
"h4" -> EnrichedSpans.H4
"h5" -> EnrichedSpans.H5
"h6" -> EnrichedSpans.H6
"blockquote" -> EnrichedSpans.BLOCK_QUOTE
"codeblock" -> EnrichedSpans.CODE_BLOCK
"unordered_list" -> EnrichedSpans.UNORDERED_LIST
"ordered_list" -> EnrichedSpans.ORDERED_LIST
"checkbox_list" -> EnrichedSpans.CHECKBOX_LIST
else -> null
}

private fun handleConfigurableShortcuts(
s: Editable,
endCursorPosition: Int,
previousTextLength: Int,
) {
val shortcuts = view.textShortcuts
if (shortcuts.isEmpty()) return
if (previousTextLength >= s.length) return

val cursorPosition = endCursorPosition.coerceAtMost(s.length)
val (start, end) = s.getParagraphBounds(cursorPosition)
val paragraphText = s.substring(start, end)

for ((trigger, styleName, type) in shortcuts) {
if (type == "inline") continue
if (trigger.isEmpty()) continue
if (!paragraphText.startsWith(trigger)) continue

val resolvedStyle = resolveStyleName(styleName) ?: continue

s.replace(start, start + trigger.length, EnrichedConstants.ZWS_STRING)

val listConfig = EnrichedSpans.listSpans[resolvedStyle]
if (listConfig != null) {
setSpan(s, resolvedStyle, start, start + 1)
view.selection?.validateStyles()
} else {
view.paragraphStyles?.toggleStyle(resolvedStyle)
}
return
}
}

private fun handleInlineShortcuts(
s: Editable,
endCursorPosition: Int,
previousTextLength: Int,
) {
val shortcuts = view.textShortcuts
if (shortcuts.isEmpty()) return
if (previousTextLength >= s.length) return

val cursorPosition = endCursorPosition.coerceAtMost(s.length)
val text = s.toString()
val (paraStart, _) = s.getParagraphBounds(cursorPosition)

for ((trigger, styleName, type) in shortcuts) {
if (type != "inline") continue
if (trigger.isEmpty()) continue

val resolvedStyle = resolveInlineStyleName(styleName) ?: continue

if (cursorPosition < trigger.length) continue
val closingDelim = text.substring(cursorPosition - trigger.length, cursorPosition)
if (closingDelim != trigger) continue

val closeDelimStart = cursorPosition - trigger.length

val searchText = text.substring(paraStart, closeDelimStart)
val openIdx = searchText.lastIndexOf(trigger)
if (openIdx < 0) continue

val openAbsolute = paraStart + openIdx
val contentStart = openAbsolute + trigger.length
val contentEnd = closeDelimStart
if (contentEnd <= contentStart) continue

s.delete(closeDelimStart, cursorPosition)
s.delete(openAbsolute, openAbsolute + trigger.length)

val adjustedStart = openAbsolute
val adjustedEnd = contentEnd - trigger.length

view.setCustomSelection(adjustedStart, adjustedEnd)
view.inlineStyles?.toggleStyle(resolvedStyle)

view.setCustomSelection(adjustedEnd, adjustedEnd)
return
}
}

fun afterTextChanged(
s: Editable,
endCursorPosition: Int,
Expand All @@ -247,6 +352,8 @@ class ListStyles(
handleAfterTextChanged(s, EnrichedSpans.ORDERED_LIST, endCursorPosition, previousTextLength)
handleAfterTextChanged(s, EnrichedSpans.UNORDERED_LIST, endCursorPosition, previousTextLength)
handleAfterTextChanged(s, EnrichedSpans.CHECKBOX_LIST, endCursorPosition, previousTextLength)
handleConfigurableShortcuts(s, endCursorPosition, previousTextLength)
handleInlineShortcuts(s, endCursorPosition, previousTextLength)
}

fun getStyleRange(): Pair<Int, Int> = view.selection?.getParagraphSelection() ?: Pair(0, 0)
Expand Down
2 changes: 2 additions & 0 deletions ios/EnrichedTextInputView.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ NS_ASSUME_NONNULL_BEGIN
BOOL blockEmitting;
@public
BOOL useHtmlNormalizer;
@public
NSArray<NSDictionary *> *textShortcuts;
}
- (CGSize)measureSize:(CGFloat)maxWidth;
- (void)emitOnLinkDetectedEvent:(NSString *)text
Expand Down
Loading