Skip to content
Open
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
31 changes: 21 additions & 10 deletions Sources/ExpandableText/ExpandableText+Modifiers.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//
// ExpandableText+Modifiers.swift
//
//
//
// Created by ned on 25/02/23.
//
Expand All @@ -9,7 +9,7 @@ import Foundation
import SwiftUI

public extension ExpandableText {

/**
Sets the font for the text in the `ExpandableText` instance.
- Parameter font: The font to use for the text. Defaults to `body`
Expand All @@ -20,7 +20,7 @@ public extension ExpandableText {
copy.font = font
return copy
}

/**
Sets the foreground color for the text in the `ExpandableText` instance.
- Parameter color: The foreground color to use for the text. Defaults to `primary`
Expand All @@ -31,7 +31,7 @@ public extension ExpandableText {
copy.color = color
return copy
}

/**
Sets the maximum number of lines to use for rendering the text in the `ExpandableText` instance.
- Parameter limit: The maximum number of lines to use for rendering the text. Defaults to `3`
Expand All @@ -42,7 +42,7 @@ public extension ExpandableText {
copy.lineLimit = limit
return copy
}

/**
Sets the text to use for the "show more" button in the `ExpandableText` instance.
- Parameter moreText: The text to use for the "show more" button. Defaults to `more`
Expand All @@ -53,7 +53,18 @@ public extension ExpandableText {
copy.moreButtonText = moreText
return copy
}


/**
Sets the text to use for the "show less" button in the `ExpandableText` instance.
- Parameter lessText: The text to use for the "show less" button. Defaults to `less`
- Returns: A new `ExpandableText` instance with the specified "show less" button text applied.
*/
func lessButtonText(_ lessText: String) -> Self {
var copy = self
copy.lessButtonText = lessText
return copy
}

/**
Sets the font to use for the "show more" button in the `ExpandableText` instance.
- Parameter font: The font to use for the "show more" button. Defaults to the same font as the text
Expand All @@ -64,7 +75,7 @@ public extension ExpandableText {
copy.moreButtonFont = font
return copy
}

/**
Sets the color to use for the "show more" button in the `ExpandableText` instance.
- Parameter color: The color to use for the "show more" button. Defaults to `accentColor`
Expand All @@ -75,7 +86,7 @@ public extension ExpandableText {
copy.moreButtonColor = color
return copy
}

/**
Sets the animation to use when expanding the `ExpandableText` instance.
- Parameter animation: The animation to use for the expansion. Defaults to `default`
Expand All @@ -86,7 +97,7 @@ public extension ExpandableText {
copy.expandAnimation = animation
return copy
}

/**
Enables collapsing behavior by tapping on the text body when the state is expanded.
- Parameter value: Whether or not to enable collapse functionality.
Expand All @@ -97,7 +108,7 @@ public extension ExpandableText {
copy.collapseEnabled = value
return copy
}

/**
Sets whether multiple consecutive newline characters should be trimmed when truncating the text in the `ExpandableText` instance.
- Parameter value: A boolean value indicating whether to trim multiple consecutive newline characters. Defaults to `true`
Expand Down
28 changes: 17 additions & 11 deletions Sources/ExpandableText/ExpandableText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ public struct ExpandableText: View {

@State private var intrinsicSize: CGSize = .zero
@State private var truncatedSize: CGSize = .zero
@State private var moreTextSize: CGSize = .zero
@State private var buttonTextSize: CGSize = .zero

private let text: String
internal var font: Font = .body
internal var color: Color = .primary
internal var lineLimit: Int = 3
internal var moreButtonText: String = "more"
internal var lessButtonText: String = "less" // Added for "Show Less" feature
internal var moreButtonFont: Font?
internal var moreButtonColor: Color = .accentColor
internal var expandAnimation: Animation = .default
internal var collapseEnabled: Bool = false
internal var trimMultipleNewlinesWhenTruncated: Bool = true

/**
Initializes a new `ExpandableText` instance with the specified text string, trimmed of any leading or trailing whitespace and newline characters.
- Parameter text: The initial text string to display in the `ExpandableText` view.
Expand All @@ -53,11 +54,11 @@ public struct ExpandableText: View {
public init(_ text: String) {
self.text = text.trimmingCharacters(in: .whitespacesAndNewlines)
}

public var body: some View {
content
.lineLimit(isExpanded ? nil : lineLimit)
.applyingTruncationMask(size: moreTextSize, enabled: shouldShowMoreButton)
.applyingTruncationMask(size: buttonTextSize, enabled: shouldShowMoreButton)
.readSize { size in
truncatedSize = size
isTruncated = truncatedSize != intrinsicSize
Expand All @@ -73,10 +74,10 @@ public struct ExpandableText: View {
}
)
.background(
Text(moreButtonText)
Text(isExpanded ? lessButtonText : moreButtonText) // Use the appropriate text based on expansion state
.font(moreButtonFont ?? font)
.hidden()
.readSize { moreTextSize = $0 }
.readSize { buttonTextSize = $0 }
)
.contentShape(Rectangle())
.onTapGesture {
Expand All @@ -86,18 +87,18 @@ public struct ExpandableText: View {
}
}
.modifier(OverlayAdapter(alignment: .trailingLastTextBaseline, view: {
if shouldShowMoreButton {
if shouldShowMoreButton || shouldShowLessButton {
Button {
withAnimation(expandAnimation) { isExpanded.toggle() }
} label: {
Text(moreButtonText)
Text(isExpanded ? lessButtonText : moreButtonText) // Toggle button text
.font(moreButtonFont ?? font)
.foregroundColor(moreButtonColor)
}
}
}))
}

private var content: some View {
Text(.init(
trimMultipleNewlinesWhenTruncated
Expand All @@ -112,7 +113,12 @@ public struct ExpandableText: View {
private var shouldShowMoreButton: Bool {
!isExpanded && isTruncated
}



private var shouldShowLessButton: Bool {
isExpanded && collapseEnabled
}

private var textTrimmingDoubleNewlines: String {
text.replacingOccurrences(of: #"\n\s*\n"#, with: "\n", options: .regularExpression)
}
Expand Down