Skip to content

Commit

Permalink
chore(rich-text): add indentation
Browse files Browse the repository at this point in the history
  • Loading branch information
IslamRustamov committed Oct 1, 2024
1 parent ceec8f4 commit 2ba5791
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 230 deletions.
232 changes: 116 additions & 116 deletions ios/RichTextInput.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,38 @@ import Foundation
// Define all props here
// UPDATE: okay, now this class is also needed for helping functions
class RichTextInput: UITextView, UIEditMenuInteractionDelegate {
@objc var placeholder: String = "Placeholder"

@objc var onChange: RCTBubblingEventBlock? = nil

override func editMenu(for textRange: UITextRange, suggestedActions: [UIMenuElement]) -> UIMenu? {
var option: UIMenu.Options? = nil
@objc var placeholder: String = "Placeholder"

@objc var onChange: RCTBubblingEventBlock? = nil

if #available(iOS 15.0, *) {
option = .singleSelection
} else {
option = .displayInline
override func editMenu(for textRange: UITextRange, suggestedActions: [UIMenuElement]) -> UIMenu? {
var option: UIMenu.Options? = nil

if #available(iOS 15.0, *) {
option = .singleSelection
} else {
option = .displayInline
}

let customMenu = UIMenu(title: "Format", options: option ?? .displayInline, children: [
UIAction(title: "Bold") { _ in
self.toggleFont(trait: .traitBold)
},
UIAction(title: "Italic") { _ in
self.toggleFont(trait: .traitItalic)
},
UIAction(title: "Strikethrough") { _ in
self.toggleStyle(style: NSAttributedString.Key.strikethroughStyle)
},
UIAction(title: "Underline") { _ in
self.toggleStyle(style: NSAttributedString.Key.underlineStyle)
}
])

var actions = suggestedActions
actions.insert(customMenu, at: 0)
return UIMenu(children: actions)
}

let customMenu = UIMenu(title: "Format", options: option ?? .displayInline, children: [
UIAction(title: "Bold") { _ in
self.toggleFont(trait: .traitBold)
},
UIAction(title: "Italic") { _ in
self.toggleFont(trait: .traitItalic)
},
UIAction(title: "Strikethrough") { _ in
self.toggleStyle(style: NSAttributedString.Key.strikethroughStyle)
},
UIAction(title: "Underline") { _ in
self.toggleStyle(style: NSAttributedString.Key.underlineStyle)
}
])

var actions = suggestedActions
actions.insert(customMenu, at: 0)
return UIMenu(children: actions)
}

func focus() {
reactFocus()
Expand All @@ -51,102 +51,102 @@ class RichTextInput: UITextView, UIEditMenuInteractionDelegate {
func blur() {
reactBlur()
}

// TODO: styles are getting lost if you enable/reenable them, bug, needs fixing
func toggleStyle(style: NSAttributedString.Key) {
if selectedRange.length == 0 {
return
}

let attribute = textStorage.attribute(
style,
at: selectedRange.location,
longestEffectiveRange: nil,
in: selectedRange
)

let isStyleEnabled = attribute != nil

if (isStyleEnabled) {
textStorage.removeAttribute(
style,
range: selectedRange
)
} else {
textStorage.addAttribute(style, value: NSUnderlineStyle.single.rawValue, range: selectedRange)
}
}

func toggleFont(trait: UIFontDescriptor.SymbolicTraits.Element) {
if selectedRange.length == 0 {
return
// TODO: styles are getting lost if you enable/reenable them, bug, needs fixing
func toggleStyle(style: NSAttributedString.Key) {
if selectedRange.length == 0 {
return
}

let attribute = textStorage.attribute(
style,
at: selectedRange.location,
longestEffectiveRange: nil,
in: selectedRange
)

let isStyleEnabled = attribute != nil

if (isStyleEnabled) {
textStorage.removeAttribute(
style,
range: selectedRange
)
} else {
textStorage.addAttribute(style, value: NSUnderlineStyle.single.rawValue, range: selectedRange)
}
}

let fontAttribute = textStorage.attribute(
NSAttributedString.Key.font,
at: selectedRange.location,
longestEffectiveRange: nil,
in: selectedRange
)

guard let font = fontAttribute as? UIFont else {
textStorage.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 16, symbolicTraits: trait), range: selectedRange)
return
}
func toggleFont(trait: UIFontDescriptor.SymbolicTraits.Element) {
if selectedRange.length == 0 {
return
}

let traits = font.fontDescriptor.symbolicTraits
let isFontAdded = traits.contains(trait)
let fontAttribute = textStorage.attribute(
NSAttributedString.Key.font,
at: selectedRange.location,
longestEffectiveRange: nil,
in: selectedRange
)

textStorage.enumerateAttribute(.font, in: selectedRange, options: .longestEffectiveRangeNotRequired) { (value, range, stop) in
if let font = value as? UIFont {
textStorage.removeAttribute(.font, range: range)

var traits: UIFontDescriptor.SymbolicTraits = UIFontDescriptor.SymbolicTraits()

traits.insert(font.fontDescriptor.symbolicTraits)

if isFontAdded {
traits.remove(trait)
} else {
traits.insert(trait)
}

textStorage.addAttribute(
.font,
value: UIFont(descriptor: font.fontDescriptor.withSymbolicTraits(traits)!, size: font.pointSize),
range: range
)
guard let font = fontAttribute as? UIFont else {
textStorage.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 16, symbolicTraits: trait), range: selectedRange)
return
}

let traits = font.fontDescriptor.symbolicTraits
let isFontAdded = traits.contains(trait)

textStorage.enumerateAttribute(.font, in: selectedRange, options: .longestEffectiveRangeNotRequired) { (value, range, stop) in
if let font = value as? UIFont {
textStorage.removeAttribute(.font, range: range)

var traits: UIFontDescriptor.SymbolicTraits = UIFontDescriptor.SymbolicTraits()

traits.insert(font.fontDescriptor.symbolicTraits)

if isFontAdded {
traits.remove(trait)
} else {
traits.insert(trait)
}

textStorage.addAttribute(
.font,
value: UIFont(descriptor: font.fontDescriptor.withSymbolicTraits(traits)!, size: font.pointSize),
range: range
)
}
}
}
}

@discardableResult func async<T>(_ block: @escaping () -> T) -> T {
let queue = DispatchQueue.global()
let group = DispatchGroup()
var result: T?
group.enter()
queue.async(group: group) { result = block(); group.leave(); }
group.wait()

return result!
}

// TODO: does it have to be so complicated?
// NOTE: semaphors are needed cause textstorage requires to work on main thread
func getHTML() -> String {
var value: String = ""

let semaphore = DispatchSemaphore(value: 0)

DispatchQueue.main.async {
value = self.attributedText.toHTML() ?? ""
semaphore.signal()
@discardableResult func async<T>(_ block: @escaping () -> T) -> T {
let queue = DispatchQueue.global()
let group = DispatchGroup()
var result: T?
group.enter()
queue.async(group: group) { result = block(); group.leave(); }
group.wait()

return result!
}

semaphore.wait()

return value
}
// TODO: does it have to be so complicated?
// NOTE: semaphors are needed cause textstorage requires to work on main thread
func getHTML() -> String {
var value: String = ""

let semaphore = DispatchSemaphore(value: 0)

DispatchQueue.main.async {
value = self.attributedText.toHTML() ?? ""
semaphore.signal()
}

semaphore.wait()

return value
}
}

extension NSAttributedString {
Expand Down
Loading

0 comments on commit 2ba5791

Please sign in to comment.